bugGNU Octave - Bugs: bug #41584, .bmp / .png display error for...

 
 

bug #41584: .bmp / .png display error for saturated RGB image.

Submitter:  None
Submitted:  Thu 13 Feb 2014 10:36:44 PM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Inaccurate Result
Status:  Confirmed Assigned to:  None
Originator Name:  Greg Jeffery Originator Email:  -email is unavailable-
Open/Closed:  * Open Release:  * dev
Operating System:  * Any Fixed Release:  None
Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Fri 08 Dec 2017 11:37:37 PM UTC, comment #12: 
Dan Sebald <sebald>
Fri 08 Dec 2017 05:10:10 AM UTC, comment #11: 

I've looked at this one a bit, experimenting with various parts of the GraphicsMagick library.  As Carnë postulated, there may be a bug in the GraphicsMagick or underlying library code.  I'm leaning that way, and I will explain why a bit later.

However, the main issue is whether this approach should be used:


  octave_idx_type depth = img.depth ();
std::cerr << "DEPTH=" << img.depth() << "\n";
  if (depth == 8
      && img.channelDepth (Magick::RedChannel)     == 1
      && img.channelDepth (Magick::GreenChannel)   == 1
      && img.channelDepth (Magick::BlueChannel)    == 1
      && img.channelDepth (Magick::CyanChannel)    == 1
      && img.channelDepth (Magick::MagentaChannel) == 1
      && img.channelDepth (Magick::YellowChannel)  == 1
      && img.channelDepth (Magick::BlackChannel)   == 1
      && img.channelDepth (Magick::OpacityChannel) == 1
      && img.channelDepth (Magick::GrayChannel)    == 1)
    depth = 1;


My thought is to not do this because the ramification is something like described in bug report https://savannah.gnu.org/bugs/?49140 .  As described in earlier posts, GraphicsMagick can compress it's internal representation if the extremes are 0.0 and 1.0, e.g., 0x00 and 0xFF in 8-bit land thus suggesting the channel depth is 1-bit when the original file was not 1-bit per channel.

It's one of two bad-outcomes, but I lean toward treating 8-bit data as 1-bit (the above code) is a worse outcome than treating 1-bit data as 8-bit--unless there is some bad scaling effect I'm unaware of such that 0.0 and 1.0 aren't mapped to 0 and 255.  The thing is, it's really easy to convert from (0,255) back to (0,1) after the fact with logical(img) at Octave's command line--not as easy to go the other direction.  Furthermore, if down the line there are bug fixes in the GM Magick++ library, the issue will disappear on its own.

It could be a bug in the way Octave is accessing the Magick++ library (e.g., overlooked initialization, incomplete processing), but I've tried enough things to start thinking it isn't Octave's problem.

Let's get some footing by observing Octave/Magick++ (with GraphicsMagick as the library code) is /writing/ an image in 1-bit channel depth:


octave:1> img(:,:,1) = logical(ones (128));
octave:2> img(:,:,2) = zeros (128, "logical");
octave:3> img(:,:,3) = zeros (128, "logical");
octave:4> imwrite (img, "testbinary.bmp");
octave:5> exit
sebald@ ~/octave/bug_41584 $ gm identify testbinary.bmptestbinary.bmp BMP 128x128+0+0 PseudoClass 2c 8-bit 2.1Ki 0.000u 0:01
sebald@ ~/octave/bug_41584 $ identify testbinary.bmp
testbinary.bmp BMP3 128x128 128x128+0+0 1-bit sRGB 2c 2.11KB 0.000u 0:00.000


Notice in the above that I've used two different utilities to "identify" the image that was created.  The first "gm identify" is the GraphicsMagick utility.  The second "identify" is the ImageMagick utility.  Right away we see that GraphicsMagick can't properly identify a 1-bit image file (although it can create one) while ImageMagick can.

I've experimented with a few code variations, most similar to the "readImages()" of the STL.h Magick++ interface.  Yet, I just get a depth of 8, rather than 1, when reading testbinary.bmp.  I even made use of the function


  IdentifyImageCommand(image_info, 2, fnarg, &metadata, &exception_info);


which will effectively run "gm identify" from within Octave:


octave:1> img = imread ("testbinary.bmp");
/home/sebald/matlab/bug_41584/testbinary.bmp BMP 128x128+0+0 PseudoClass 2c 8-bit 2.1Ki 0.000u 0:01


which is the same result as gotten from the command line above.

The list of GM bug fixes appears to be here:

http://www.graphicsmagick.org/NEWS.html

I don't see much mention of 1-bit depth fixes.  I have version


GraphicsMagick 1.3.23 2015-11-07 Q16 http://www.GraphicsMagick.org/


I suppose someone should get the latest version of GM and compile it.  Then test if the testbinary.bmp file is identified as 1-bit.  If not, then file a bug report at the GM SourceForge development site.  Maybe it wouldn't be that difficult to fix either...could be that no one ever noticed because 1-bit images aren't used too much.

FWIW, my version of ImageMagick utilities is:


Version: ImageMagick 6.8.9-9 Q16 x86_64 2017-07-31 http://www.imagemagick.org


Dan Sebald <sebald>
Tue 14 Jul 2015 10:35:40 AM UTC, comment #10: 

Vallery said on Comment #9:

> if all channels are saturated or zero then imread couldn't be blamed for returning damaging data because of the logical matrix.


Of course it can.  It is part of the file information if the data is 8 bit, 16 bit, signed or unsigned, boolean, floating point, or something else.  The actual pixel values of the image are irrelevant.  Unfortunately, this information is not available (at least not in a reliable way) to us when using GraphicsMagick (but would be if we used the format specific libraries).

Carnë Draug <carandraug>
Group Member
Mon 13 Jul 2015 11:58:27 PM UTC, comment #9: 

Carnё, thank you.

BTW, if all channels are saturated or zero then imread couldn't be blamed for returning damaging data because of the logical matrix. In my case imread was simply destroying a huge part of the data. 

So, imshow still probably needs to be patched to show the logical matrix right...

Valery <vak>
Mon 13 Jul 2015 12:05:50 PM UTC, comment #8: 

Thank you. I confirm that your patch fixes for your image. However it does not fix the original bug report.

You fix works when only the red channels was saturated. The original bug report is when all channels are either saturated or zero. In those cases, we are still reading as binary images.

Interestingly, the issue you have would not occur if your image was in bmp so this really is a GM coder specific issue.

Anyway, I pushed your fix and a test which will part of the next minor release (Octave 4.2)

  http://hg.savannah.gnu.org/hgweb/octave/rev/a7770c66cb3d

but will keep the bug report open since the original bug is not fixed yet.

Carnë Draug <carandraug>
Group Member
Mon 13 Jul 2015 07:27:37 AM UTC, comment #7: 

Carnё, please, find the attached image (works fine with patched version)

Valery <vak>
Fri 10 Jul 2015 04:37:37 PM UTC, comment #6: 

@Valery

Can you please submit a test image that displays the problem. I just tested with the artifical image generated on comment #1, and your fix does not fix it.

Carnë Draug <carandraug>
Group Member
Fri 10 Jul 2015 11:41:23 AM UTC, comment #5: 

Hi,

the problem shows up to me when using the following images:

PNG 1250x1250 1250x1250+0+0 8-bit sRGB 250KB 0.000u 0:00.000

in which:

[...]
Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 1-bit
    green: 8-bit
    blue: 8-bit
[...]

So the "unlucky" red channel causes get_depth currently to override the correct default result value "8" with the incorrect "1", what then leads to the false matrix type "logical".

As quick-n-dirty fix I added these two lines with conditions for the green and blue channels:

libinterp/dldfcn/__magick_read__.cc

static octave_idx_type
get_depth (Magick::Image& img)
{
  octave_idx_type depth = img.depth ();
  if (depth == 8
      && img.channelDepth (Magick::RedChannel)     == 1
      && img.channelDepth (Magick::GreenChannel)   == 1 // <<--- added
      && img.channelDepth (Magick::BlueChannel)    == 1 // <<--- added
      && img.channelDepth (Magick::CyanChannel)    == 1
      && img.channelDepth (Magick::OpacityChannel) == 1
      && img.channelDepth (Magick::GrayChannel)    == 1)
    depth = 1;

  return depth;
}

and am getting uint8 for the image matrix in result.
Now I am bound to this my fixed Octave version and would be cool if this or other patch could be incorporated in next public releases.

P.S. Disclaimer: I don't have an answer though, why Cyan, Opacity and Gray channels all return depth of 1 for such images .


Valery <vak>
Sat 15 Feb 2014 08:04:33 PM UTC, comment #4: 

I can confirm that I also get a an image of class logical rather than of uint8.  My GraphicsMagick is built with a quantum-depth of 8 so I think this is a general problem.

Rik <rik5>
Group administrator
Fri 14 Feb 2014 03:21:01 AM UTC, comment #3: 

I messed up the syntax on the last message sos here it goes again:

Mike, I can replicate the problem on my system.

imread() returns a 128x128x3 logical matrix on my system which imshow() fails
to display.

I don't know if the quantum depth used with GraphicsMagick (GM) could make a
difference (I have it built with quantum-depth 32).

The gm application identifies the image correctly has 8bit


$ gm identify test.bmp
test.bmp BMP 128x128+0+0 DirectClass 8-bit 48.1K 0.000u 0:01


I believe the problem may be with get_depth() in _magick_read_.cc which
tries to workaround some wrong results of GM (there's a big block of comments
there trying to explain the issue).

The issue is that GM is not in fault here. What they return as depth,
channelDepth, classType, etc is not meant to be interpreted as the way the
image was represented in the file, but the way GM is keeping it in memory. If
an image has few colors, GM may decide to interpret it as indexed, if all
channels are equal, it may decide to keep it grayscale, etc. They don't have
methods that will reliable tell us what was in the file.

Carnë Draug <carandraug>
Group Member
Thu 13 Feb 2014 11:39:33 PM UTC, comment #2: 

Mike, I can replicate the problem on my system.

imread() returns a 128x128x3 logical matrix on my system which imshow() fails to display.

I don't know if the quantum depth used with GraphicsMagick (GM) could make a difference (I have it built with quantum-depth 32).

The gm application identifies the image correctly has 8bit


$ gm identify test.bmp
test.bmp BMP 128x128+0+0 DirectClass 8-bit 48.1K 0.000u 0:01
+verbatim+

I believe the problem may be with get_depth() in __magick_read__.cc which tries to workaround some wrong results of GM (there's a big block of comments there trying to explain the issue).

The issue is that GM is not in fault here. What they return as depth, channelDepth, classType, etc is not meant to be interpreted as the way the image was represented in the file, but the way GM is keeping it in memory. If an image has few colors, GM may decide to interpret it as indexed, if all channels are equal, it may decide to keep it grayscale, etc. They don't have methods that will reliable tell us what was in the file.

Carnë Draug <carandraug>
Group Member
Thu 13 Feb 2014 11:23:26 PM UTC, comment #1: 

Can you provide a script or example of how to demonstrate the error you are describing?

Here's what I did:


img(:,:,1) = uint8 (255) * ones (128);
img(:,:,2) = zeros (128, "uint8");
img(:,:,3) = zeros (128, "uint8");
imshow (img)
imwrite (img, "test.bmp");
clear
img = imread ("test.bmp");
imshow (img)


No errors or problems that I can see.

Mike Miller <mtmiller>
Group Member
Thu 13 Feb 2014 10:36:44 PM UTC, original submission:  

iminfo/imread for any fully saturated RGB image will return logical type instead of uint8 if the pixel values are saturated. Same problem in 3.6.4, probably 3.4.3 as well. To test this, create a solid red image, with all pixels = 0xff, green=blue=0. Save as a .bmp or a .png. Try to display it; Octave throws errors. It doesn't matter if .bmp, .png.

If the same image is saved as .jpg, though, Octave is happy, and it displays properly.

Drop the value to 0xfe, image reports and displays properly.

Anonymous

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #34429:  example.png added by vak (11KiB - image/png)

 

Carbon-Copy List
  • -email is unavailable- added by pot
  • -email is unavailable- added by sebald (Posted a comment)
  • -email is unavailable- added by vak (Posted a comment)
  • -email is unavailable- added by mtmiller (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 10 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2017-12-08 pot Carbon-Copy- Added pot
    2016-09-20 mtmiller Dependencies- bugs #49140 is dependent
    2016-06-04 mtmiller Dependencies- bugs #48129 is dependent
    2015-11-06 carandraug Dependencies- bugs #46382 is dependent
    2015-07-13 carandraug Release3.8.0 dev
        Operating SystemMicrosoft Windows Any
    2015-07-13 vak Attached File- Added example.png, #34429
    2015-07-10 rik5 Carbon-CopyRemoved 72865 -
    2014-02-15 rik5 StatusNeed Info Confirmed
    2014-02-13 mtmiller StatusNone Need Info

    Back to the top

    Powered by Savane 3.13-4448.
    Corresponding source code