61
votes

I need to convert series of images drawn as white on black background letters to images where white and black are inverted (as negative). How can I achieve this using PIL?

5

5 Answers

98
votes

Try the following from the docs: http://effbot.org/imagingbook/imageops.htm

from PIL import Image
import PIL.ImageOps    

image = Image.open('your_image.png')

inverted_image = PIL.ImageOps.invert(image)

inverted_image.save('new_name.png')

Note: "The ImageOps module contains a number of 'ready-made' image processing operations. This module is somewhat experimental, and most operators only work on L and RGB images."

33
votes

If the image is RGBA transparent this will fail... This should work though:

from PIL import Image
import PIL.ImageOps    

image = Image.open('your_image.png')
if image.mode == 'RGBA':
    r,g,b,a = image.split()
    rgb_image = Image.merge('RGB', (r,g,b))

    inverted_image = PIL.ImageOps.invert(rgb_image)

    r2,g2,b2 = inverted_image.split()

    final_transparent_image = Image.merge('RGBA', (r2,g2,b2,a))

    final_transparent_image.save('new_file.png')

else:
    inverted_image = PIL.ImageOps.invert(image)
    inverted_image.save('new_name.png')
27
votes

For anyone working with an image in "1" mode (i.e., 1-bit pixels, black and white, stored with one pixel per byte -- see docs), you need to convert it into "L" mode before calling PIL.ImageOps.invert.

Thus:

im = im.convert('L')
im = ImageOps.invert(im)
im = im.convert('1')
-1
votes

In case someone is inverting a CMYK image, the current implementations of PIL and Pillow don't seem to support this and throw an error. You can, however, easily circumvent this problem by inverting your image's individual bands using this handy function (essentially an extension of Greg Sadetsky's post above):

def CMYKInvert(img) :
    return Image.merge(img.mode, [ImageOps.invert(b.convert('L')) for b in img.split()])
-2
votes
from PIL import Image

img = Image.open("archive.extension") 

pixels = img.load()

for i in range(img.size[0]):
    for j in range(img.size[1]):
        x,y,z = pixels[i,j][0],pixels[i,j][1],pixels[i,j][2]
        x,y,z = abs(x-255), abs(y-255), abs(z-255)
        pixels[i,j] = (x,y,z)

img.show()

`