ImageToFile - what is it supposed to do exactly?

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Posts: 21
Joined: 2014-04-24T15:51:58-07:00
Authentication code: 6789

ImageToFile - what is it supposed to do exactly?

Post by Minok »

I've been working on this problem where I"m handed some CCITT Group 4 compressed image data with the other metadata needed to define an image.

I've managed to get the blob into ImageMagick to hopefully process things and convert the image to other formats internally (not to have ImageMagick write to files), BUT as intermediate step and to validate that I've got a valid ImageMagick image object, I wanted to write out the image I had stored in ImageMagick.

How that is done isn't obvious. (to me). From the docs

BlobToImage() implements direct to memory image formats. It returns the blob as an image.

This I have used to get my TIFF blob into an ImageMagic image

Now that same C API page also lists the function:

ImageToFile() writes an image to a file. It returns MagickFalse if an error occurs otherwise MagickTrue.

Which, based on the terminology would take the image I now have and write it out to a file I specify.
But what does it do? No, it does not.

Taking the TIFF blob that ImageMagic converted via BlobToImage just fine, and trying to write it to file via ImageToFile( myImageMagickImage, "magick.tiff", myImageMagickException) causes a run-time fault - ImageMagic stops at an assert:
assert(image->blob->type != UndefinedStream);

Indeed while the ImageMagick image is defined:

Code: Select all

-		image	0x0096cd68 {storage_class=DirectClass colorspace=GRAYColorspace compression=Group4Compression ...}	_Image *
		storage_class	DirectClass	ClassType
		colorspace	GRAYColorspace	ColorspaceType
		compression	Group4Compression	CompressionType
		quality	0	unsigned int
		orientation	TopLeftOrientation	OrientationType
		taint	MagickFalse	MagickBooleanType
		matte	MagickFalse	MagickBooleanType
		columns	240	unsigned int
		rows	210	unsigned int
		depth	1	unsigned int
		colors	0	unsigned int
+		colormap	0x00000000 {blue=??? green=??? red=??? ...}	_PixelPacket *
+		background_color	{blue=65535 green=65535 red=65535 ...}	_PixelPacket
+		border_color	{blue=57311 green=57311 red=57311 ...}	_PixelPacket
+		matte_color	{blue=48573 green=48573 red=48573 ...}	_PixelPacket
		gamma	0.45454545454545453	double
+		chromaticity	{red_primary={...} green_primary={...} blue_primary={...} ...}	_ChromaticityInfo
		rendering_intent	UndefinedIntent	RenderingIntent
		profiles	0x00000000	void *
		units	PixelsPerInchResolution	ResolutionType
+		montage	0x00000000 <Bad Ptr>	char *
+		directory	0x00000000 <Bad Ptr>	char *
+		geometry	0x00000000 <Bad Ptr>	char *
		offset	0	long
		x_resolution	100.00000000000000	double
		y_resolution	100.00000000000000	double
+		page	{width=240 height=210 x=0 ...}	_RectangleInfo
+		extract_info	{width=0 height=0 x=0 ...}	_RectangleInfo
+		tile_info	{width=0 height=0 x=0 ...}	_RectangleInfo
		bias	0.00000000000000000	double
		blur	1.0000000000000000	double
		fuzz	0.00000000000000000	double
		filter	UndefinedFilter	FilterTypes
		interlace	NoInterlace	InterlaceType
		endian	MSBEndian	EndianType
		gravity	UndefinedGravity	GravityType
		compose	OverCompositeOp	CompositeOperator
		dispose	UnrecognizedDispose	DisposeType
+		clip_mask	0x00000000 {storage_class=??? colorspace=??? compression=??? ...}	_Image *
		scene	0	unsigned int
		delay	0	unsigned int
		ticks_per_second	100	long
		iterations	0	unsigned int
		total_colors	0	unsigned int
		start_loop	0	long
+		error	{mean_error_per_pixel=0.00000000000000000 normalized_mean_error=0.00000000000000000 normalized_maximum_error=0.00000000000000000 }	_ErrorInfo
+		timer	{user={...} elapsed={...} state=RunningTimerState ...}	_TimerInfo
		progress_monitor	0x00000000	MagickBooleanType (const char *, const __int64, const const unsigned __int64, const void *)*
		client_data	0x00000000	void *
		cache	0x00970030	void *
		attributes	0x00000000	void *
+		ascii85	0x00000000 {offset=??? line_break=??? buffer=0x00000008 <Bad Ptr> }	_Ascii85Info *
+		blob	0x00972510 {length=0 extent=1074 quantum=65541 ...}	_BlobInfo *
+		filename	0x0096cf30 ""	char [4096]
+		magick_filename	0x0096df30 ""	char [4096]
+		magick	0x0096ef30 "TIFF"	char [4096]
		magick_columns	240	unsigned int
		magick_rows	210	unsigned int
+		exception	{severity=UndefinedException error_number=0 reason=0x00000000 <Bad Ptr> ...}	_ExceptionInfo
		debug	MagickFalse	MagickBooleanType
		reference_count	1	volatile long
+		semaphore	0x009726c0 {mutex={...} id=20036 reference_count=0 ...}	SemaphoreInfo *
+		color_profile	{name=0x00000000 <Bad Ptr> length=0 info=0x00000000 <Bad Ptr> ...}	_ProfileInfo
+		iptc_profile	{name=0x00000000 <Bad Ptr> length=0 info=0x00000000 <Bad Ptr> ...}	_ProfileInfo
+		generic_profile	0x00000000 {name=??? length=??? info=??? ...}	_ProfileInfo *
		generic_profiles	0	unsigned int
		signature	2880220587	unsigned int
+		previous	0x00000000 {storage_class=??? colorspace=??? compression=??? ...}	_Image *
+		list	0x00000000 {storage_class=??? colorspace=??? compression=??? ...}	_Image *
+		next	0x00000000 {storage_class=??? colorspace=??? compression=??? ...}	_Image *
		interpolate	UndefinedInterpolatePixel	InterpolatePixelMethod
		black_point_compensation	MagickFalse	MagickBooleanType
+		transparent_color	{blue=0 green=0 red=0 ...}	_PixelPacket
+		mask	0x00000000 {storage_class=??? colorspace=??? compression=??? ...}	_Image *
+		tile_offset	{width=0 height=0 x=0 ...}	_RectangleInfo
		properties	0x00972ea0	void *
		artifacts	0x00000000	void *
		type	BilevelType	ImageType
		dither	MagickTrue	MagickBooleanType
		extent	1074	unsigned __int64
		ping	MagickFalse	MagickBooleanType
		channels	0	unsigned int
		timestamp	1398985982	__int64
		intensity	UndefinedPixelIntensityMethod	PixelIntensityMethod
		duration	0	unsigned int

the embedded blob information did indeed have an an undefined stream type:

Code: Select all

-		blob	0x00972510 {length=0 extent=1074 quantum=65541 ...}	_BlobInfo *
		length	0	unsigned int
		extent	1074	unsigned int
		quantum	65541	unsigned int
		mapped	MagickFalse	MagickBooleanType
		eof	MagickFalse	MagickBooleanType
		offset	0	__int64
		size	1074	unsigned __int64
		exempt	MagickFalse	MagickBooleanType
		synchronize	MagickFalse	MagickBooleanType
		status	MagickFalse	MagickBooleanType
		temporary	MagickFalse	MagickBooleanType
		[b]type	UndefinedStream	StreamType[/b]
+		file_info	{file=0x00000000 gzfile=0x00000000 bzfile=0x00000000 }	FileInfo
+		properties	{st_dev=0 st_ino=0 st_mode=0 ...}	_stat64
		stream	0x00000000	unsigned int (const _Image *, const void *, const unsigned int)*
+		data	0x00000000 <Bad Ptr>	unsigned char *
		debug	MagickFalse	MagickBooleanType
+		semaphore	0x00972600 {mutex={...} id=20036 reference_count=0 ...}	SemaphoreInfo *
		reference_count	1	long
		signature	2880220587	unsigned int
Um, ok, so what is up with that?
What is ImageToFile supposed to do? The core API's documentation is rather simple and doesn't indicate there would be any issue with this not performing as expected.

I did find another post on this website forum system saying to not use ImageToFile, but rather use WriteImage(imgMagickInfo, imgMagickImage);

Well, that does work as expected.

So now my question remains: what is the difference between the two, and note that ImageToFile is rather misleading in that section of the docs.
ImageToFile() writes an image to a file. It returns MagickFalse if an error occurs otherwise MagickTrue. ... WriteImage
WriteImage() writes an image or an image sequence to a file or file handle. If writing to a file is on disk, the name is defined by the filename member of the image structure. WriteImage() returns MagickFalse is there is a memory shortage or if the image cannot be written. Check the exception member of image to determine the cause for any failure.

Both indicate they write the image to a file.

My logical issue with what ever ImageToFile does is that it does NOT behave like ImageToBlob, except rather than to a blog it outputs to a file. And that is really confusing (beyond not knowing what ImageToFile is supposed to be used for).

For example, the following succesfully converts my TIFF blob, that was brought in as a TIFF image, into a PNG blob:
strcpy(imgMagickImage->filename, "internal.png" );
strcpy(imgMagickImage->magick, "png" );
unsigned char* pngBlob = ImageToBlob( imgMagickInfo, imgMagickImage, &pngSize, imgMagickException); // create the PNG blob
But if you try to do the same with ImageToFIle, you get our old friend, the assert fail.