title: Convert RGBA PNG to RGB with PIL
body: <p>I'm using PIL to convert a transparent PNG image uploaded with Django to a JPG file. The output looks broken.</p>
  
  <h3>Source file</h3>
  
  <p><img src="https://i.stack.imgur.com/I2uNe.png" alt="transparent source file"></p>
  
  <h3>Code</h3>
  
  <pre><code>Image.open(object.logo.path).save('/tmp/output.jpg', 'JPEG')
  </code></pre>
  
  <p>or</p>
  
  <pre><code>Image.open(object.logo.path).convert('RGB').save('/tmp/output.png')
  </code></pre>
  
  <h3>Result</h3>
  
  <p>Both ways, the resulting image looks like this:</p>
  
  <p><img src="https://i.stack.imgur.com/rmlPz.png" alt="resulting file"></p>
  
  <p>Is there a way to fix this? I'd like to have white background where the transparent background used to be.</p>
  
  <hr>
  
  <h1>Solution</h1>
  
  <p>Thanks to the great answers, I've come up with the following function collection:</p>
  
  <pre><code>import Image
  import numpy as np
  
  
  def alpha_to_color(image, color=(255, 255, 255)):
      """Set all fully transparent pixels of an RGBA image to the specified color.
      This is a very simple solution that might leave over some ugly edges, due
      to semi-transparent areas. You should use alpha_composite_with color instead.
  
      Source: http://stackoverflow.com/a/9166671/284318
  
      Keyword Arguments:
      image -- PIL RGBA Image object
      color -- Tuple r, g, b (default 255, 255, 255)
  
      """ 
      x = np.array(image)
      r, g, b, a = np.rollaxis(x, axis=-1)
      r[a == 0] = color[0]
      g[a == 0] = color[1]
      b[a == 0] = color[2] 
      x = np.dstack([r, g, b, a])
      return Image.fromarray(x, 'RGBA')
  
  
  def alpha_composite(front, back):
      """Alpha composite two RGBA images.
  
      Source: http://stackoverflow.com/a/9166671/284318
  
      Keyword Arguments:
      front -- PIL RGBA Image object
      back -- PIL RGBA Image object
  
      """
      front = np.asarray(front)
      back = np.asarray(back)
      result = np.empty(front.shape, dtype='float')
      alpha = np.index_exp[:, :, 3:]
      rgb = np.index_exp[:, :, :3]
      falpha = front[alpha] / 255.0
      balpha = back[alpha] / 255.0
      result[alpha] = falpha + balpha * (1 - falpha)
      old_setting = np.seterr(invalid='ignore')
      result[rgb] = (front[rgb] * falpha + back[rgb] * balpha * (1 - falpha)) / result[alpha]
      np.seterr(**old_setting)
      result[alpha] *= 255
      np.clip(result, 0, 255)
      # astype('uint8') maps np.nan and np.inf to 0
      result = result.astype('uint8')
      result = Image.fromarray(result, 'RGBA')
      return result
  
  
  def alpha_composite_with_color(image, color=(255, 255, 255)):
      """Alpha composite an RGBA image with a single color image of the
      specified color and the same size as the original image.
  
      Keyword Arguments:
      image -- PIL RGBA Image object
      color -- Tuple r, g, b (default 255, 255, 255)
  
      """
      back = Image.new('RGBA', size=image.size, color=color + (255,))
      return alpha_composite(image, back)
  
  
  def pure_pil_alpha_to_color_v1(image, color=(255, 255, 255)):
      """Alpha composite an RGBA Image with a specified color.
  
      NOTE: This version is much slower than the
      alpha_composite_with_color solution. Use it only if
      numpy is not available.
  
      Source: http://stackoverflow.com/a/9168169/284318
  
      Keyword Arguments:
      image -- PIL RGBA Image object
      color -- Tuple r, g, b (default 255, 255, 255)
  
      """ 
      def blend_value(back, front, a):
          return (front * a + back * (255 - a)) / 255
  
      def blend_rgba(back, front):
          result = [blend_value(back[i], front[i], front[3]) for i in (0, 1, 2)]
          return tuple(result + [255])
  
      im = image.copy()  # don't edit the reference directly
      p = im.load()  # load pixel array
      for y in range(im.size[1]):
          for x in range(im.size[0]):
              p[x, y] = blend_rgba(color + (255,), p[x, y])
  
      return im
  
  def pure_pil_alpha_to_color_v2(image, color=(255, 255, 255)):
      """Alpha composite an RGBA Image with a specified color.
  
      Simpler, faster version than the solutions above.
  
      Source: http://stackoverflow.com/a/9459208/284318
  
      Keyword Arguments:
      image -- PIL RGBA Image object
      color -- Tuple r, g, b (default 255, 255, 255)
  
      """
      image.load()  # needed for split()
      background = Image.new('RGB', image.size, color)
      background.paste(image, mask=image.split()[3])  # 3 is the alpha channel
      return background
  </code></pre>
  
  <h2>Performance</h2>
  
  <p>The simple non-compositing <code>alpha_to_color</code> function is the fastest solution, but leaves behind ugly borders because it does not handle semi transparent areas.</p>
  
  <p>Both the pure PIL and the numpy compositing solutions give great results, but <code>alpha_composite_with_color</code> is much faster (8.93 msec) than <code>pure_pil_alpha_to_color</code> (79.6 msec). <del>If numpy is available on your system, that's the way to go.</del> (Update: The new pure PIL version is the fastest of all mentioned solutions.)</p>
  
  <pre><code>$ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.alpha_to_color(i)"
  10 loops, best of 3: 4.67 msec per loop
  $ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.alpha_composite_with_color(i)"
  10 loops, best of 3: 8.93 msec per loop
  $ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.pure_pil_alpha_to_color(i)"
  10 loops, best of 3: 79.6 msec per loop
  $ python -m timeit "import Image; from apps.front import utils; i = Image.open(u'logo.png'); i2 = utils.pure_pil_alpha_to_color_v2(i)"
  10 loops, best of 3: 1.1 msec per loop
  </code></pre>