Skip to content

Instantly share code, notes, and snippets.

@GrantTrebbin
Created May 21, 2015 13:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GrantTrebbin/4aba7898840d96fc6b86 to your computer and use it in GitHub Desktop.
Save GrantTrebbin/4aba7898840d96fc6b86 to your computer and use it in GitHub Desktop.
Compressing Similar PNG Images
#!/usr/bin/python
from PIL import Image
import numpy
import argparse
import os
import sys
#Configure argument parser to take input arguments
parser = argparse.ArgumentParser(description='Compress similar PNG images')
parser.add_argument('firstFile', type=argparse.FileType('r'),
help='First Image File')
parser.add_argument('secondFile', type=argparse.FileType('r'),
help='Second Image File')
args = parser.parse_args()
#Open first image
firstImageObject = Image.open(args.firstFile.name)
firstImMode = firstImageObject.mode
#Convert first image to array
if (firstImMode == 'L'):
print ('L')
firstImage = numpy.asarray(firstImageObject)
firstImageChannels = 1
elif (firstImMode == 'P'):
print ('p')
firstImage = numpy.asarray(firstImageObject.convert('RGBA'))
firstImageChannels = 4
elif (firstImMode == 'RGB'):
print ('rgb')
firstImage = numpy.asarray(firstImageObject)
firstImageChannels = 3
elif (firstImMode == 'RGBA'):
print ('rgba')
firstImage = numpy.asarray(firstImageObject)
firstImageChannels = 4
else:
sys.exit("This type of image can't be handled, maybe it is palette based")
#Open second image
secondImageObject = Image.open(args.secondFile.name)
secondImMode = secondImageObject.mode
#Convert second image to array
if (secondImMode == 'L'):
secondImage = numpy.asarray(secondImageObject)
secondImageChannels = 1
elif (secondImMode == 'P'):
secondImage = numpy.asarray(secondImageObject.convert('RGBA'))
secondImageChannels = 4
elif (secondImMode == 'RGB'):
secondImage = numpy.asarray(secondImageObject)
secondImageChannels = 3
elif (secondImMode == 'RGBA'):
secondImage = numpy.asarray(secondImageObject)
secondImageChannels = 4
else:
sys.exit("This type of image can't be handled, maybe it is palette based")
#Check to make sure the images have the same number of channels
if (firstImageChannels != secondImageChannels):
sys.exit("The two images have a different number of channels")
#Check to make sure the images are the same size
if (firstImage.shape != secondImage.shape) :
sys.exit("Image dimensions don't match")
#calculate difference and sign images
differenceImage = numpy.subtract(firstImage.astype('int'), secondImage.astype('int'))
absoluteDifferenceImage = numpy.abs(differenceImage)
imageSign = 255*(differenceImage < 0).astype('uint8')
#Write sign and difference images to file for each channel
for channel in range(0,firstImageChannels):
if (firstImageChannels == 1):
imOut = Image.fromarray(absoluteDifferenceImage.astype('uint8'))
signOut = Image.fromarray(imageSign.astype('uint8'))
else:
imOut = Image.fromarray(absoluteDifferenceImage[:,:,channel].astype('uint8'))
signOut = Image.fromarray(imageSign[:,:,channel].astype('uint8'))
imOut.save(args.firstFile.name + args.secondFile.name + str(channel) + "D.png")
signOut.save(args.firstFile.name + args.secondFile.name + str(channel) + "S.png")
#!/usr/bin/python
from PIL import Image
import numpy
import argparse
import os
import sys
#Configure argument parser to take input arguments
parser = argparse.ArgumentParser(description='Expand compressed PNG images. Example ' +
'"imInflate.py 1.png 2.png" takes the ' +
'file 1.png and uses the files ' +
'1.png2.pngxD.png and 1.png2.pngxS.png ' +
'to recreate 2.png Two images are required ' +
'for each channel of the first file, where x ' +
'in the above example is the channel number ')
parser.add_argument('baseFileName', help='Base Image File')
parser.add_argument('outputFileName', help='Output Image File')
args = parser.parse_args()
#Load base Image
with Image.open(args.baseFileName) as baseImageObject:
baseImMode = baseImageObject.mode
if (baseImMode == 'L'):
baseImage = numpy.asarray(baseImageObject)
baseImageChannels = 1
elif (baseImMode == 'P'):
baseImage = numpy.asarray(baseImageObject.convert('RGBA'))
baseImageChannels = 4
elif (baseImMode == 'RGB'):
baseImage = numpy.asarray(baseImageObject)
baseImageChannels = 3
elif (baseImMode == 'RGBA'):
baseImage = numpy.asarray(baseImageObject)
baseImageChannels = 4
else:
sys.exit("This type of image can't be handled, maybe it is palette based")
#Make base image writeable
baseImage.setflags(write=True)
print (baseImageChannels)
for channel in range(0,baseImageChannels):
with Image.open(args.baseFileName + args.outputFileName + str(channel) + "D" + ".png") as diffFile:
absoluteDifferenceImage = numpy.asarray(diffFile)
with Image.open(args.baseFileName + args.outputFileName + str(channel) + "S" + ".png") as signFile:
signImage = numpy.asarray(signFile)
signMask = (-2*(signImage)//255 + 1)
differenceImage = numpy.multiply(absoluteDifferenceImage, signMask)
if (baseImageChannels == 1):
baseImage = baseImage - differenceImage
print (numpy.min(baseImage))
else:
baseImage[:,:,channel] = baseImage[:,:,channel] - differenceImage
imOut = Image.fromarray(baseImage.astype('uint8'))
imOut.save(args.outputFileName)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment