Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #======================================================
- # Cross Stitch Pattern Generator
- # cspg.py
- # Written by G.D. Walters
- # Created for Full Circle Magazine issues 85, 86, 87 & 88
- #======================================================
- from Tkinter import *
- import tkFileDialog
- import tkCommonDialog
- import tkMessageBox
- import ttk
- from PIL import Image,ImageTk,ImageOps
- import Pmw
- import apsw # Database Access
- import math # Math library
- import sys
- class Test:
- def __init__(self, master):
- self.picFormats = [
- ('JPEG / JFIF','*.jpg'),
- ('Portable Network Graphics','*.png'),
- ('CompuServer GIF','*.gif'),
- ('Windows Bitmap','*.bmp'),
- ('All File Types *.*','*.*'),
- ]
- self.openimage = PhotoImage(file='open.gif')
- self.DefaultImage =ImageTk.PhotoImage(self.Thumbnail("default.jpg",450,450))
- #-------------------------------------------
- # Global Definitions
- #-------------------------------------------
- # UI Required
- global OriginalFilename
- OriginalFilename = StringVar()
- global OriginalColorCount
- OriginalColorCount = StringVar()
- global OriginalSize
- OriginalSize = StringVar()
- global OriginalImage
- OriginalImage = StringVar()
- global ComboStitch
- ComboStitch = IntVar()
- global ComboSize
- ComboSize = StringVar()
- global FabricWidth
- FabricWidth = DoubleVar()
- global FabricHeight
- FabricHeight = DoubleVar()
- global MaxColors
- MaxColors = IntVar()
- global BorderSize
- BorderSize = DoubleVar()
- global ProcessedColors
- ProcessedColors = StringVar()
- global ProcessedSize
- ProcessedSize = StringVar()
- global DmcColor
- DmcColor = StringVar()
- #-------------------------------------------
- global ShowGrid
- ShowGrid = True
- global ProcessedImage
- ProcessedImage = ""
- global GridImage
- GridImage = ""
- global backgroundColor1
- backgroundColor1 = (120,)*3
- global backgroundColor2
- backgroundColor2 = (0,)*3
- global ReadyToProcess
- ReadyToProcess = False
- #-------------------------
- self.OpenDB()
- self.MakeMenu(master)
- frm = self.BuildWidgets(master)
- self.PlaceWidgets(frm)
- #======================================================
- # BEGIN UI DEFINITION
- #======================================================
- def MakeMenu(self,master):
- menu = Menu(master)
- root.config(menu=menu)
- filemenu = Menu(menu, tearoff=0)
- process = Menu(menu,tearoff=0)
- help = Menu(menu,tearoff=0)
- #-------------------------------------------
- # File Menu
- #-------------------------------------------
- menu.add_cascade(label="File", menu=filemenu)
- menu.add_cascade(label="Process",menu=process)
- menu.add_cascade(label="Help",menu=help)
- filemenu.add_command(label="New")
- filemenu.add_command(label="Open", command=self.GetFileName)
- filemenu.add_command(label="Save", command=self.FileSave)
- filemenu.add_separator()
- filemenu.add_command(label="Exit", command=self.DoExit)
- #-------------------------------------------
- # Process Menu
- #-------------------------------------------
- process.add_command(label="All",command=self.Process1)
- #-------------------------------------------
- # Help Menu
- #-------------------------------------------
- help.add_command(label="Help",command=self.ShowHelp)
- help.add_separator()
- help.add_command(label="About",command=self.ShowAbout)
- def BuildWidgets(self,master):
- self.frame = Frame(master,width=1024,height=850)
- # ---------------- TOP FRAME ---------------------
- self.frm1 = Frame(self.frame,width=1024,height=100,bd=4,relief=GROOVE)
- self.label1 = Label(self.frm1,text = "Original Filename: ")
- self.entFileName = Entry(self.frm1,width=50,textvariable=OriginalFilename)
- self.btnGetFN = Button(self.frm1,width=28,image=self.openimage,command=self.GetFileName)
- self.label2 = Label(self.frm1,text = "Original Colors: ")
- self.lblOriginalColorCount = Label(self.frm1,text="",width=10,textvariable=OriginalColorCount)
- self.label3 = Label(self.frm1,text = "Original Size: ")
- self.lblOriginalSize = Label(self.frm1,text="",width=10,textvariable=OriginalSize)
- # ---------------Middle Frame --------------------
- self.frm2 = Frame(self.frame,width=1024,height=160,bd=4,relief=GROOVE)
- self.lbl4 = Label(self.frm2,text="Aida Stitch Size: ")
- self.lbl5 = Label(self.frm2,text="Aida Fabric Size: ")
- self.TCombobox1 = ttk.Combobox(self.frm2,textvariable=ComboStitch,width=8)
- self.TCombobox1.bind('<<ComboboxSelected>>', self.StitchSizeSelect)
- self.TCombobox1['values'] = (7,10,11,12,14,16,18,22)
- self.TCombobox2 = ttk.Combobox(self.frm2,textvariable=ComboSize,width = 8)
- self.TCombobox2.bind('<<ComboboxSelected>>',self.AidaSizeSelect)
- self.TCombobox2['values'] = ("12x18","15x18","30")
- self.lbl6 = Label(self.frm2,text="Max Colors: ")
- self.entMaxColors = Entry(self.frm2,textvariable=MaxColors,width=3)
- self.lbl7 = Label(self.frm2,text="Border Size: ")
- self.entBorderSize = Entry(self.frm2,textvariable=BorderSize,width = 8)
- self.frmLine = Frame(self.frm2,width=6,height=80,bd=3,relief="raised")
- self.lbl8 = Label(self.frm2,text=" Processed Image Colors: ")
- self.lbl9 = Label(self.frm2,text="Processed Image Stitch Count: ")
- self.lblProcessedColors=Label(self.frm2,width=10,textvariable=ProcessedColors,justify=LEFT)
- self.lblProcessedSize=Label(self.frm2,width=10,textvariable=ProcessedSize,justify=LEFT)
- self.btnDoIt = Button(self.frm2,text="Process",width=11,command = self.Process1)
- self.btnShowGrid = Button(self.frm2,text="Hide Grid",width=11,command=self.ShowHideGrid)
- ComboStitch.set(14)
- ComboSize.set("15x18")
- FabricWidth.set(15)
- FabricHeight.set(18)
- MaxColors.set(50)
- BorderSize.set(1.0)
- # --------------- Bottom Frame ------------------
- self.frm3 = Frame(self.frame,width=1024, height = 768,bd=4,relief=GROOVE)
- self.lblImageL = Label(self.frm3,image=self.DefaultImage,height=500,width=500,borderwidth=2,relief=GROOVE,textvariable=OriginalImage)
- self.lblImageR = Label(self.frm3,image=self.DefaultImage,height=500,width=500,borderwidth=2,relief=GROOVE)
- #---------------- Side Frame -------------------
- self.frm4 = Frame(self.frame,width = 300,height=610,bd=4,relief=GROOVE)
- self.lbl20 = Label(self.frm4,text="Processed Color List",width = 50)
- # Create the ScrolledFrame.
- self.sf = Pmw.ScrolledFrame(self.frm4,
- labelpos = 'n', label_text = 'Processed Color List',
- usehullsize = 1,
- hull_width = 300,
- hull_height = 590,
- )
- return self.frame
- def PlaceWidgets(self,frame):
- frame.grid(column = 0, row = 0)
- # ---------------- TOP FRAME ---------------------
- self.frm1.grid(column=0,row=0,rowspan=2,sticky="new")
- self.label1.grid(column=0,row=0,sticky='w')
- self.entFileName.grid(column=1,row=0,sticky='w',columnspan = 5)
- self.btnGetFN.grid(column=7,row = 0,sticky='w')
- self.label2.grid(column=9,row=0,sticky='w',padx=10)
- self.lblOriginalColorCount.grid(column=10,row=0,sticky='w')
- self.label3.grid(column=9,row=1,sticky='w',padx=10,pady=5)
- self.lblOriginalSize.grid(column=10,row=1,sticky='w')
- # ---------------- MIDDLE FRAME ---------------------
- self.frm2.grid(column=0,row=2,rowspan=2,sticky="new")
- self.lbl4.grid(column=0,row=0,sticky="new",pady=5)
- self.lbl5.grid(column=0,row=1,sticky="new")
- self.TCombobox1.grid(column=1,row=0,sticky="new",pady=5)
- self.TCombobox2.grid(column=1,row=1,sticky="new")
- self.lbl6.grid(column=2,row = 0,sticky="new",padx=5,pady=5)
- self.entMaxColors.grid(column=3,row=0,sticky="new",pady=5)
- self.lbl7.grid(column=2,row=1,sticky='new',padx=5)
- self.entBorderSize.grid(column=3,row=1,sticky='new')
- self.frmLine.grid(column=4,row=0,rowspan=2,sticky='new',padx=15)
- self.lbl8.grid(column=5,row=0,sticky='new',pady=5)
- self.lbl9.grid(column=5,row=1,sticky='new',pady=5)
- self.lblProcessedColors.grid(column=6,row=0,sticky='w',pady=5)
- self.lblProcessedSize.grid(column=6,row=1,sticky='w',pady=5)
- self.btnDoIt.grid(column=7,row=0,sticky='e',padx=5,pady = 5)
- self.btnShowGrid.grid(column=7,row=1,sticky='e',padx=5,pady = 5)
- # ---------------- BOTTOM FRAME ---------------------
- self.frm3.grid(column=0,row=4,sticky="nsew")
- self.lblImageL.grid(column=0,row=0,sticky="w")
- self.lblImageR.grid(column=1,row=0,sticky="e")
- # ---------------- SIDE FRAME ---------------------
- self.frm4.grid(column=2,row=0,rowspan=12,sticky="new")
- #self.lbl20.grid(column=0,row=0,columnspan=2,sticky='ewn')
- self.sf.grid(column=0,row=1)
- self.sfFrame = self.sf.interior()
- self.lblch1 = Label(self.sfFrame,text=" Original")
- self.lblch2 = Label(self.sfFrame,text=" DMC")
- self.lblch3 = Label(self.sfFrame,text="Name/Number")
- self.lblch1.grid(column=0,row=0,sticky='w')
- self.lblch2.grid(column=1,row=0,sticky='w')
- self.lblch3.grid(column=2,row=0,sticky="w")
- #======================================================
- # END UI DEFINITION
- #======================================================
- def GetFileName(self):
- global ReadyToProcess
- #---------------------------------
- fileName = tkFileDialog.askopenfilename(parent=root,filetypes=self.picFormats ,title="Select File to open...")
- print fileName
- OriginalFilename.set(fileName)
- OriginalColorCount.set(self.GetColorCount(fileName))
- OriginalSize.set(self.GetHW(fileName))
- masterimage=Image.open(fileName)
- masterimage.thumbnail((500,500))
- self.img = ImageTk.PhotoImage(masterimage)
- self.lblImageL['image'] = self.img
- ReadyToProcess = True
- def Thumbnail(self,file,hsize,wsize):
- size = hsize,wsize
- extpos = file.rfind(".")
- outfile = file[:extpos] + ".thumbnail"
- im = Image.open(file)
- im.thumbnail(size)
- im.save(outfile,"JPEG")
- return im
- def OriginalInfo(self,file):
- im = Image.open(file)
- imFormat = im.format
- imSize = im.size
- imMode = im.mode
- self.size = imSize
- self.imformat = imFormat
- self.immode = imMode
- def GetColorCount(self,file):
- im = Image.open(file)
- numColors = im.getcolors(1600000)
- self.colors = len(numColors)
- print self.colors
- return self.colors
- def GetHW(self,file):
- im = Image.open(file)
- tmp = "{0}x{1}".format(im.size[0],im.size[1])
- print tmp
- return tmp
- def GetHW2(self,file):
- im = Image.open(file)
- return im.size[0],im.size[1]
- def GetColors(self,image):
- numColors = image.getcolors(1600000)
- colors = len(numColors)
- print colors
- def Process1(self):
- #---------------------------------
- # Reduce Colours
- # Resize image
- # Place image into right label
- global ReadyToProcess
- #---------------------------------
- if ReadyToProcess == False:
- tkMessageBox.showinfo(title="ERROR...",message='You must load an original imaage first.')
- else:
- newimage = self.Pixelate(OriginalFilename.get(),5)
- Reduced = self.ReduceColours(newimage)
- W,H = self.GetHW2(Reduced)
- siz = "{0}x{1}".format(W/5,H/5)
- ProcessedSize.set(siz)
- # Place image
- self.im2=Image.open(Reduced)
- self.im2.thumbnail((500,500))
- self.img3 = ImageTk.PhotoImage(self.im2)
- self.lblImageR['image'] = self.img3
- self.ProcessedImage = 'im1.png'
- self.MakeLines(Reduced,5)
- self.MakeLines2('output.png',50)
- self.im2 = Image.open('output2.png')
- self.im2.thumbnail((500,500))
- self.img3 = ImageTk.PhotoImage(self.im2)
- self.lblImageR['image'] = self.img3
- self.FillScrolledList('output.png')
- self.GridImage = 'output2.png'
- def Pixelate(self,im,pixelSize):
- image = Image.open(im)
- self.GetColors(image)
- image = image.resize((image.size[0]/pixelSize, image.size[1]/pixelSize),Image.NEAREST)
- image = image.resize((image.size[0]*pixelSize, image.size[1]*pixelSize),Image.NEAREST)
- self.GetColors(image)
- #image.show()
- image.save('newimage.png')
- return 'newimage.png'
- def ReduceColours(self,ImageName):
- #Reduce colors
- numcolors=MaxColors.get()
- print("Numcolors={0}".format(numcolors))
- image = Image.open(ImageName)
- output = image.convert('P', palette=Image.ADAPTIVE, colors=numcolors)
- x = output.convert("RGB")
- self.GetColors(x)
- numcolors = x.getcolors()
- ProcessedColors.set(len(numcolors))
- for i in numcolors:
- print i
- x.save('im1.png')
- return 'im1.png'
- def MakeLines(self,im,pixelSize):
- global backgroundColor1
- #---------------------------------
- image = Image.open(im)
- pixel = image.load()
- for i in range(0,image.size[0],pixelSize):
- for j in range(0,image.size[1],pixelSize):
- for r in range(pixelSize):
- pixel[i+r,j] = backgroundColor1
- pixel[i,j+r] = backgroundColor1
- image.save('output.png')
- def MakeLines2(self,im,pixelSize):
- global backgroundColor2
- #---------------------------------
- image = Image.open(im)
- pixel = image.load()
- for i in range(0,image.size[0],pixelSize):
- for j in range(0,image.size[1],pixelSize):
- for r in range(pixelSize):
- try:
- pixel[i+r,j] = backgroundColor2
- pixel[i,j+r] = backgroundColor2
- except:
- pass
- image.save('output2.png')
- def ResizeImage(self,im):
- #im.show()
- tempsize = im.size
- print tempsize
- BS = BorderSize.get()
- FW = FabricWidth.get()-BS
- FH = FabricHeight.get()-BS
- print("FW={0},FH={1}".format(FW,FH))
- StitchSize = ComboStitch.get()
- MaxStitchW = (FW*StitchSize)/tempsize[0]
- MaxStitchH = (FH*StitchSize)/tempsize[1]
- print("MSW={0},MSH={1}".format(MaxStitchW,MaxStitchH))
- NewImageHeight = MaxStitchH * tempsize[1]
- NewImageWidth = MaxStitchW * tempsize[0]
- print("NIW={0},NIH={1}".format(NewImageWidth,NewImageHeight))
- newImage = im.resize((int(NewImageWidth),int(NewImageHeight)),Image.NEAREST)
- newImage.save('temp.jpg')
- return newImage
- def StitchSizeSelect(self,p):
- selection = ComboStitch.get()
- print selection
- def AidaSizeSelect(self,p):
- selection = ComboSize.get()
- print selection
- if selection != "30":
- pos = selection.find("x")
- width = int(selection[:pos])
- height=int(selection[pos+1:])
- print("W={0},H={1}".format(width,height))
- else:
- width = 30
- height = 30
- FabricWidth.set(width)
- FabricHeight.set(height)
- def rgb2hex(self,rgb):
- return '#%02x%02x%02x' % rgb
- def FillScrolledList(self,filename):
- im = Image.open(filename)
- numColors = im.getcolors()
- colors = len(numColors)
- cntr = 1
- for c in numColors:
- hexcolor = self.rgb2hex(c[1])
- lblColor=Label(self.sfFrame,text=" ",bg=hexcolor,relief=GROOVE)
- lblColor.grid(row = cntr, column = 0, sticky = 'nsew',padx=10,pady=5)
- pkID = self.GetBestDistance(c[1][0],c[1][1],c[1][2])
- sql = "SELECT * FROM DMC WHERE pkID = {0}".format(pkID)
- rset = cursor.execute(sql)
- for r in rset:
- hexcolor2 = r[6]
- dmcnum = r[1]
- colorname = r[2]
- lblColor2=Label(self.sfFrame,text=" ",bg="#" + hexcolor2,relief=GROOVE)
- lblColor2.grid(row = cntr,column = 1,sticky = 'w',padx=5,pady=5)
- lblColor3=Label(self.sfFrame,text = str(dmcnum) + "-" + colorname,justify=LEFT)
- DmcColor.set(dmcnum)
- lblColor3.grid(row = cntr, column = 2,sticky = "w",padx=1,pady=5)
- cntr += 1
- def OpenDB(self):
- global connection
- global cursor
- #---------------------------------
- connection = apsw.Connection("floss.db3")
- cursor = connection.cursor()
- def GetBestDistance(self,r1,g1,b1):
- # dist = math.sqrt(((r1-r2)**2) + ((g1-g2)**2) + ((b1-b2)**2))
- sql = "SELECT * FROM DMC"
- rset = cursor.execute(sql)
- BestDist = 10000.0
- for r in rset:
- pkID = r[0]
- r2 = r[3]
- g2 = r[4]
- b2 = r[5]
- dist = math.sqrt(((r1-r2)**2) + ((g1-g2)**2) + ((b1-b2)**2))
- if dist < BestDist:
- BestDist = dist
- BestpkID = pkID
- return BestpkID
- def ShowHideGrid(self):
- global ShowGrid
- #---------------------------------
- if ShowGrid == False:
- self.btnShowGrid['text'] = 'Hide Grid'
- ShowGrid = True
- self.im2=Image.open(self.GridImage)
- self.im2.thumbnail((500,500))
- self.img3 = ImageTk.PhotoImage(self.im2)
- self.lblImageR['image'] = self.img3
- else:
- self.btnShowGrid['text'] = 'Show Grid'
- ShowGrid = False
- self.im2=Image.open(self.ProcessedImage)
- self.im2.thumbnail((500,500))
- self.img3 = ImageTk.PhotoImage(self.im2)
- self.lblImageR['image'] = self.img3
- def FileSave(self):
- tkMessageBox.showinfo(title="File Save",message='Sorry, but the File Save function is not yet available.')
- def ShowHelp(self):
- tkMessageBox.showinfo(title="Help",message='Sorry, but help is not yet available.')
- def ShowAbout(self):
- tkMessageBox.showinfo(title="About",message='Sorry, but the About function is not yet available.')
- def DoExit(self):
- sys.exit()
- root = Tk()
- root.title("Cross Stitch Pattern Creator")
- test = Test(root)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement