4

I am using custom batch script to make resized copies (33% and 66%) of all PNG images in folder. Here is my code:

for f in $(find /myFolder -name '*.png'); 
do
sudo cp -a $f "${f/%.png/-3x.png}"; 
sudo convert $f -resize 66.67% "${f/%.png/-2x.png}"; 
sudo convert $f -resize 33.33% $f; 
done

It works fine, except when the original image is indexed. In this case the smaller version of the image is RGB (so even larger file size then original image).

I have try several versions but not worked. One that I guess supposed to sort this out was fallowing:

for f in $(find /myFolder -name '*.png'); 
do
sudo cp -a $f "${f/%.png/-3x.png}"; 
sudo convert $f -define png:preserve-colormap -resize 66.67% "${f/%.png/-2x.png}"; 
sudo convert $f -define png:preserve-colormap -resize 33.33% $f; 
done

But it doesn't work.

EDIT:

This is updated co, but it still doesn't work as it supposed to (see the attached image-left is original, right is resized):

for f in $(find /myFolder -name '*.png');
do
  sudo cp -a $f "${f/%.png/-3x.png}";
  numberOfColors=`identify -format "%k" $f`

  convert "$f"                                                        \
    \( +clone -resize 66.67% -colors $numberOfColors -write "${f/%.png/-2x.png}" +delete \)  \
    -resize 33.33% -colors $numberOfColors "$f"
done

enter image description here

Original image: Original image

Scaled version: Scaled image

Juraj.Lorinc
  • 503
  • 6
  • 26
  • 1
    Is the issue that you want to preserve a specific, exact colourmap? Or that you want to be sure that the resized image is small and indexed to *a* colormap but you don't really mind what's in that colourmap? The answer will be different. – Mark Setchell Mar 09 '16 at 07:33
  • I don't mind the color map. I want to be sure that resized images are small. This is for retina images on web. The first (original image) is for screens with 3dpi screens and so on. – Juraj.Lorinc Mar 09 '16 at 09:02
  • Can you provide the original images separately please - instead of joined to the output images. – Mark Setchell Mar 09 '16 at 11:09
  • How about detecting palletised images with `convert image.png -format "%[type]" info: | grep -i Palette` and if palletised, use `-colors 250` to get the best result you can with a palletised output image. – Mark Setchell Mar 09 '16 at 13:49
  • I'm not observing this problem with the current release of ImageMagick (6.9.3-7). Your script works fine and produces clean -2x and -3x images. What version are you using? (use "convert | head -2" to find out). – Glenn Randers-Pehrson Mar 09 '16 at 17:29
  • I am using 6.8.9-9. I have tried to upgrade but with no luck. I was fallowing these instructions: http://askubuntu.com/questions/267746/how-can-i-install-the-latest-upstream-version-of-imagemagick-without-compiling – Juraj.Lorinc Mar 10 '16 at 18:04

2 Answers2

5

Use "-sample" instead of "-resize" to preserve the color set. This causes the resizing to be done by nearest-neighbor color selection rather than any kind of interpolation.

Otherwise, the colormap ends up with more than 256 colors and the png encoder can't preserve it, due to the 256-color limit on the size of a PNG PLTE chunk. I cannot guarantee that you'll like the appearance of the result, though.

Also, be sure you are using a recent version of ImageMagick. I'm not observing this problem with the current release (6.9.3-7). Your script works fine and produces clean -2x and -3x images.

Glenn Randers-Pehrson
  • 11,940
  • 3
  • 37
  • 61
  • Could OP maybe use `-resize` to get pleasing interpolation followed by `-colors 250` or `-colors 60` to allow your library to use palettised colormap? – Mark Setchell Mar 09 '16 at 00:06
0

There are several things to address here...

find vs glob

You say you want to process all files in a folder, then you use find which will search down into sub-directories as well. If you just want to process files in the current directory, you can let bash do the globbing directly for you. So, instead of

for f in $(find . -name "*.png"); do

you can just do:

shopt -s nullglob
for f in *.png; do

Performance

You run convert twice and load the original image twice, and that is not very efficient. You can run a single process that loads a single image and resizes to two different sizes and writes both to disk. So, instead of

for ...; do
   convert ...
   convert ...
done

you can write the following to start one convert, read the image once, clone it in memory and write it out, delete the spare copy in memory and then resize the original image and re-save that.

for ...; do
   convert "$f"                                                        \
      \( +clone -resize 66.67% -write "${f/%.png/-2x.png}" +delete \)  \
      -resize 33.33% "$f"
done 

Palette

It seems you actually only want to output palettised (indexed) images with "any" colormap rather than with a "specific" colormap. Glenn's answer is perfect if you want to retain a specific colormap. However, if any colormap is ok, you can use -colors to reduce the colours in the resulting image to a level where the PNG library can make the decision to create a palettised image. Glenn knows a lot more than me about that as he wrote it! However, I think if you reduce the colours to 250 (or so) you will probably get a 256 entry colormap and if you reduce the colours to around 60 or so, you will get a 64 entry colourmap. So, you would do:

shopt -s nullglob
for f in *.png; do
   sudo cp ... ...
   convert "$f"                                                        \
      \( +clone -resize 66.67% -colors 250 -write "${f/%.png/-2x.png}" +delete \)  \
      -resize 33.33% -colors 250 "$f"
done

You can try experimenting with other numbers of colours and see how that affects filesize - the number you need will depend on your images.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Performance is not i big issue (I am processing tens of images not thousands) but it is nice tweak. I want to process all the images in directory and sub directories so find works for me. The issue in your solution is, that I have in folder (and sub folders) a few different kinds of PNG (8-bit, 24-bit, indexed, not indexed...) so I need different parameters for different images. See my post edit for my code so far. It is not working as expected. There are large (square) areas of different color. – Juraj.Lorinc Mar 09 '16 at 10:58