I need to to convert PNGs coming from chrome-headless to BMPs to work with them, and I also need to do this through pipes without saving those images somewhere.
Chrome is set up to just screencast the images to stdout, which is working fine, but I can't seem to get the imagemagick convert tool to do, what I need.
While testing with
cat foo.png | convert PNG:- BMP:-
seems to work with one input image (Output starts with 'BM', indicating BMP binary garbage),
cat foo.png bar.png | convert PNG:- BMP:-
also returns only one image, which seems to be the first one.
How can I get convert to "overwrite" the output for each file it reads through stdin?
EDIT: The cat example is just to demonstrate the input. The final idea is more like
chrome-headless | *solution* | bmpreader
As fmw42 and Mark pointed out, this doesn't seem to be possible with imagemagick out of the box.
As Fred (@fmw42) says, you cannot do this with ImageMagick alone, but it should be possible to do something with a small C/C++, Perl, PHP or Python script.
Basically, PNG files are nicely "chunked", see Wikipedia PNG Specification, and each chunk has a type - such as IHDR
(header), PLTE
(palette), IDAT
(image data), IEND
(end of file marker) and, crucially, a length in bytes.
So, you could write a script/program that reads data off your pipe, gets the chunks and appends them to an in-memory string and keeps doing so until it reaches an IEND
chunk. At that point it would either use ImageMagick or GD or Pillow to convert the in-memory string into a BMP and write it to a further pipe, or write the string to a pipe that ImageMagick was reading from and let ImageMagick convert the file. You would then zero out the accumulated (PNG) string and start reading the next file.
I don't feel like writing and debugging all that for 15 points, but it would look something like this:
chrome-cast | demultiplex
where demultiplex
would be like:
while not error
clear accumulated string of PNG data
done = false
while not done
read chunk type and length of chunk
read whole chunk and append to accumulated string of PNG data
if chunk = IEND
pass accumulated PNG string to ImageMagick to make BMP
done = true
endif
end
end
Note that your program would not have to "understand" all the chunk types or their contents - just recognise the chunk length and the IEND
chunk when it arrives.
Note that you may like to run pngcheck
or pngsplit
to get started in understanding how PNG files are structured in chunks - they are here. In fact, pngsplit
may do what you want anyway.
Here is an example of pngcheck
in action:
pngcheck -v file.png
File: file.png (462308 bytes)
chunk IHDR at offset 0x0000c, length 13
800 x 468 image, 32-bit RGB+alpha, non-interlaced
chunk gAMA at offset 0x00025, length 4: 0.45455
chunk cHRM at offset 0x00035, length 32
White x = 0.3127 y = 0.329, Red x = 0.64 y = 0.33
Green x = 0.3 y = 0.6, Blue x = 0.15 y = 0.06
chunk bKGD at offset 0x00061, length 6
red = 0x00ff, green = 0x00ff, blue = 0x00ff
chunk pHYs at offset 0x00073, length 9: 3779x3779 pixels/meter (96 dpi)
chunk tIME at offset 0x00088, length 7: 2 Oct 2017 21:34:26 UTC
chunk IDAT at offset 0x0009b, length 32768
zlib: deflated, 32K window, maximum compression
chunk IDAT at offset 0x080a7, length 32768
chunk IDAT at offset 0x100b3, length 32768
chunk IDAT at offset 0x180bf, length 32768
chunk IDAT at offset 0x200cb, length 32768
chunk IDAT at offset 0x280d7, length 32768
chunk IDAT at offset 0x300e3, length 32768
chunk IDAT at offset 0x380ef, length 32768
chunk IDAT at offset 0x400fb, length 32768
chunk IDAT at offset 0x48107, length 32768
chunk IDAT at offset 0x50113, length 32768
chunk IDAT at offset 0x5811f, length 32768
chunk IDAT at offset 0x6012b, length 32768
chunk IDAT at offset 0x68137, length 32768
chunk IDAT at offset 0x70143, length 3115
chunk tEXt at offset 0x70d7a, length 37, keyword: date:create
chunk tEXt at offset 0x70dab, length 37, keyword: date:modify
chunk IEND at offset 0x70ddc, length 0
No errors detected in file.png (24 chunks, 69.1% compression).
I did a rudimentary version of the PNG chunking in Perl for another answer, so have a quick look here.