简体   繁体   中英

Magick++ C++ Input 16-bit Greyscale PNG

I've got a series of PNG files that I know is in a 16-bit greyscale format. I haven't had a problem loading this up with Magick++ and getting access to the data in 8-bit format (this was done, primarily, because all the code was there and no change was necessary).

magick_image->write(0, 0, grey->GetWidth(), grey->GetHeight(), "R", Magick::CharPixel, grey->GetBeginData());

Please note that grey is in our own container for images, but the memory layout is just one block of pre-allocated memory.

I've now been told that we need to get access to the full 16-bit range, and I'm not too sure how to do this. I presume I wouldn't use Magick::CharPixel, but the others described in the documentation don't specify what bit size they actually are.


So, I need to be able to do the following things:

  • Determine whether it is a 16-bit image in the first place
  • Read out of the Magick::Image class into a block of memory that would map to place into a block of memory for a u_int16_t

Can anyone help with this?

There's a few ways to do this, but without seeing the definitions of magick_image & grey , this answer is based on a few assumptions.

To work with bare-bone grey , I would argue it could be defined as...

struct MaybeGray {
    std::vector<u_int16_t> blob;
    size_t width;
    size_t height;
    MaybeGray(size_t w, size_t h) : blob(w * h) { width = w; height = h; };
    size_t getWidth() { return width; };
    size_t getHeight() { return height; };
    void * getBeginData() { return blob.data(); } // C11? Is this allowed?
};

Next, I'll create a 2x2 canvas image to satisfy magick_image .

Magick::Image magick_image;
Magick::Geometry size(2, 2);
magick_image.size(size);
magick_image.read("XC:blue");
// Apply gray scale (Magick::Image.quantize may be better.)
magick_image.type(Magick::GrayscaleType);

Determine whether it is a 16-bit image in the first place

Magick::Image.depth can be used to identify, and set depth value.

const size_t DEPTH = 16;
if ( magick_image.depth() != DEPTH ) {
    magick_image.depth(DEPTH);
}

Read out of the Magick::Image class into a block of memory that would map to place into a block of memory for a u_int16_t

What you're doing with Magick::Image.write is correct. However Magick::CharPixel would be for 8-bit, 256 colors, depth. For 16-bit, use Magick::ShortPixel .

struct MaybeGray gray(2, 2);
magick_image.write(0, 0,
                   gray.getWidth(),
                   gray.getHeight(),
                   "R",
                   Magick::ShortPixel,
                   gray.getBeginData());

How to test

A image canvas of XC:red should fill the blob with 0xFFFF , and XC:black with 0x0000 . Use ImageMagick's convert & identify utilities to create the expected results.

# Create identical canvas
convert -size 2x2 xc:blue -colorspace gray -depth 16 blue.tiff
# Dump info
identify -verbose blue.tiff

  Image: blue.tiff
  Format: TIFF (Tagged Image File Format)
  Class: DirectClass
  Geometry: 2x2+0+0
  Units: PixelsPerInch
  Type: Grayscale
  Base type: Grayscale
  Endianess: LSB
  Colorspace: Gray
  Depth: 16/14-bit
  Channel depth:
    gray: 14-bit
  Channel statistics:
    Gray:
      min: 4732 (0.0722057)
      max: 4732 (0.0722057)
      mean: 4732 (0.0722057)
      standard deviation: 0 (0)
      kurtosis: 0
      skewness: 0
  Colors: 1
  Histogram:
         4: ( 4732, 4732, 4732) #127C127C127C gray(7.22057%)
  # ... rest omitted

And the verbose info confirms that I have 16-bit gray image, and the histogram informs me that MaybeGrey.blob would be filled with 4 0x127C .

16位灰度PNG

Which it is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM