Load Images from memory (libharu) from Magick++ images - c++

I am working on some pdf generation software in c++ based on libharu and I would like to be able to first manipulate images using Magick++ and then load them from memory using libharu function:
HPDF_LoadRawImageFromMem()
Which according to the documentation essentially load images from some void *buffer.
My goal is to be able to get this void* data out of a Magick::Image instance and load this image into my haru pdf based on this data.
I have tried writing to a void*or to a Magick::Blob but the only achievement I have had so far was some black rectangle instead of the image I am expecting.
Does anyone have any experience in converting Raw image data from one library into another one ?
The reason I am trying to do this from memory is because so far I am writing Magick::Image instances into a file and then reading from this file to load then in haru, which is a huge performance hit in the context of my Application.

I'm a little late to answer I guess, but here's a real-life answer.
I successfully added an itk::Image to my pdf using LibHaru so it should work about the same for you. First, you need to know if the library you use is row major or column major. LibHaru (and all the libraries I know) works in row major, so your library should too, or you will need to "transpose" your data.
// Black and white image (8 bits per pixel)
itk::Image<unsigned char, 2>::Pointer image = ...;
const unsigned char *imageData = image->GetBufferPointer();
const HPDF_Image image = HPDF_LoadRawImageFromMem(m_Document,
imageData, width, height, HPDF_CS_DEVICE_GRAY, 8);
// Or color image (24 bits per pixel, 8 bits per color component)
itk::Image<RGBPixel, 2>::Pointer image = ...;
const RGBPixel *imageData = image->GetBufferPointer();
const HPDF_Image image = HPDF_LoadRawImageFromMem(m_Document,
reinterpret_cast<const unsigned char *>(imageData),
width, height, HPDF_CS_DEVICE_RGB, 8);
// Usual LibHaru code. EndText, Position, Draw, StartText, etc.
// This code should not be dependant on the type
InsertImage(image);
I think the only complicated part is the reinterpret_cast. The black and white image don't need one because it's already defined as byte. For example, if you have this image
102 255 255
99 200 0
255 0 100
imageData == {102, 255, 255, 99, 200, 0, 255, 0, 100};
However, if you have this color image
( 0, 0, 255) (0, 255, 255) ( 42, 255, 242)
(200, 200, 255) (0, 199, 199) (190, 190, 190)
imageData == {0, 0, 255, 0, 255, 255, 42, 255, 242, 200, 200, 255, ... }
which LibHaru will inderstand because you tell him to use HPDF_CS_DEVICE_RGB, which means that it will group the data in (R, G, B).
Of course, using ImageMagick, you need to find how to access the first pixel. It's probably a method like data(), begin(), pointer(), etc.

Unfortunately I neither worked with ImageMagic nor libharu, however I have some experience with image processing and since nobody answered yet, maybe I can be of some help.
The problem is probably that there is a plethora of raw image formats and I'm quite sure that both libraries do not have the same understanding of these. What makes things worse is that the raw image interpretation of libharu is virtually not documented. However the conclusions that libharu handles raw data quite straightforward can be drawn from the parameters of: "HPDF_LoadRawImageFromMem".
Width and Height are pretty much self-explanatory, with the only question of the used (probably pixels). More interesting is: "bits_per_component". This parameter probably describes how many bits are used to define one pixel (common values are 8: indexed from a palette of 256 values, 16: indexed from a palette of 65535 values, 24: one byte for red, green, and blue respectivly [RGB], 32: as 24 but with alpha channel or 8 bits for cyan, magenta, yellow, and black [CMYK], 36: as 32 but with 9 bit per value for easier transpostion...). A problem is the lousy documentation of the type: HPDF_ColorSpace, since it probably describes how color values of with: "bits_per_component" are to be interpreted.
A totally different approach seems to be implemented by ImageMagic. An image object seems to have always an image format (JPEG, PNG, GIF), therefore an image object probably never has a "straightforward" memory representation but is encoded.
My recommendation would be to switch the ImagaMagic image to the TIFF format, since it condones compression and therefore has a similar approach to the assumed raw interpretation by libharu.
Hope this helped at least a bit...
Cheers
Mark.

It is never late to answer.
I have used a PNG blob as intermediate step:
Image image;
image.read("file.jpg");
Blob blob;
image.write(blob, "PNG");
HPDF_Image pdfImg = HPDF_LoadPngImageFromMem(doc, (const HPDF_BYTE*)blob.data(), blob.length());
HPDF_Page_DrawImage(doc, pdfImg, 0, 0, image.columns(), image.rows());
PDF document and page creation omitted for brevity.

Related

PPM wrong color display

I get weird results when displaying a PPM:
pixeldisplay
(this is actually an upscaled PNG)
And here's what the file looks like:
textdisplay
The dimensions are fine (10 rows, 8 columns), just the colors are wrong (or am I wrong?).
As it says in the 3rd line of the file, I want to use a value from 0 to 255 per channel. Using an usual rgb color space like (255, 255, 255) for white, (0, 0, 0) for black, (255, 0, 0) for red and so on. But those colors in the image are apparently not the same as in the file.
Already at the first look, the image seems way to dark.
Do I misunderstand the format? Is the file not interpretated this way?
This document: http://netpbm.sourceforge.net/doc/ppm.html describes the PPM image format.
When the "magic" value P6 is found at the beginning of the file, the color of the pixels is stored as binary data. Quoting the previously mentioned document (emphasis mine):
[...] A raster of Height rows, in order from top to bottom. Each row consists of Width pixels, in order from left to right. Each pixel is a triplet of red, green, and blue samples, in that order. Each sample is represented in pure binary by either 1 or 2 bytes. If the Maxval is less than 256, it is 1 byte. Otherwise, it is 2 bytes. The most significant byte is first.
The file showed by the asker seems to contain their decimal textual representation instead.
So, the string "\n224 93 229..." (yes, I suspect the windows endline sequence "\r\n") is interpreted as (assuming that the file was saved in ASCII format) {10, 50, 50}, {50, 32, 32}, {57, 51, 32}, ....
Note the blackish pixel in the middle, which probably correspond to the end of the first line, it may be a {13, 10, 32} ("\r\n ").
If you change the magic value to P3, it should be interpreted correctly.

CImg saving images changes values?

So I am using the CImg library to have some fun with images...
The issue is that when I open a file to change its RGB values and save, the modified image does not retain the changed values OR the original value.
CImg<unsigned char> image_out( img.c_str() );
image_out(0,0,0) = 253; //reset new rgb values
image_out(0,0,1) = 248;
image_out(0,0,2) = 251;
image_out.save( "out.jpeg" );
Then when I open the image again, I get this as the new RGB values...
R: 249 G: 249 B: 249
I don't really understand why the values aren't being saved to the ones I set...
edit:
Sorry also mentioning I KNOW the initial value of the pixel (respect to RGB) is 255, 255, 255.
Don't use jpeg, this is a destructive image format that doesn't preserve the values, due to the Dct compression.
Use .png or. Bmp instead.

image threasholding in opencv (thereshold to 255)

I have this code which is work well:
cv::threshold( image, out, 20, 255,cv::THRESH_TOZERO );
In this code, all pixels which are less than 20, became zero. Now I want to write a code that all pixels which are more than say 230, became 255.
Is there any way to do this?
I know that I can iterate over all pixels, but I am looking for a simpler solutions.
There is no parameter for CV::threshold that does this, but you could simply use THRESH_BINARY and then get the maximum of your original image and the thresholded image.

Converting opencv image to gdi bitmap doesn't work depends on image size

I have this code that converts an opencv image to a bitmap:
void processimage(MAT imageData)
{
Gdiplus::Bitmap bitmap(imageData.cols,imageData.rows,stride, PixelFormat24bppRGB,imageData.data);
// do some work with bitmap
}
It is working well when the size of image is 2748 X 3664. But I am tring to process an image wth size 1374 X 1832, it doesn't work.
The error is invalid parameter(2).
I checked and can confirm that:
in 2748 *3664:
cols=2748
rows=3664
stride= 8244
image is continues.
in 1374 X 1832
cols=1374
rows=1832
stride= 4122
image is continues.
So everything seems correct to me, but it generate error.
What is the problem and how can I fix it?
Edit
Based on answer which explained why I can not create bitmap. I finally implemented it in this way:
Mat newImage;
cvtColor(imageData, newImage, CV_BGR2BGRA);
Gdiplus::Bitmap bitmap(newImage.cols,newImage.rows,newImage.step1(), PixelFormat32bppRGB,newImage.data);
So effectively, I convert input image to a 4 byte per pixel and then use the convert it to bitmap.
All credits to Roger Rowland for his answer.
I think the problem is that a BMP format must have a stride that is a multiple of 4.
Your larger image has a stride of 8244, which is valid (8244/4 = 2061) but your smaller image has a stride of 4122, which is not (4122/4 = 1030.5).
As it says on MSDN for the stride parameter (with my emphasis):
Integer that specifies the byte offset between the beginning of one
scan line and the next. This is usually (but not necessarily) the
number of bytes in the pixel format (for example, 2 for 16 bits per
pixel) multiplied by the width of the bitmap. The value passed to this
parameter must be a multiple of four.
Assuming your stride is correct, I think you're only option is to copy it row by row. So, something like:
Great a Gdiplus::Bitmap of the required size and format
Use LockBits to get the bitmap pixel data.
Copy the OpenCV image one row at a time.
Call UnlockBits to release the bitmap data.
You can use my class CGdiPlus that implements all you need to convert from cv::Mat to Gdiplus::Bitmap and vice versa:
OpenCV / Tesseract: How to replace libpng, libtiff etc with GDI+ Bitmap (Load into cv::Mat via GDI+)

Getting RGB from WIC image c++

I am using WIC to load in an image and then I want to be able to get the RGB values of each pixel. I have got as far as using getDataPointer() to create a byte buffer (which I cast to a COLORREF array) but after this things get strange.
I have a 10x10 24bit png that I'm testing with. If I look at the size value getDataPointer() gives me it says it's 300, which makes sense because 10 * 10 * 3 (for 3 bytes per pixel) = 300. If I do getStride() it gives me 30, which also makes sense.
So I create a loop to go through the COLORREF with an iterator and the condition is i < size/3 because I know there are only 100 pixels in the array. I then use the macros GetRValue(), GetGValue() and GetBValue() to get the rgb values out.
This is when things go weird - My small image is just a test image with solid red, green, blue and black pixels in, but my RGB values come out (255, 0, 0), (0, 255, 0), (27, 255, 36), (0, 0, 0) etc. it seems that some values don't come out properly and are corrupted somehow. Also, the last 20/30 pixels of the image are either loads of crazy colors or all black making me think there some sort of corruption.
I also tested it with a larger actual photograph and this comes out all grayscale and repeating the same pattern, making me think it's a stride issue but I don't understand how because when I call getPixelFormat() WIC says it's 24bppBGR or 24bppRGB depending on the images.
Does anyone have any idea what I am doing wrong? Shouldn't I be using COLORREF and the macros or something like that?
Thanks for your time.
EDIT
Hmm I've still got a problem here. I tried with another 24bit PNG that PixelFormat() was reporting as 24bppBGR but it seems like the stride is off or something because it is drawing as skewed (obligatory nyan cat test):
EDIT 2
Okay so now it seems I have some that work and some that don't. Some reporting themselves as 24bpp BGR work while others look like the image above and if I calculate the stride it gives me compared to what it should be they are different and also the size of the buffer is different too. I also have some 32bpp BGR images and some of those work and others don't. Am I missing something here? What could make up the extra bytes in the buffer?
Here is an example image:
24bppBGR JPEG:
width = 126
height = 79
buffer size = 30018
stride = 380
If I calculate this:
buffer size should be: width * height * 3 = 126 * 79 * 3 = 29862
difference between calculation and actual buffer size: 30018 - 29862 = 156 bytes
stride size should be: width * 3 = 378
difference between calculation and actual buffer size: 380 - 378 = 2 bytes
I was thinking that we had 2 extra bytes per line but 79 * 2 is 158 not 156 hmm.
If I do these calculations for the images that have worked so far I find no difference in the calculations and the values the code gives me...
Am I understanding what is happening here wrong? Should these calculations now work as I have thought?
Thanks again
You shouldn't be using COLORREF and related macros. COLORREF is a 4-byte type, and you have 3-byte pixels. Accessing the data as an array of COLORREF values won't work. Instead, you should access it as an array of bytes with each pixel located at ((x + y * width) * 3). The order of individual channels is indicated by the format name. So if it's 24bppBGR you'd do data[(x + y * width) * 3] to get the blue channel, data[(x + y * width) * 3 + 1] for green, and data[(x + y * width) * 3 + 2] for red.
If you really want an array of pixels, you can make a structure with 3 BYTE fields, but since the meaning of those fields depends on the pixel format, that may not be useful.
In fact, you can't assume an arbitrary image will load as a 24-bit format at all. The number of formats you could get is larger than you could reasonably be expected to support.
Instead, you should use WICConvertBitmapSource to convert the data to a format you can work with. If you prefer to work with a COLORREF array and related macros, use GUID_WICPixelFormat32bppBGR.