Using PIL to open an image with a palette and save that image with the same palette
<p>So I am trying to convert a bmp to a NumPy array, store the array somewhere, and then convert it back into a bmp image at a later time. </p>

<pre><code>bmp = Image.open(fn_bmp)
data = np.array(bmp.convert('P', palette=Image.WEB))
</code></pre>

<p>This data is stored in another file temporarily and then I go to retrieve it at some later point.</p>

<pre><code>bmp = Image.fromarray(np.array(dataset).convert('P', palette=Image.WEB))
bmp.save(fn)
</code></pre>

<p>Note that dataset is an object converted back into a NumPy array and np.array(dataset) == data in all indices.</p>

<p>For some reason, when I show or save this resulting image, a "14" corresponding to some palette color is interpreted as a grey scale value and saved a such. How do I save the image as a colored palette bitmap image? I have tried adding options to the save (e.g. mode='P', palette=Image.WEB) to no avail. Thank you for your help.</p>

<p><strong>EDIT:</strong></p>

<p>In the tutorial portion of the PIL documentation, it specifies the limitations of conversions.</p>

<blockquote>
  <p>The library supports transformations between each supported mode and the âLâ and âRGBâ modes. To convert between other modes, you may have to use an intermediate image (typically an âRGBâ image).</p>
</blockquote>

<p>So, in order to accomplish what I was doing, I have to convert the image to RGB in the first array and convert back to P in the second.</p>

<p>However, the image (with only 4 colors) becomes distorted when converted from RGB back to P. Is there any reason for this? </p>

<p>In this case <code>Image.fromarray(data)</code> returns a greyscale image. When you convert this image to a different image mode it will remain greyscale!</p>

<p>Instead you have to supply color information in the form of a palette:</p>

<pre><code># first part
bmp = Image.open(fn_bmp)
bmp_P_web = bmp.convert('P', palette=Image.WEB)
web_palette = bmp_P_web.getpalette()  # &lt;---
data = np.array(bmp_P_web)

# second part
bmp = Image.fromarray(data)
bmp.putpalette(web_palette)  # &lt;---
</code></pre>

<p>No clue how to get the <code>web_palette</code> directly from PIL, but here's a way to generate <a href="https://github.com/python-pillow/Pillow/blob/3.3.x/libImaging/Palette.c#L65:L92" rel="nofollow">it</a> with numpy:</p>

<pre><code>web_palette = np.zeros(3*256, int)
web_palette[30:-90] = np.mgrid[0:256:51, 0:256:51, 0:256:51].ravel('F')
</code></pre>

python image numpy bitmap python-imaging-library