Search code examples
imagemagickpng

imagemagick convert png 16 bit to raw


I'm trying to convert a 16 bit greyscale PNG to a raw file. The image size is 640*480.

First, identify:

$ identify image.png 
image.png PNG 640x480 640x480+0+0 16-bit PseudoClass 65536c 299KB 0.000u 0:00.000

I'm expecting the result file to be 640*480*2 bytes in size.

Attempt 1:

$ convert image.png -depth 16 image.raw

This gives a file size of 330805 bytes. Its first 16 bytes look like:

0x00000000: 89504E47 0D0A1A0A 0000000D 49484452     .PNG........IHDR

Attempt 2:

$ convert image.png -depth 16 image.rgb

This gives a file size of 1843200 bytes, which is 640*480*2*3.

I'm running imagemagick version 6.7.7-10 on Ubuntu 14.04.

Any ideas?


Solution

  • Updated Answer

    It occurred to me since answering you, that there is a simpler method of doing what you want, that takes advantage of ImageMagick's little-used stream tool, to stream raw pixel data around.

    In effect, you can use this command

    stream -map r -storage-type short image.png image.raw
    

    which will read the Red channel (-map r), which is the same as the Green and Blue channels if your image is greyscale, and write it out as unsigned 16-bit shorts (-storage-type short) to the output file image.raw.

    This is cleaner than my original answer - though should give identical results.

    Original Answer

    If you write an RGB raw file, you will get 3 channels - R, G and B. Try writing a PGM (Portable Greymap) like this...

    convert image.png -depth 16 pgm:-
    P5
    640 480
    65535
    <binary data> < binary data>
    

    The PGM format is detailed here, but suffice to say that there is header with a P followed by a digit describing the actual subtype, then a width and height and then a MAX VALUE that describes the range of the pixel intensities. In your case, the MAX VALUE is 65535 rather than 255 because your data are 16-bit.

    You can the strip the header like this:

    convert image.png -depth 16 pgm:- | tail -c 614400 > file.raw
    

    If you are converting lots of files of different sizes and dislike the hard-coded 614400, and are using bash, you can get ImageMagick to tell you the size (height * width * 2 bytes/pixel) and use that like this:

    bytes=$(identify -format "%[fx:h*w*2]" image.png)
    convert image.png -depth 16 pgm:- | tail -c $bytes > file.raw