lyell
lyell

Reputation: 71

PIL/Pillow inverting transparency seemingly arbitrarily

I have Pillow 2.4.0 installed (both in a virtual env on OS X and on a Ubuntu 14.04 EC2). I wrote the following script to generate a visualization of a waveform (drawing some inspiration from Jiaaro). It uses the Pydub library to analyze the waveform and the ImageDraw function from PIL/Pillow to draw the lines. The wav variable is an audiosegment() (from the Pydub library), imgname is a string:

def draw_waveform(wav, imgname, color="#000000", w=400, h=40):
    sound = wav
    name = imgname
    width = w
    height = h
    color = color

    chunk_length = len(sound) / width

    loudness_of_chunks = [
        sound[ i*chunk_length : (i+1)*chunk_length ].rms
        for i in range(width)]

    max_rms = max(loudness_of_chunks)
    scale = max_rms/(height/2)

    size = (width,height)
    im = Image.new('RGBA', size, (255, 255, 255, 255))

    draw = ImageDraw.Draw(im)

    for i in range(1, width):
        pos = (width - i, height/2 + loudness_of_chunks[i]/scale-4)
        draw.line((width - i,height/2) + pos, fill=color)
        pos = (width - i, height/2 - loudness_of_chunks[i]/scale+4)
        draw.line((width - i,height/2) + pos, fill=color)

    del draw

    im.rotate(180).save(app.config['UPLOAD_FOLDER'] + '/' + name, 'GIF', transparency=0) #, transparency=0

    return app.config['UPLOAD_FOLDER'] + '/' + name

All's groovy, most of the time. On some waveforms, particularly, it seems, the ones that are closest to peaking, PIL will output a GIF that has flipped transparency - the waveform will be transparent and the space around it will be white. Normally the background's transparent and the waveform is black (#000000).

Here is a picture of the expected output:

Correct output

And the incorrect (right click save-as and open in an image editor, as its background is white and the middle is transparent):

Incorrect output

Has anyone experienced a similar issue? Am I missing something obvious (likely)?

Upvotes: 4

Views: 1179

Answers (1)

lyell
lyell

Reputation: 71

Turns out this is simpler than I imagined it to be (surprise surprise). Thanks to @MarkRansom for inspiration here.

Instantiate the image with 'P' rather than 'RGBA',

im = Image.new('P', size, 255)

Define your color (for black, 0)

color=0

Ensure that the save call defines the white area as transparent rather than the black:

im.save(name, 'GIF', transparency=255)

Still a little curious why it would only fail some of the time with the original code...

Upvotes: 3

Related Questions