Resized PNG (4 bit) with transparency gives black images

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
theylmdl
Posts: 5
Joined: 2011-02-20T14:11:20-07:00
Authentication code: 8675308
Location: Frankfurt, Germany

Resized PNG (4 bit) with transparency gives black images

Post by theylmdl »

Hi!

May I introduce myself and the task: I run a private website about model railroading and railway prototypes with lots of 4 bit images in proper quality. There's a resize function for these images (for visitors with sight issues). Example: English introduction (currently, the script is set to "scale").

Since most modern browsers use the (censored) bicubic interpolation when raster graphics are output at a size that differs from the original even if it's an integer magnifying factor (2x), I use IM (Perl layer in between) on a local Server (IM 6.4.1) and at the ISP. There's a caching algorithm, too.

Here's the essential part of the code:

Code: Select all

            my ($inimage, $xlimage);
            $inimage = new Image::Magick;
            $inimage->Read($root.$imgfile);
            $xlimage = $inimage->Clone();
            $xlimage->Resize(width => $nNewWd, height => $nNewHt, blur => 0);
            $xlimage->Write($root.$xlfile);
            $imgfile = $xlfile;
            undef($inimage);
            undef($xlimage);
$root.$imgfile is the source file, $nNewWd / $nNewHt are the resize size results (integer, typically factor 2, 3 or 4). $root.$xlfile is the file name of the image to write. $imgfile is what is streamed back to the browser (from cache). $root is the file system root on both servers.

This works - and worked - perfectly fine, but PNG images with 4 bit (16 colours) and a transparency colour turned out to be fully black after the resize. If I turn "blur => 0" off, the transparency is maintained, and also scale works fine, but of course, the 16M colours image are too huge, and the images w/o blur => 0 look more than ugly.

Here is one of the images that turn out to cause problems:
Image

Could anybody please help a more or less IM noob? And yes, I spent hours searching at Google and used the forum search, too.

Thanks in advance!
Best regards, Thomas
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Resized PNG (4 bit) with transparency gives black images

Post by fmw42 »

There has been quite a lot of development on PNG image format over the last number of releases. see http://www.imagemagick.org/script/changelog.php

You don't say what version of IM you are using. So you might try to upgrade to the latest version and try again. I get pretty good results by using in command line mode, though transparency has gone from 0 to 1 out of 65535:


convert vzs-20-004.png -resize 200% -colors 5 vzs-20-004_c5.png

There is likely a better way to do this that my attempt above. Perhaps one of the IM developers or another user can suggest a better way.
theylmdl
Posts: 5
Joined: 2011-02-20T14:11:20-07:00
Authentication code: 8675308
Location: Frankfurt, Germany

Re: Resized PNG (4 bit) with transparency gives black images

Post by theylmdl »

Hi!

Thank you for your answer.
You don't say what version of IM you are using.
I did ;-) :
on a local Server (IM 6.4.1)
In the meantime I update to a combination of ActiveState Perl 5.8.12 (Build 1204) and ImageMagick 6.6.7-8 Q8 Windows DLL. It works perfectly, but gives exactly the same error.

Your proposal, fmw42, is a little bit unpractical, because I'd have to examine the used colors count first (but maybe I'll give it a try tonight).

I guess the issue with "resize" might be a bug that should be fixed.

Best Regards, Thomas
Last edited by theylmdl on 2011-02-24T16:39:42-07:00, edited 1 time in total.
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Re: Resized PNG (4 bit) with transparency gives black images

Post by Drarakel »

I don't know Perl. But your code probably does that:

Code: Select all

convert vzs-20-004.png -define filter:blur=0 -resize 200% test.png
And yes, enlargements like that always give a black square.

But I don't think that the behaviour with your code is a bug.(?)
The default resize in ImageMagick uses the 'Mitchell' filter (for enlargements). This adds a small amount of blurriness of course. You can control the level of blurriness a bit with the 'blur' setting, yes - but you really shouldn't change it too much. (Extremely lowering the blur setting changes the filter/the weighting curve almost into a Point filter. That doesn't make much sense - with very low blur settings that still work, you will have a more difficult command - but will get the same result as with 'scale' in the first place. And apparently, too low settings or a setting of 0 can't work anymore.)
See also here for some background regarding the resize filters or the blur setting:
http://www.imagemagick.org/Usage/resize/

Perhaps someone else can give a detailed explanation of why the resize with a blur setting of 0 can't work anymore. But it shouldn't matter that much.. Just go with 'scale' (or 'sample'). Or try some other resize filters - but with sane blur settings. :)
theylmdl wrote:currently, the script is set to "scale"
So, why do you want to change that? If I understood you right, you need some simple, magnified images - without any blurring - right?
Regarding the colors: Resizing without any interpolation ('scale') shouldn't add new colors. If you still end up with too large files, then it could be the 'fault' of the PNG encoder, but not of the resizing. You could add a few options for the PNG output.. But with a current ImageMagick version, I think you should do fine with the default options. As Fred (fmw42) said, the PNG output has gone through a lot of changes/improvements in the last versions. Just try it again with your new IM version.

And if you want to save a few more bytes, you could use something like that (as I don't use Perl, I can't give you the Perl equivalent, sorry):

Code: Select all

convert vzs-20-004.png -define png:include-chunk=none,tRNS -scale 200% -quality 90 test.png
(The define option strips the metadata - which you won't need. That option only works in the newer IM versions, I think.)
theylmdl
Posts: 5
Joined: 2011-02-20T14:11:20-07:00
Authentication code: 8675308
Location: Frankfurt, Germany

Re: Resized PNG (4 bit) with transparency gives black images

Post by theylmdl »

Hello!

Thanks for your answer, Drakarel. Maybe my statements where not clear enough, I'm sorry about that.

All I want is an image that maintains the same palette (4 or 8 bit) and transparent color when resized to the double or triple original size. There's no need to blur, interpolate pixels or kind of that. Will say, since we are talking about pixel raster drawings, any blur or interpolation can only diminuate the image quality with an integer scaling factor.

The Perl statement is an equivalent to -resize width×height.

scale, as mentioned, works fine, but produces 24 bit images. Since my caching algorithm stores these images as files, they require heavily more download data than 4 or 8 bit images (quite obvious). This may be a matter due to loading time. The same technique - please note this point - works perfectly including transparency using *.gif instead of *.png. But GIF tends to have some unnecessary overhead that PNG might save. Any why should I provide GIF images in 2011 if even MSIE 6 is able to interpret single color PNG transparency correctly...?

The difference seems to be ridiculous (scale and GIF), but when we are talking about thousands of images and requests, it isn't anymore. I already noticed the difference in Google Webmaster Tools since I switched from resize to scale.
And yes, enlargements like that always give a black square.
No, they don't. They do it only if there's one of 16 colors defined to be transparent (see my first example "English Introduction": 4 bit, no transparency, resized with blur=0 and a perfect result with both scale and resize).
See also here for some background regarding the resize filters or the blur setting
I have read this reference before posting - several times. But it does neither explain why it works with 8 bit images nor why it works with *.gif nor why it works when no transparent color is defined in the image.

Sorry in advance if I am wrong (this may always happen), but in my opinion this is a bug, still. It would be more or less acceptable to write the transparent color pixels as opaque, but fully black image data (and not only their display) are faulty.

Regards, Thomas
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Resized PNG (4 bit) with transparency gives black images

Post by magick »

The problem appears to be a bug in the resize algorithm and we're working on it. Hopefully we'll have a patch for the problem this week.
theylmdl
Posts: 5
Joined: 2011-02-20T14:11:20-07:00
Authentication code: 8675308
Location: Frankfurt, Germany

Re: Resized PNG (4 bit) with transparency gives black images

Post by theylmdl »

Hi!
The problem appears to be a bug in the resize algorithm and we're working on it. Hopefully we'll have a patch for the problem this week.
Thank you so very much, magick!

This is exactly what I hoped to read ;-) . Don't hurry - fix carefully :-D .

If there's anything I could do to help, just let me know.

Best regards by a professional lead tester,
Thomas
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Re: Resized PNG (4 bit) with transparency gives black images

Post by Drarakel »

theylmdl wrote:They do it only if there's one of 16 colors defined to be transparent (see my first example "English Introduction": 4 bit, no transparency, resized with blur=0 and a perfect result with both scale and resize).
Interesting. So, it seems that it works with some colormapped images without transparency.
But that doesn't mean that images with transparency are the only ones that result in a black image. (Try for example the truecolor rose image: "convert rose: -define filter:blur=0.07 -resize 400% rose4x.png". Gives a.. sort of 'interlaced' output. :D And lower blur settings again result in a black image.)

I still wouldn't recommend a blur setting of 0 (and I don't think that this is recommended in the documentation somewhere). But if the shown behaviour leads to an error that can be fixed: Fair enough!
In the meantime, if you want to use the resize with blur 0, there seems to be a workaround - with 'colors' (you don't need to know the color count of the image for that, just insert a high enough number). At least at the commandline:

Code: Select all

convert vzs-20-004.png -colors 4294967296 -define filter:blur=0 -resize 200% test.png
So, the color reduction does nothing, but after that it works. (And the output of that is identical to that of "-scale".)
theylmdl wrote:scale, as mentioned, works fine, but produces 24 bit images.
Did you try that command?
Drarakel wrote:

Code: Select all

convert vzs-20-004.png -define png:include-chunk=none,tRNS -scale 200% -quality 90 test.png
The commands with "-scale" give me an indexed image - with a 4bit palette. Using ImageMagick v6.6.7-9 Q16. Of course that are only the results at the commandline. But if the Perl equivalent doesn't optimize the PNG output like that (especially since your code with Image->Resize seems to 'optimize' the PNG output), perhaps that hints to another small problem there?

By the way: Personally, I would use a PNG optimizing tool like OptiPNG (see also here). (Of course that doesn't mean that the error with IM shouldn't be fixed.) That should reduce space/traffic as much as possible.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Resized PNG (4 bit) with transparency gives black images

Post by magick »

Anthony says:
The image is suposed to be black.

The Support of the image is effected by the Blur factor (which shoudl default to 1.0). Support should not go to zero, but it should not be prevented either!!!

Basically when support goes below 1/2, 'filtered' samples can miss all pixels in an image from the 'floating point location'

I would expect to see a black (undefined) pixel when you get no match!

Expert options are dangerous, that is why they are expert options.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Resized PNG (4 bit) with transparency gives black images

Post by anthony »

theylmdl wrote:All I want is an image that maintains the same palette (4 or 8 bit) and transparent color when resized to the double or triple original size. There's no need to blur, interpolate pixels or kind of that. Will say, since we are talking about pixel raster drawings, any blur or interpolation can only diminuate the image quality with an integer scaling factor.
As pointed out 'scale' or 'sample' (same thing for enlargements. will produce larger square (rectangular) areas of color.
I gather you want to smooth those squares and shapes, but without generating new colors.

Their are algorithms for generating such enlargements, and I have them on my ToDo list, but they are so far down on my list that I am unlikely to get around to them. You are of course welcome to implement them yourself (or others).

The algorithms, are generally known as scale or scaleX type algorithms.

Closely related to scaling with preserved palette, is a image rotation with palette preservation.

This is a reference to my personal "hotlist" extracted from my web browser bookmarks, for such algorithms. When I bookmark a new algorithm it will automatically appear here within 24 hours...
http://www.ict.griffith.edu.au/~anthony ... %20Scaling
The Perl statement is an equivalent to -resize width×height.
To ge equivelent the expert "filter:blur" define should be 1.0 This is a scaling factor. A smaller number causes the filter function and the support function to become proportionally smaller.

It is typically used to make gaussian like functions less or more blurry. Though Guassian filter itself has a special 'filter:sigma' recently added so you can scale that function separate to the filters support setting. This setting does not work well for functions with 'negative weightings' such as Windowed Sinc functions (such as Lancoz), and setting it to zero is completely non-nonsensical.

In any case a 'blurred' or 'scaled' weighted filter is still a weighted filter and you will still get a color mixing in the result, or as you saw a 'mathematical zero' or 'black' when no pixel falls in the filters support range.

NOTE: a 'Point' filter (optimized as the -sample operator) is not strictly a 'weighted filter', but a nearest neighbour function. For a convolution (a unscaled resize), or in enlargments it is equivalent to a 'box' filter (implemented as a optimized -scale operation), but it does not act in that same way for shinking where a weighted box filter will start ot average pixels together. Only the Point (sample) filter will preserve the image palette.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
theylmdl
Posts: 5
Joined: 2011-02-20T14:11:20-07:00
Authentication code: 8675308
Location: Frankfurt, Germany

Re: Resized PNG (4 bit) with transparency gives black images

Post by theylmdl »

Hello!

Thank you all very much for your patience and interest.

Unfortunately, the Perl Image::Magick Module (as an interface to ImageMagick) does not have a real equivalent to the "convert" command line command, as it seems.

Using ActiveState Perl 5.12 build 1204 and ImageMagick 6.6.7-8 Q8 Windows DLL under Windows XP SP3, I found a method that does what I want with all of the affected images I tested:

Code: Select all

$xlimage->Resize(width=>$nNewWd, height=>$nNewHt, filter=>'point', blur=>0);
The trick is to explicitely declare 'point' as filter method, just as explained. This works with 4 Bit PNGs with a transparent color, too, and there's no blur at all (and no black images anymore).

There are two minor drawbacks, both of them (almost) negligable.
  • Images that have only gray color values will always convert to 256 colors gray scaled bitmaps, even if only 2 through 16 colors are required and the source image has a matching palette.
  • The color values will be maintained (unchanged), but the order differs, and the transparent color will always be black an the first color palette entry (black may be duplicated, one index for the transparency, one for really opaque black pixels). The source's transparent color will not be maintained. Unused colors are removed.
The first of the "issues" is not ideal, since of course an 8bpp image requires more time to load than a 4bpp image.

The other problem affects only myself. At my provider's machine running my servers (I'm shared ;-) ), there's only ImageMagick 6.2.8.0-4 running (both with CentOS 5.x, one with Perl 5.8.8 and the other with Perl 5.10). And there the output is fine, but the produced images have 24bpp - which results to exactly the same as using the PerlMagick scale function.

I also gave $xlimage->Magnify and $xlimage->Resample a chance, but both gave ugly blurry results (although transparency was maintained).

@anthony:
I looked at some of the algorithms you linked to - nice things indeed. It's many years now since I programmed my first ANSI C image processing libraries for Win16/Win32 :-) . Unfortunately, I'm sooo short of time, so I don't see the chance for an own solution.

Best regards, Thomas
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Resized PNG (4 bit) with transparency gives black images

Post by anthony »

theylmdl wrote:Unfortunately, the Perl Image::Magick Module (as an interface to ImageMagick) does not have a real equivalent to the "convert" command line command, as it seems.

Using ActiveState Perl 5.12 build 1204 and ImageMagick 6.6.7-8 Q8 Windows DLL under Windows XP SP3, I found a method that does what I want with all of the affected images I tested:

Code: Select all

$xlimage->Resize(width=>$nNewWd, height=>$nNewHt, filter=>'point', blur=>0);
That is not the equivalent Use blur=>1.0, or leave it out completely.

Alternative instead of specifying filter->'point' Use the Sample() function instead. That is equivalent to using -sample which is a optimized point filtered resize function. Essentually it gets a 'nearest neighbour' interpolation for each pixel in destination, without going though the whole 'weighted filter' process.

BOTH Magnify() and Resample() are wrappers around the Resize() function. Basically shorthand functions.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply