Create Image instance from in-memory monochrome data

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
komuta

Create Image instance from in-memory monochrome data

Post by komuta »

Hi,

Is it possible to create an Image instance from in-memory data when it is stored as monochrome 1 pixel-per-bit array ?
I can't find any working configuration in the primitive Image(const size_t width_, const size_t height_, std::string map_, const StorageType type_, const void *pixels_). However, the library is capable of loading such image formats, therefore I suppose it should be possible from in-memory raw buffer.

Thanks in advance.
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

Hi, I have this problem also. I found this thread through a search.

The only thing I can think of is converting to Windows DIB and using that but it seems like it won't work.
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

I found an ...extremely inefficient... solution!
However, I am sure there is a better solution, so please let me know!!
EDIT: Thinking about it, maybe I could manually setPixel() for every pixel in ImageMagick? Does anyone know how to do this efficiently?

Code: Select all

void myImage::copyToMagick(Magick::Image &magickImage) const
{
	myImage temp = *this;

	//we need to resize to 1 byte per pixel..
	temp._pixelBuffer = (BYTE*)realloc((void*)temp._pixelBuffer, getLength()*getHeight());
	for (unsigned int y = 0; y < getHeight(); y++)
	{
		for (unsigned int x = 0; x < getLength(); x++)
		{
			//'curPix' is 0 if black. 1 if white. BYTE is actually like one bit. I used it instead of bool
			BYTE curPix = this->_getPixelDirect(x, y);
			curPix = (curPix == 0) ? 255 : 0;
			*(temp._pixelBuffer + y*getLength() + x) = curPix;
		}
	}
	//Write in black color space
	magickImage.read(temp.getLength(), temp.getHeight(), "K", MagickLib::CharPixel, temp._pixelBuffer);
}
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

Okay, I updated the code to be more efficient (directly set each pixel) but am getting weird errors (I think it has to do with MagickLib::BilevelType because MagickLib::TrueColorType causes no error, but I assume BilevelType is more efficient):

Code: Select all

.
.
.
First-chance exception at 0x76ec75ff in Scrap 2.exe: 0xC0000005: Access violation reading location 0xdddddde1.
First-chance exception at 0x76e79f17 in Scrap 2.exe: 0xC0000005: Access violation reading location 0xdddddddd.
First-chance exception at 0x76ec75ff in Scrap 2.exe: 0xC0000005: Access violation reading location 0xdddddde1.
The program '[1116] Scrap 2.exe: Native' has exited with code 702 (0x2be).
Please explain why or correct my code: (why BilevelType does not work but TrueColorType does?)

Code: Select all

void myImage::copyToMagick(Magick::Image &magickImage) const
{
	//Create a blank image with the same dimensions as this image
	magickImage = Magick::Image(Magick::Geometry(getLength(), getHeight()), Magick::Color(255, 255, 200));

	//Prepare to modify the image
	magickImage.modifyImage();

	//Set the image type to bilevel (black-and-white, 1 bit per pixel). IF WE CHANGE TO 'TrueColorType' NO ERROR!
	magickImage.type(MagickLib::BilevelType);

	//Get the pixel cache
	MagickLib::PixelPacket* magickPixels = magickImage.getPixels(0, 0, getLength(), getHeight());

	//Copy each pixel individually to 'magickImage'
	for (unsigned int y = 0; y < getHeight(); y++)
	{
		for (unsigned int x = 0; x < getLength(); x++)
		{
			//The current pixel in the original image
			BYTE curPix = this->_getPixelDirect(x, y);
			//Convert it to magick++ representation (black is 0. white is 255)
			curPix = (curPix == BLACK_PIXEL) ? 0 : 255;

			//The current pixel in 'magickImage'
			MagickLib::PixelPacket* curMagickPix = magickPixels + (y*getLength() + x);

			//Set the color of this pixel to 'curPix'
			curMagickPix->blue = curMagickPix->green = curMagickPix->red = curPix;
			curMagickPix->opacity = 0;
		}
	}

	//Save the changes to the magick image
	magickImage.syncPixels();
}
komuta

Re: Create Image instance from in-memory monochrome data

Post by komuta »

You say that BilevelType image is "black-and-white, 1 bit per pixel". But in when modifying, you're accessing pixels as byte, not as bit.
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

komuta wrote:You say that BilevelType image is "black-and-white, 1 bit per pixel". But in when modifying, you're accessing pixels as byte, not as bit.
Yeah, but ImageMagick apparently stores every pixel in 4 bytes no matter the type (for portability between a trillion different image formats).
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Create Image instance from in-memory monochrome data

Post by anthony »

anotherprogrammer123 wrote:
komuta wrote:You say that BilevelType image is "black-and-white, 1 bit per pixel". But in when modifying, you're accessing pixels as byte, not as bit.
Yeah, but ImageMagick apparently stores every pixel in 4 bytes no matter the type (for portability between a trillion different image formats).
That is true though it is 3 or 4 numbers not bytes. The 4th depends on if you have a transparency channel. The actual number of bytes depends on your IM quality setting. Q16 will use 2-byte integers per number. Q8 on byte per number, A HDRI version of IM uses floating point 'doubles' for the number.

The various MagickCore methods extract the image values into one of two pixel data types for processing. The best idea is to go though the image row by row.

This is all documented in the 'Architecture' page on the IM website.
http://www.imagemagick.org/script/architecture.php
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

Thanks for the information about the storage and the link, but why does my code above not work with BilevelType?
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Create Image instance from in-memory monochrome data

Post by anthony »

bilevel is just binary. Pure black and white, no colors saved in the file.

See Im Examples. Common File Formats, TIFF
http://www.imagemagick.org/Usage/formats/#tiff
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
anotherprogrammer123
Posts: 36
Joined: 2010-02-21T18:02:40-07:00
Authentication code: 8675308

Re: Create Image instance from in-memory monochrome data

Post by anotherprogrammer123 »

anthony wrote:bilevel is just binary. Pure black and white, no colors saved in the file.
I tried this, but all pixels become white!

Code: Select all

 
	//Set the image type to bilevel (black-and-white, 1 bit per pixel)
	magickImage.type(MagickLib::BilevelType);
	//The current pixel in 'magickImage'
         MagickLib::PixelPacket* curMagickPix = magickPixels + (y*getLength() + x);

         //Set the color of this pixel to 'curPix'
         curMagickPix->blue = curMagickPix->green = curMagickPix->red = curPix;
         memset(curMagickPix, curPix, sizeof(curMagickPix));
Post Reply