def average_hash_and_sizes(self): height = 0 width = 0 if isJython(): image = ImageIO.read(File(self.image_path)) height = image.getHeight() width = image.getWidth() newImage = BufferedImage(self.hash_size, self.hash_size, BufferedImage.TYPE_INT_ARGB) g = newImage.createGraphics() g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC) g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.drawImage(image, 0, 0, self.hash_size, self.hash_size, None) g.dispose() allchannelpixels = [[], [], [], []] for i in range(self.hash_size): for j in range(self.hash_size): pixel = int(newImage.getRGB(i, j)) allchannelpixels[0].append((pixel >> 16) & 0xFF) allchannelpixels[1].append((pixel >> 8) & 0xFF) allchannelpixels[2].append((pixel) & 0xFF) allchannelpixels[3].append((pixel >> 24) & 0xFF) elif isIronPython(): srcImage = Bitmap(self.image_path) height = srcImage.Height width = srcImage.Width newImage = Bitmap(self.hash_size, self.hash_size) gr = Graphics.FromImage(newImage) gr.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias gr.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic gr.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality gr.DrawImage(srcImage, Rectangle(0, 0, self.hash_size, self.hash_size)) allchannelpixels = [[], [], [], []] for i in range(self.hash_size): for j in range(self.hash_size): pixel = newImage.GetPixel(i, j) allchannelpixels[0].append(int(pixel.R)) allchannelpixels[1].append(int(pixel.G)) allchannelpixels[2].append(int(pixel.B)) allchannelpixels[3].append(int(pixel.A)) else: self.image = Image.open(self.image_path) width, height = self.image.size image = self.image.resize((self.hash_size, self.hash_size), Image.ANTIALIAS) # image.show() allchannelpixels = [ list(channel.getdata()) for channel in image.split() ] bits = [] for pixels in allchannelpixels: bits.append(self.getBitString(pixels)) return bits, width, height
class Image: """Holds an image of RGB pixels accessed by column and row indices (col, row). Origin (0, 0) is at upper left.""" # QUESTION: For efficiency, should we also extract and save self.pixels (at image reading time)? # Also make setPixel(), getPixel(), setPixels() and getPixels() work on/with self.pixels. # And when writing, use code in current setPixels() to update image buffer, before writing it out? # This is something to try. def __init__(self, filename, width=None, height=None): """Create an image from a file, or an empty (black) image with specified dimensions.""" # Since Python does not allow constructors with different signatures, # the trick is to reuse the first argument as a filename or a width. # If it is a string, we assume they want is to open a file. # If it is an int, we assume they want us to create a blank image. if type(filename) == type(""): # is it a string? self.filename = filename # treat is a filename self.image = BufferedImage( 1, 1, BufferedImage.TYPE_INT_RGB) # create a dummy image self.read(filename) # and read external image into ti elif type(filename) == type(1): # is it a int? # create blank image with specified dimensions self.filename = "Untitled" self.width = filename # holds image width (shift arguments) self.height = width # holds image height self.image = BufferedImage( self.width, self.height, BufferedImage.TYPE_INT_RGB) # holds image buffer (pixels) else: raise TypeError( "Image(): first argument must a filename (string) or an blank image width (int)." ) # display image self.display = JFrame() # create frame window to hold image icon = ImageIcon( self.image) # wrap image appropriately for displaying in a frame container = JLabel(icon) self.display.setContentPane(container) # and place it self.display.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) self.display.setTitle(self.filename) self.display.setResizable(False) self.display.pack() self.display.setVisible(True) # remember that this image has been created and is active (so that it can be stopped/terminated by JEM, if desired) _ActiveImages_.append(self) def getWidth(self): """Returns the width of the image.""" return self.width def getHeight(self): """Returns the height of the image.""" return self.height def getPixel(self, col, row): """Returns a list of the RGB values for this pixel, e.g., [255, 0, 0].""" # Obsolete - convert the row so that row zero refers to the bottom row of pixels. #row = self.height - row - 1 color = Color(self.image.getRGB(col, row)) # get pixel's color return [color.getRed(), color.getGreen(), color.getBlue()] # create list of RGB values (0-255) def setPixel(self, col, row, RGBlist): """Sets this pixel's RGB values, e.g., [255, 0, 0].""" # Obsolete - convert the row so that row zero refers to the bottom row of pixels. #row = self.height - row - 1 color = Color(RGBlist[0], RGBlist[1], RGBlist[2]) # create color from RGB values self.image.setRGB(col, row, color.getRGB()) def getPixels(self): """Returns a 2D list of pixels (col, row) - each pixel is a list of RGB values, e.g., [255, 0, 0].""" pixels = [] # initialize list of pixels #for row in range(self.height-1, 0, -1): # load pixels from image for row in range(0, self.height): # load pixels from image pixels.append([]) # add another empty row for col in range(self.width): # populate row with pixels # RGBlist = self.getPixel(col, row) # this works also (but slower) color = Color(self.image.getRGB(col, row)) # get pixel's color RGBlist = [color.getRed(), color.getGreen(), color.getBlue() ] # create list of RGB values (0-255) pixels[-1].append( RGBlist) # add a pixel as (R, G, B) values (0-255, each) # now, 2D list of pixels has been created, so return it return pixels def setPixels(self, pixels): """Sets image to the provided 2D list of pixels (col, row) - each pixel is a list of RGB values, e.g., [255, 0, 0].""" self.height = len(pixels) # get number of rows self.width = len( pixels[0] ) # get number of columns (assume all columns have same length #for row in range(self.height-1, 0, -1): # iterate through all rows for row in range(0, self.height): # iterate through all rows for col in range( self.width): # iterate through every column on this row RGBlist = pixels[row][col] #self.setPixel(col, row, RGBlist) # this works also (but slower) color = Color(RGBlist[0], RGBlist[1], RGBlist[2]) # create color from RGB values self.image.setRGB(col, row, color.getRGB()) def read(self, filename): """Read an image from a .png, .gif, or .jpg file. as 2D list of RGB pixels.""" # JEM working directory fix (see above) filename = fixWorkingDirForJEM(filename) # does nothing if not in JEM # *** #print "fixWorkingDirForJEM( filename ) =", filename file = File(filename) # read file from current directory self.image = ImageIO.read(file) self.width = self.image.getWidth(None) self.height = self.image.getHeight(None) pixels = [] # initialize list of pixels # load pixels from image for row in range(self.height): pixels.append([]) # add another empty row for col in range(self.width): # now, populate row with pixels color = Color(self.image.getRGB(col, row)) # get pixel's color RGBlist = [color.getRed(), color.getGreen(), color.getBlue() ] # create list of RGB values (0-255) pixels[-1].append( RGBlist) # add a pixel as (R, G, B) values (0-255, each) # now, pixels have been loaded from image file, so create an image self.setPixels(pixels) def write(self, filename): """Saves the pixels to a file (.png or .jpg).""" # JEM working directory fix (see above) filename = fixWorkingDirForJEM(filename) # does nothing if not in JEM # *** #print "fixWorkingDirForJEM( filename ) =", filename # get suffix suffix = filename[-3:] suffix = suffix.lower() if suffix == "jpg" or suffix == "png": ImageIO.write(self.image, suffix, File(filename)) # save, and also self.filename = filename # update image filename self.display.setTitle(self.filename) # update display title else: print "Filename must end in .jpg or .png" def show(self): """It displays the image.""" self.display.setVisible(True) #self.display.repaint() # draw it def hide(self): """It hides the image.""" self.display.setVisible(False)
class Image: """Holds an image of RGB pixels accessed by column and row indices (col, row). Origin (0, 0) is at upper left.""" # QUESTION: For efficiency, should we also extract and save self.pixels (at image reading time)? # Also make setPixel(), getPixel(), setPixels() and getPixels() work on/with self.pixels. # And when writing, use code in current setPixels() to update image buffer, before writing it out? # This is something to try. def __init__(self, filename, width=None, height=None): """Create an image from a file, or an empty (black) image with specified dimensions.""" # Since Python does not allow constructors with different signatures, # the trick is to reuse the first argument as a filename or a width. # If it is a string, we assume they want is to open a file. # If it is an int, we assume they want us to create a blank image. if type(filename) == type(""): # is it a string? self.filename = filename # treat is a filename self.image = BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB) # create a dummy image self.read(filename) # and read external image into ti elif type(filename) == type(1): # is it a int? # create blank image with specified dimensions self.filename = "Untitled" self.width = filename # holds image width (shift arguments) self.height = width # holds image height self.image = BufferedImage(self.width, self.height, BufferedImage.TYPE_INT_RGB) # holds image buffer (pixels) else: raise TypeError("Image(): first argument must a filename (string) or an blank image width (int).") # display image self.display = JFrame() # create frame window to hold image icon = ImageIcon(self.image) # wrap image appropriately for displaying in a frame container = JLabel(icon) self.display.setContentPane(container) # and place it self.display.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) self.display.setTitle(self.filename) self.display.setResizable(False) self.display.pack() self.display.setVisible(True) def getWidth(self): """Returns the width of the image.""" return self.width def getHeight(self): """Returns the height of the image.""" return self.height def getPixel(self, col, row): """Returns a list of the RGB values for this pixel, e.g., [255, 0, 0].""" # Obsolete - convert the row so that row zero refers to the bottom row of pixels. #row = self.height - row - 1 color = Color(self.image.getRGB(col, row)) # get pixel's color return [color.getRed(), color.getGreen(), color.getBlue()] # create list of RGB values (0-255) def setPixel(self, col, row, RGBlist): """Sets this pixel's RGB values, e.g., [255, 0, 0].""" # Obsolete - convert the row so that row zero refers to the bottom row of pixels. #row = self.height - row - 1 color = Color(RGBlist[0], RGBlist[1], RGBlist[2]) # create color from RGB values self.image.setRGB(col, row, color.getRGB()) def getPixels(self): """Returns a 2D list of pixels (col, row) - each pixel is a list of RGB values, e.g., [255, 0, 0].""" pixels = [] # initialize list of pixels #for row in range(self.height-1, 0, -1): # load pixels from image for row in range(0, self.height): # load pixels from image pixels.append( [] ) # add another empty row for col in range(self.width): # populate row with pixels # RGBlist = self.getPixel(col, row) # this works also (but slower) color = Color(self.image.getRGB(col, row)) # get pixel's color RGBlist = [color.getRed(), color.getGreen(), color.getBlue()] # create list of RGB values (0-255) pixels[-1].append( RGBlist ) # add a pixel as (R, G, B) values (0-255, each) # now, 2D list of pixels has been created, so return it return pixels def setPixels(self, pixels): """Sets image to the provided 2D list of pixels (col, row) - each pixel is a list of RGB values, e.g., [255, 0, 0].""" self.height = len(pixels) # get number of rows self.width = len(pixels[0]) # get number of columns (assume all columns have same length #for row in range(self.height-1, 0, -1): # iterate through all rows for row in range(0, self.height): # iterate through all rows for col in range(self.width): # iterate through every column on this row RGBlist = pixels[row][col] #self.setPixel(col, row, RGBlist) # this works also (but slower) color = Color(RGBlist[0], RGBlist[1], RGBlist[2]) # create color from RGB values self.image.setRGB(col, row, color.getRGB()) def read(self, filename): """Read an image from a .png, .gif, or .jpg file. as 2D list of RGB pixels.""" # JEM working directory fix (see above) filename = fixWorkingDirForJEM( filename ) # does nothing if not in JEM # *** #print "fixWorkingDirForJEM( filename ) =", filename file = File(filename) # read file from current directory self.image = ImageIO.read(file) self.width = self.image.getWidth(None) self.height = self.image.getHeight(None) pixels = [] # initialize list of pixels # load pixels from image for row in range(self.height): pixels.append( [] ) # add another empty row for col in range(self.width): # now, populate row with pixels color = Color(self.image.getRGB(col, row)) # get pixel's color RGBlist = [color.getRed(), color.getGreen(), color.getBlue()] # create list of RGB values (0-255) pixels[-1].append( RGBlist ) # add a pixel as (R, G, B) values (0-255, each) # now, pixels have been loaded from image file, so create an image self.setPixels(pixels) def write(self, filename): """Saves the pixels to a file (.png or .jpg).""" # JEM working directory fix (see above) filename = fixWorkingDirForJEM( filename ) # does nothing if not in JEM # *** #print "fixWorkingDirForJEM( filename ) =", filename # get suffix suffix = filename[-3:] suffix = suffix.lower() if suffix == "jpg" or suffix =="png": ImageIO.write(self.image, suffix, File(filename)) # save, and also self.filename = filename # update image filename self.display.setTitle(self.filename) # update display title else: print "Filename must end in .jpg or .png" def show(self): """It displays the image.""" self.display.setVisible(True) #self.display.repaint() # draw it def hide(self): """It hides the image.""" self.display.setVisible(False)