[PYTHON] Load a photo and make a handwritten sketch. With zoom function. Tried to make it.

Introduction

You can find several tools for drawing handwritten sketches on your photos. However, I couldn't find a tool with a zoom function. Standard photos and markup were difficult to use due to the limited magnification. So I made it this time. I also created ui with a script, so it works with one file.

For those who can write the code bang bang, I am writing annotations that may make me angry. It's a memo for myself, but for those who are starting to study Python, the operation of the script is easy to follow. I'm leaving it. Also, as a result of trial and error, some unused functions are sleeping.

I started using the class and wrote it.

environment

ipad + pythonista3

Requirements

・ You can read photos and write handwritten sketches. ・ Several types of line colors and thicknesses are available. -Implemented the undo function. -Implementation of zoomin zoomout function. zoom starts from the upper left. -Implemented scrollview according to the implementation of the enlargement function.

Difficulties

-The implementation method of scrollview and the cooperation of scrolling and scaling. -The touch event and sxrollview conflict with each other in receiving the touch event. -Implementation of undo (stores handwritten lines in an array, erases the last line, and then redraws all lines)

code

epaint.py


#! python3
#You can load images and sketch with enlargement function
# 
# 
#20201228 ver000 Easypaint creation started.
#20201229 ver001 scroll view is implemented by viewing a large image and displaying it.
#20201231 ver002 botton menu added. Added display such as coordinates.
#20210101 ver003 path is created in another class. The touch event conflicts with scrollview in path. Receive only the front.
# 20210101 ver004 btn_lock etc. Switch between scv and pv touch enable to avoid touch conflict+Coordinate correction of pv with all frames.
#20210101 ver005 path The color and width are reflected in the drawing. The drawing position of path remains flying to the upper left. load was implemented several versions ago.
#20210102 ver006 path Fixed so that the drawing does not jump to the upper left even if it scrolls. I added the process of pouring offset into pv.
#20210102 ver007 save created.
#20210103 ver008 zoom created. The center position at zoom is slightly above the upper left. When drawing near the upper left, an error of painting the entire surface appears.
#20210105 ver009 Display image size, magnification, file name argument or epaint in the title. Fixed path drawing strange.
#20210105 ver010 save Fixed that the image is doubled by the magnification. Show save completion.
#20210106 ver011b b version. undo implementation. However, drawing is slow with the photo 3200x2400 size.
#20210107 ver012c c version. Fixed bugs such as speed improvement and undo thickness that are initialized. Code notes and old code cleanup.
#20210110 ver013c c version. Fixed a bug that the drawing position shifts in zoom after scrolling. Button position correction.
#Remaining
# 
#Abandon the acquisition of the read photo file name. Only intermediate file names can be obtained. I want to save with the original file name + alpha.
#Abandon embedding the QR code and passing the original file name. The QR code can only be decoded via the camera.
#Passing the original file name by embedding steganography in the image is not good because of the operation speed. Do you work in separate threads?
# 
# 

import ui, os, sys, photos, scene
import Image, io
import datetime


def pil2ui(imgIn): # pil(jpg) => ui(PNG)pil and ios(ui)The image data used by is different, so conversion is required. This time I'm converting from pil to ui. imgIn=pil
	with io.BytesIO() as bIO: #Convert pil image data to image data that can be used with ios ui. import io required
		imgIn.save(bIO, 'PNG')
		imgOut = ui.Image.from_data(bIO.getvalue())
	del bIO
	return imgOut

########################################
#Hand-painted on the screen. Since it conflicts with SCROLLVIEW, it needs to be in a different class. Only the front moves.
class PathView (ui.View):
    def __init__(self):
        #self.frame = frame
        self.flex = 'WH'
        self.frame=(0,40,1000,680)
        self.color = 'red'
        self.path_width = 3
        self.path_color = 'red'
        
        self.action = None
        self.touch_enabled = True
        self.path = None
        self.paths = []
        self.bpath = None
        self.bpaths= []
        
        self.scvoffset_x = 0
        self.scvoffset_y = 0
        self.scvrate = 1.0
        self.image = None
        self.base_image = None
        self.image_w = 256
        self.image_h = 256
        
        
    def touch_began(self, touch):
        x, y = touch.location
        x2 = (self.scvoffset_x + x)/self.scvrate
        y2 = (self.scvoffset_y + y)/self.scvrate
        
        print('touch_began x  '+str(x)+' y  '+str(y))
        print('           x2:'+str(x2)+' y2:'+str(y2)+' rate'+str(self.scvrate))
        print('scv offset x'+str(self.scvoffset_x)+' y'+str(self.scvoffset_y))
        
        self.path = ui.Path()#For screen drawing
        self.path.line_width = self.path_width#This sentence only sets the initial value of the width. Fixed value is OK.
        self.path.line_join_style = ui.LINE_JOIN_ROUND
        self.path.line_cap_style = ui.LINE_CAP_ROUND
        self.path.line_width = 3#
        self.path.move_to(x, y)
        
        self.bpath=ui.Path()#For drawing on images
        self.bpath.line_width = self.path_width#This sentence only sets the initial value of the width. Fixed value is OK.
        self.bpath.line_join_style = ui.LINE_JOIN_ROUND
        self.bpath.line_cap_style = ui.LINE_CAP_ROUND
        self.bpath.line_width = 0#The width is set to 0 so as not to draw on the screen.
        self.bpath.move_to(x2, y2)
        
    
    def touch_moved(self, touch):
        x, y = touch.location
        x2 = (self.scvoffset_x + x)/self.scvrate
        y2 = (self.scvoffset_y + y)/self.scvrate
        
        #print('touch_moved x ;'+str(x)+' y'+str(y))
        #print('touch_moved x2;'+str(x2)+' y'+str(y2))
        
        self.path.line_to(x, y)#If this is not executed, it will not be drawn on the image. However, when executed, it is temporarily drawn on the screen.
        self.bpath.line_to(x2,y2)#Executes both screen drawing and image drawing, and hides the image drawing with a width of 0. Pass the width when drawing.
        self.set_needs_display()
    
    def touch_ended(self, touch):
        print('touch_ended')
        
        #Save the path in bpaths and use it for undo implementation. Since path is only a route, record the line color and line width as well.
        self.bpaths.append((self.bpath, (int(self.image_w), int(self.image_h)), self.path_color,int(self.path_width)))
        #Set action in view and call the drawing function. If you do not register it in acion, the function path of the upper class_I couldn't call action.
        if callable(self.action): #callable checks if the function is executable. Maybe you don't need it?
            self.action(self)#Since it is set to action of pv, path_I'm calling action.
        #Initialize path for each brush.
        self.path = None
        self.bpath = None
        self.set_needs_display()
    
    #With this function, the touch is drawn on the screen.
    def draw(self):
        if self.path:
            self.path.stroke()
            self.bpath.stroke()
    
    #line when realizing undo_I couldn't mess with width on the main program side, so run it on a pv instance
    def pv_bpath_undo(self):
        print('pv_path_undo')
        bpath = None
        if callable(self.action):
            self.action(self)#We are calling the action of pv. path_action
        bpath = None
    
    



########################################
#Main program
class epaint(ui.View):
	def __init__(self,filename1):
		self.name='easy paint'#View name display. Later, the magnification and xy coordinates ui will be displayed here.
		self.btn_w=100#Button width
		self.btn_h=40 #Button height
		self.filename1 = filename1
		
		self.path_color = 'red'
		self.path_width = int(6)
		self.scvoffset_x = int(0)#Origin position on the upper left of the drawing surface with respect to the original image
		self.scvoffset_y = int(0)#Origin position on the upper left of the drawing surface with respect to the original image
		self.scvrate = float(1.0)#Magnification of drawing surface with respect to original image
		self.scvrate0= float(1.0)#For storing the drawing magnification before zooming
		self.image_w,self.image_h=int(0),int(0)#Width and height of the original image
		self.pathimage_x,self.pathimage_y=int(0),int(0)#Path coordinates of the original image
		self.pathscv_x,pathscv_y=int(0),int(0)#Drawing surface path coordinates
		self.paths = []#Store path as an array. (For undo)
		self.path=None
		
		self.base_image = ui.Image.named('test:Peppers')#The original image
		self.image_w,self.image_h = self.base_image.size#Original image width and height pil.size method
				
		w,h = ui.get_screen_size()#Get the screen size. The part excluding x and the class name.
		self.scr_w,self.scr_h = w,h #Full screen width and height
		
		self.biv = ui.ImageView()#base image view View of the original image
		self.biv.frame = (0, 0,self.image_w,self.image_h)#Get the size of the original image. Upper left coordinates and lower right coordinates
		#Upper left absolute coordinates x,Upper left absolute coordinates y,Bottom right x absolute coordinates,Lower right y absolute coordinates
		#ui coordinates: The coordinates increase from the upper left to the lower right.
		#scene coordinates: The coordinates increase from the lower left to the upper right. Same as so-called ordinary xy coordinates.
		#

		self.biv.image = self.base_image
		self.biv.bg_color = 'red'
		self.biv.center = (128,128)#Specify the coordinates to display the center of the view. Since the test image is 256x256, I set it to 128.
		self.biv.transform = ui.Transform.scale(1,1)#Specify the magnification of the image to be displayed on biv. Specified in x and y directions.
		#self.biv.image = ui.Image.from_data(pil2ui(photos.pick_image()))#It doesn't work. Is the image format different?
		self.scv = ui.ScrollView()
		#flame(The window size of the rscroll view that is actually displayed)Declare the width of
		self.scvframesize=(0,self.btn_h+3,self.scr_w,self.scr_h-self.btn_h-80)
		self.scv.frame = self.scvframesize#(0,self.btn_h+3,self.scr_w,self.scr_h-self.btn_h-80)
		self.scv.content_size = (self.image_w,self.image_h)#Declare the size of the frame to put the original image
		#self.scv.flex='WH' #
		self.scv.scroll_enabled = False#False #Scrolling is True enabled=Move / False invalid=Stop. Default True
		self.scv.touch_enabled = False#False Do not receive touch events. Touch and pass to the view below.
		#Receive a True Touch event. Do not touch to the view below.
				
		self.scv.add_subview(self.biv)#By putting biv in scv, it was assigned to the original image contents of scrollview.
		self.add_subview(self.scv)#Declared that it is scv to be displayed by putting scv in self
		
		
		self.btnscv = ui.ScrollView()#Create scrollview for menu button
		self.btnscv.background_color = '#d9dcff'#Light purple
		self.btnscv.frame = (0,0,self.scr_w,self.btn_h)
		self.btnscv.content_size = (1300,self.btn_h)
		self.btnscv.flex = 'W'#Fixed only in the width direction
		self.add_subview(self.btnscv)
		
		#Register the menu button. Repeating the same item is the function config below_I make it with button.
		#config_button(button, name, frame, title)
		self.scv_btn_lock = ui.Button()
		self.config_button(self.scv_btn_lock, 'btn_lock',(5*self.btn_w,0,self.btn_w,self.btn_h), 'Lock')
		self.scv_btn_load = ui.Button()
		self.config_button(self.scv_btn_load, 'btn_load',(0*self.btn_w,0,self.btn_w,self.btn_h), 'Load')
		self.scv_btn_save = ui.Button()
		self.config_button(self.scv_btn_save, 'btn_save',(1*self.btn_w,0,self.btn_w,self.btn_h), 'Save')
		self.scv_btn_undo = ui.Button()
		self.config_button(self.scv_btn_undo, 'btn_undo',(4*self.btn_w,0,self.btn_w,self.btn_h), 'Undo')
		self.scv_btn_color = ui.Button()
		self.config_button(self.scv_btn_color, 'btn_color',(2*self.btn_w,0,self.btn_w,self.btn_h), 'Color')
		self.scv_btn_path_width = ui.Button()
		self.config_button(self.scv_btn_path_width, 'btn_path_width',(3*self.btn_w,0,self.btn_w,self.btn_h), '-')#No title because it is a button to specify the width of the line
		self.scv_btn_zoomin = ui.Button()
		self.config_button(self.scv_btn_zoomin,'btn_zoomin',(6*self.btn_w,0,self.btn_w,self.btn_h),'Zin')
		self.scv_btn_zoomout = ui.Button()
		self.config_button(self.scv_btn_zoomout,'btn_zoomout',(7*self.btn_w,0,self.btn_w,self.btn_h),'Zout')

		self.lock_switch = 'lock'
		self.colors = ['white', 'grey', 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow']
		self.color_nr = 2    #Specify the initial color of the red line
		self.path_widths = [3, 6, 12, 24]
		self.path_w_nr = 1	    #6 Specify what the width of the line is
		self.scv_btn_color.tint_color = self.colors[self.color_nr]

		

		#Needed to pass touch to drawing(Perform drawing on the screen)However, the view receives the touch event only in the foreground.
		#In other words, drawing and scroll view are incompatible. (Possible by replacing the front.It is also possible to switch touch enabled)
		self.pv = PathView()#(frame=self.bounds)
		self.pv.frame = self.scvframesize#(0,self.btn_h,self.scr_w,self.scr_h-self.btn_h)
		self.pv.action = self.path_action
		self.pv.color=self.colors[self.color_nr]
		self.pv.path_width = self.path_widths[self.path_w_nr]
		self.pv.scvoffset_x = self.scvoffset_x
		self.pv.scvoffset_y = self.scvoffset_y
		self.pv.scvrate = self.scvrate
		self.add_subview(self.pv)
		
		self.path_width_change()
		self.image = None
		self.set_btn_actions()#Added action to btn. (Since it can be registered only after reading the function, it was added later)
		#
		self.present('fullscreen')


	###############################
	#btn click no action def
	def btn_lock(self,sender):
		self.logp(sender,'btn_lock')
		#Modify the scrollview element to lock / unlock the scroll
		#self.scv.scroll_enabld = True#False #Scrolling is True enabled=Move / False invalid=Stop. Default True
		if self.lock_switch == 'lock':
			print('btn_lock  to scroll')
			self.lock_switch = 'scroll'
			self.scv.scroll_enabled = True
			self.scv_btn_lock.title = 'scroll'
			#self.pv.send_to_back()#Move the view to the back. (If the front view is opaque, it will not be visible)
			self.scv.touch_enabled = True#False Do not receive touch events. Touch and pass to the view below.
			self.pv.touch_enabled = False#False Do not receive touch events. Touch and pass to the view below.
		else:
			print('btn_lock  to lock')
			self.lock_switch = 'lock'
			self.scv.scroll_enabled = False
			self.scv_btn_lock.title = 'lock'
			#self.scv.send_to_back()#Send view to the back. Doing this hides the screen under the top view.
			self.scv.touch_enabled = False#False Do not receive touch events. Touch and pass to the view below.
			self.pv.touch_enabled = True#False Do not receive touch events. Touch and pass to the view below.

			self.scvoffset_x,self.scvoffset_y = self.scv.content_offset
			self.pv.scvoffset_x = self.scvoffset_x#Pour the current scv offset into the pv.
			self.pv.scvoffset_y = self.scvoffset_y
			
	
	def btn_load(self,sender):
		print('btn_load')
		self.scvrate = 1
		self.scvrate0 =1

		self.base_image = ui.Image.from_data(photos.pick_image(raw_data=True))
		self.image_w,self.image_h = self.base_image.size#Original image width and height pil.size method
		
		self.pv.image_w , self.pv.image_h = self.image_w , self.image_h
		
		self.biv.frame = (0, 0,self.image_w,self.image_h)#Resize biv to original image size
		self.scv.content_size = (self.image_w,self.image_h)#Declare the size of the frame to put the original image
		w,h = ui.get_screen_size()#Get the screen size. The part excluding x and the class name.
		self.scr_w,self.scr_h = w,h #Full screen width and height
		
		self.scvrate0 = self.scvrate #*2
				
		self.biv.image = self.base_image#Substitute the original image for biv.
		
		self.zoom_set(sender)

		#Display image size and magnification in title
		self.name ='Size:' + str(int(self.image_w)) + ', ' + str(int(self.image_h))+' rate:'+str(self.scvrate)+' '+self.filename1

		self.set_needs_display()
					
	def btn_save(self,sender):
		print('btn_save')
		saveimage0 = self.ui2pil(self.biv.image)
		
		nitiji_now = datetime.datetime.now() #Get the current date and time
		file_nitiji = nitiji_now.strftime("%Y%m%d_%H%M%S" )#Pillow cannot use double-byte characters in the file name.
		#Extract the date and time from the datetime function and assign it to the variable of the character to be displayed. If you suddenly enter the file name, processing may fail.
		filename = file_nitiji+'.jpg'
		print(str(self.image_w)+' , '+str(self.image_h))
		#pil risize int required. ANTIALIAS is slow with a focus on performance.
		saveimage = saveimage0.resize((int(self.image_w),int(self.image_h)),Image.ANTIALIAS)#for PIL
		#Regardless of zoom, each xy is doubled, so it is reduced to the original size.
		saveimage.save(filename, quality=95, optimize=True, progressive=True)#for PIL
		#You need to save the image in the py folder before saving it to the camera roll.
		filename2 = 'MemoCamera'+str(self.filename1)+str(file_nitiji)+'Draw.jpg'
		#filename1=Arguments added to the constructor when calling the nyuuryoubunn class
		os.rename(filename,filename2)#Create full-width file name instead of pillow
		#print('Draw_filename2:',filename2)
		photos.create_image_asset(filename2) #Save to camera roll.
		#The file name is the path to the previously saved image file. Not a saved name.
		
		#file deleate
		os.remove(filename2) 
		#If you do not erase the JPEG generated in the py folder, the time stamp of the first file will be
		#Delete the jpg in the py folder every time because it will continue to be inherited by the exif data of the photo.
			#Display image size and magnification in title
		self.name ='save success'		
		
		#self.close() #Enable when you want to close the script after saving.
				

	def btn_undo(self, sender):
		print('btn_undo')
		self.path_undo(sender)
		
		self.set_needs_display()

	def btn_color(self, sender):
		if self.color_nr < len(self.colors) - 1:
			self.color_nr += 1
		else:
			self.color_nr = 0
		self.scv_btn_color.tint_color = self.colors[self.color_nr]
		self.path_color = self.colors[self.color_nr]
		self.pv.path_color = self.path_color
		self.path_width_change()

	def btn_path_width(self, sender):
		if self.path_w_nr < len(self.path_widths) - 1:
			self.path_w_nr += 1
		else:
			self.path_w_nr = 0
		self.path_width = self.path_widths[self.path_w_nr]
		self.pv.path_width = self.path_width
		self.path_width_change()

	def btn_zoomin(self,sender):
		print('btn_zoomin')
		self.scvrate0= self.scvrate
		self.scvrate = self.scvrate * 2
		self.zoom_set(sender)
		self.logp(sender,'zoomin')
		
				
	def btn_zoomout(self,sender):
		print('btn_zoomout')
		self.scvrate0= self.scvrate
		self.scvrate = self.scvrate * 0.5
		self.zoom_set(sender)
		self.logp(sender,'zoomout')
		

###############################						
# sub tool

	def pil2ui(imgIn): # pil(jpg) => ui(PNG)pil and ios(ui)The image data used by is different, so conversion is required. This time I'm converting from pil to ui. imgIn=pil
		with io.BytesIO() as bIO: #Convert pil image data to image data that can be used with ios ui. import io required
			imgIn.save(bIO, 'PNG')
			imgOut = ui.Image.from_data(bIO.getvalue())
		del bIO
		return imgOut
	
	#from pythonista forum
	def ui2pil(self, image):
		mem = io.BytesIO(image.to_png())
		out = Image.open(mem)
		out.load()
		mem.close()
		return out
	
	
	#A function that sets buttons together. Since the same attribute is repeatedly registered, it is made into a function.
	def config_button(self,button,name,frame,title):
		button.name = name
		button.frame = frame
		button.title = title
		button.border_width = 1
		button.corner_radius = 2
		button.border_color = 'blue'
		button.font = ('<system-bold>',25)
		#button.action = name#The function when the button is pressed is the same as the button name.
		#However, it cannot be added here because the function to be called must be loaded first. Added later with another function.
		self.btnscv.add_subview(button)#scroll view of menu button=Assign the button to btnscv as the original view.

	#The button action cannot be declared without registering the action function, so register it last.
	def set_btn_actions(self):
		for subview in self.btnscv.subviews:#Specify the view that contains the button
			if isinstance(subview, ui.Button):
				subview.action = getattr(self, subview.name)

	#Display the processed photo in imageview.
	def imgv_pick():
		imgIn = photos.pick_image()
		imggg = pil2ui(imgIn) #The image format is converted from pil to ui below.
		#sender.superview['photo1'].image = imggg #imegeview photo_now to ios(ui)Pass the format image and reflect it.
		return imggg
		#It fits the image to the window size.
		
##############################
# draw tool
	#path_Change the line width image of the width button
	def path_width_change(self):
		with ui.ImageContext(self.btn_w, self.btn_h) as ctx:
			ui.set_color(self.colors[self.color_nr])
			path = ui.Path()
			path.line_width = self.path_widths[self.path_w_nr]
			path.line_join_style = ui.LINE_JOIN_ROUND
			path.line_cap_style = ui.LINE_CAP_ROUND
			path.move_to(20,20)
			path.line_to(80,20)
			path.stroke()
			image = ctx.get_image()

			#background_image is the ui method that puts the background image of the button
			self.scv_btn_path_width.background_image = image
			#An image that reflects the line color and line width is put in the line width button as a background image.


		
	#There is no particular meaning.
	def layout(self):
		pass
		
	#Drawing to biv with bpath converted to biv
	def path_action(self, sender):
		#path = sender.path
		bpath= sender.bpath#Required when accessing attributes outside init within an instance such as pv. The function also needs a sender.
		#In this case, "attributes outside init in the instance"=self.pv.bpath.line_width .However, an error will occur if it is not registered in the action of pv.
		
		old_img = self.biv.image
		width, height = self.image_w,self.image_h		
		#If you get the size of biv, you cannot use it because the upper left part of the image is cut off when the image is reduced.
		self.logp(sender,'path_action')
		
		#The path is drawn as an image. w h is the drawing range, so base_The size of imge. Not the biv size to be zoomed.
		with ui.ImageContext(width, height) as ctx:
			if old_img:
				old_img.draw()
			self.pv.bpath.line_width = self.path_width#Reflect the width of the line
			ui.set_color(self.path_color)#Reflect the drawing color of path
			bpath.stroke()
			self.biv.image = ctx.get_image()

		
	def path_undo(self,sender):
		#bpath= sender.bpath
		last_path_color = self.path_color
		last_path_width = self.path_width
		
		#bpaths Counting the number of lists. To redraw all bpaths again with undo.
		path_count = len(self.pv.bpaths)
		#print(self.pv.bpaths)
		
		width, height = self.image_w,self.image_h
		#print('w h '+str(width)+' , '+str(height))
		
		if path_count > 0:
			self.pv.bpaths.pop()#Delete the last element
			path_count -= 1
			self.biv.image = self.base_image #Return the biv image to no bpath.
			for i in range(0, path_count):#Redraw the bpath from the beginning to the previous bpath.
					self.path_width = self.pv.bpaths[i][3]#self.path_width#Reflect the width of the line
					self.path_color = self.pv.bpaths[i][2]#
					self.pv.bpath = self.pv.bpaths[i][0]
					self.pv.pv_bpath_undo()#Bpt is generated in pv to reflect the line width

			self.path_color = last_path_color
			self.path_width = last_path_width
			
			self.set_needs_display()		
		

	def zoom_set(self,sender):
		scvw,scvh = self.scr_w,self.scr_h-self.btn_h-80#Get the size of scv
		self.scvoffset_x,self.scvoffset_y = self.scv.content_offset#The position of the upper left origin of scv in biv
		#Move the scv offset closer to the position when it was scaled up or down
		newx=self.scvoffset_x * self.scvrate / self.scvrate0
		newy=self.scvoffset_y * self.scvrate / self.scvrate0		
		
		self.biv.frame = (0,0,self.image_w*self.scvrate,self.image_h*self.scvrate)
		self.scv.content_size = (self.image_w*self.scvrate,self.image_h*self.scvrate)#Frame size to put the original image

		self.scvoffset_x,self.scvoffset_y = self.scv.content_offset#The position of the upper left origin of scv in biv
		self.pv.scvoffset_x = self.scvoffset_x#Pour the current scv offset into the pv.
		self.pv.scvoffset_y = self.scvoffset_y
		self.pv.scvrate = self.scvrate
		self.scv.content_size = (self.image_w*self.scvrate,self.image_h*self.scvrate)#Frame size to put the original image
		
		self.scv.content_offset=(newx,newy)#Move the scv offset to a position closer to the original position. Upper left reference.
		self.scvoffset_x,self.scvoffset_y = self.scv.content_offset
		self.pv.scvoffset_x = self.scvoffset_x#Pour the current scv offset into the pv.
		self.pv.scvoffset_y = self.scvoffset_y		
		
		self.logp(sender,'zoom_set')
		#Display image size and magnification in title
		self.name ='Size:' + str(int(self.image_w)) + ', ' + str(int(self.image_h))+' rate:'+str(self.scvrate)+' '+self.filename1

	#log print
	def logp(self,sender,memo):
		print(str(memo)+' biv.w'+str(self.biv.width)+' h'+str(self.biv.height)+' : offset'+str(self.scv.content_offset)+' rate'+str(self.scvrate)+' rate0:'+str(self.scvrate0))

						
	###############################
#v = epaint()
#v.present('fullscreen')

if __name__ == "__main__":
	epaint('epaint')#I want to take filename1 as an argument.


Recommended Posts

Load a photo and make a handwritten sketch. With zoom function. Tried to make it.
Associate Python Enum with a function and make it Callable
I tried to make a periodical process with Selenium and Python
I tried to make a calculator with Tkinter so I will write it
I tried to make a periodical process with CentOS7, Selenium, Python and Chrome
When I tried to make a VPC with AWS CDK but couldn't make it
I tried to make a simple image recognition API with Fast API and Tensorflow
Make a function to describe Japanese fonts with OpenCV
I tried to make GUI tic-tac-toe with Python and Tkinter
I made a server with Python socket and ssl and tried to access it from a browser
I also tried to imitate the function monad and State monad with a generator in Python
How to make a recursive function
[5th] I tried to make a certain authenticator-like tool with python
Rubyist tried to make a simple API with Python + bottle + MySQL
[2nd] I tried to make a certain authenticator-like tool with python
Make it possible to output a log to a file with go echo
A memorandum when I tried to get it automatically with selenium
[3rd] I tried to make a certain authenticator-like tool with python
How to make a surveillance camera (Security Camera) with Opencv and Python
Make a thermometer with Raspberry Pi and make it viewable with a browser Part 4
I tried to create Bulls and Cows with a shell program
I tried to make a todo application using bottle with python
[4th] I tried to make a certain authenticator-like tool with python
[1st] I tried to make a certain authenticator-like tool with python
I tried to make a strange quote for Jojo with LSTM
I tried to make an image similarity function with Python + OpenCV
I tried to make a mechanism of exclusive control with Go
2. Make a decision tree from 0 with Python and understand it (2. Python program basics)
Python: I tried to make a flat / flat_map just right with a generator
Gorilla judgment machine, gorilla! !! Tried to make it!
Beginners want to make something like a Rubik's cube with UE4 and make it a library for reinforcement learning # 4
Fractal to make and play with Python
Is it possible to enter a venture before listing and make a lot of money with stock options?
I came up with a way to make a 3D model from a photo.
Set up a Lambda function and let it work with S3 events!
I tried to make "Sakurai-san" a LINE BOT with API Gateway + Lambda
I tried to make a traffic light-like with Raspberry Pi 4 (Python edition)
How to make a container name a subdomain and make it accessible in Docker
I tried to make a Web API
Make a decision tree from 0 with Python and understand it (4. Data structure)
[Zaif] I tried to make it easy to trade virtual currencies with Python
I tried to make a url shortening service serverless with AWS CDK
Beginners want to make something like a Rubik's cube with UE4 and make it a library for reinforcement learning # 5
Beginners want to make something like a Rubik's cube with UE4 and make it a library for reinforcement learning # 6
Make a thermometer with Raspberry Pi and make it visible on the browser Part 3
I tried to make a simple mail sending application with tkinter of Python
[Patent analysis] I tried to make a patent map with Python without spending money
When I tried to create a virtual environment with Python, it didn't work
I tried to make a castle search API with Elasticsearch + Sudachi + Go + echo
[ES Lab] I tried to develop a WEB application with Python and Flask ②
I want to write an element to a file with numpy and check it.
Machine learning beginners tried to make a horse racing prediction model with python
[Python] Smasher tried to make the video loading process a function using a generator
I tried to make a dictionary function that does not distinguish between cases
I tried my best to make an optimization function, but it didn't work.
I set up TensowFlow and was addicted to it, so make a note
A memorandum to make WebDAV only with nginx
How to make a dictionary with a hierarchical structure.
Make a chatbot and practice to be popular.
Try to make a "cryptanalysis" cipher with Python
I tried function synthesis and curry with python