Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginRAW.cpp  view on Meta::CPAN

	}

    int get_char() { 
		int c = 0;
		if(substream) return substream->get_char();
		if(!_io->read_proc(&c, 1, 1, _handle)) return -1;
		return c;
   }
	
	char* gets(char *buffer, int length) { 
		if (substream) return substream->gets(buffer, length);
		memset(buffer, 0, length);
		for(int i = 0; i < length; i++) {
			if(!_io->read_proc(&buffer[i], 1, 1, _handle))
				return NULL;
			if(buffer[i] == 0x0A)
				break;
		}
		return buffer;
	}

	int scanf_one(const char *fmt, void* val) {
		std::string buffer;
		char element = 0;
		bool bDone = false;
		if(substream) return substream->scanf_one(fmt,val);				
		do {
			if(_io->read_proc(&element, 1, 1, _handle) == 1) {
				switch(element) {
					case '0':
					case '\n':
					case ' ':
					case '\t':
						bDone = true;
						break;
					default:
						break;
				}
				buffer.append(&element, 1);
			} else {
				return 0;
			}
		} while(!bDone);

		return sscanf(buffer.c_str(), fmt, val);
	}

	int eof() { 
		if(substream) return substream->eof();
        return (_io->tell_proc(_handle) >= _eof);
    }

	void * make_jas_stream() {
		return NULL;
	}
};

// ----------------------------------------------------------

/**
Convert a processed raw data array to a FIBITMAP
@param RawProcessor LibRaw handle containing the processed raw image
@return Returns the converted dib if successfull, returns NULL otherwise
*/
static FIBITMAP * 
libraw_ConvertProcessedRawToDib(LibRaw *RawProcessor) {
	FIBITMAP *dib = NULL;
    int width, height, colors, bpp;

	try {
		int bgr = 0;	// pixel copy order: RGB if (bgr == 0) and BGR otherwise

		// get image info
		RawProcessor->get_mem_image_format(&width, &height, &colors, &bpp);

		// only 3-color images supported...
		if(colors != 3) {
			throw "LibRaw : only 3-color images supported";
		}

		if(bpp == 16) {
			// allocate output dib
			dib = FreeImage_AllocateT(FIT_RGB16, width, height);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}

		} else if(bpp == 8) {
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
			bgr = 1;	// only useful for FIT_BITMAP types
#endif

			// allocate output dib
			dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
		}

		// copy post-processed bitmap data into FIBITMAP buffer
		if(RawProcessor->copy_mem_image(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), bgr) != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to copy data into dib";
		}

		// flip vertically
		FreeImage_FlipVertical(dib);

		return dib;

	} catch(const char *text) {
		FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(s_format_id, text);
		return NULL;
	}
}


/**
Convert a processed raw image to a FIBITMAP
@param image Processed raw image
@return Returns the converted dib if successfull, returns NULL otherwise
@see libraw_LoadEmbeddedPreview
*/
static FIBITMAP * 
libraw_ConvertProcessedImageToDib(libraw_processed_image_t *image) {
	FIBITMAP *dib = NULL;

	try {
		unsigned width = image->width;
		unsigned height = image->height;
		unsigned bpp = image->bits;
		if(bpp == 16) {
			// allocate output dib
			dib = FreeImage_AllocateT(FIT_RGB16, width, height);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
			// write data
			WORD *raw_data = (WORD*)image->data;
			for(unsigned y = 0; y < height; y++) {
				FIRGB16 *output = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y);
				for(unsigned x = 0; x < width; x++) {
					output[x].red   = raw_data[0];
					output[x].green = raw_data[1];
					output[x].blue  = raw_data[2];
					raw_data += 3;
				}
			}
		} else if(bpp == 8) {
			// allocate output dib
			dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
			// write data
			BYTE *raw_data = (BYTE*)image->data;
			for(unsigned y = 0; y < height; y++) {
				RGBTRIPLE *output = (RGBTRIPLE*)FreeImage_GetScanLine(dib, height - 1 - y);
				for(unsigned x = 0; x < width; x++) {
					output[x].rgbtRed   = raw_data[0];
					output[x].rgbtGreen = raw_data[1];
					output[x].rgbtBlue  = raw_data[2];
					raw_data += 3;
				}
			}
		}
		
		return dib;

	} catch(const char *text) {
		FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(s_format_id, text);
		return NULL;
	}
}

/** 
Get the embedded JPEG preview image from RAW picture with included Exif Data. 
@param RawProcessor Libraw handle
@param flags JPEG load flags
@return Returns the loaded dib if successfull, returns NULL otherwise
*/
static FIBITMAP * 
libraw_LoadEmbeddedPreview(LibRaw *RawProcessor, int flags) {
	FIBITMAP *dib = NULL;
	libraw_processed_image_t *thumb_image = NULL;
	
	try {
		// unpack data
		if(RawProcessor->unpack_thumb() != LIBRAW_SUCCESS) {
			// run silently "LibRaw : failed to run unpack_thumb"
			return NULL;
		}

		// retrieve thumb image
		int error_code = 0;
		thumb_image = RawProcessor->dcraw_make_mem_thumb(&error_code);
		if(thumb_image) {
			if(thumb_image->type != LIBRAW_IMAGE_BITMAP) {
				// attach the binary data to a memory stream
				FIMEMORY *hmem = FreeImage_OpenMemory((BYTE*)thumb_image->data, (DWORD)thumb_image->data_size);
				// get the file type
				FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(hmem, 0);
				if(fif == FIF_JPEG) {
					// rotate according to Exif orientation
					flags |= JPEG_EXIFROTATE;
				}
				// load an image from the memory stream
				dib = FreeImage_LoadFromMemory(fif, hmem, flags);
				// close the stream
				FreeImage_CloseMemory(hmem);
			} else if((flags & FIF_LOAD_NOPIXELS) != FIF_LOAD_NOPIXELS) {
				// convert processed data to output dib
				dib = libraw_ConvertProcessedImageToDib(thumb_image);
			}
		} else {
			throw "LibRaw : failed to run dcraw_make_mem_thumb";
		}

		// clean-up and return
		RawProcessor->dcraw_clear_mem(thumb_image);

		return dib;

	} catch(const char *text) {
		// clean-up and return
		if(thumb_image) {
			RawProcessor->dcraw_clear_mem(thumb_image);
		}
		if(text != NULL) {
			FreeImage_OutputMessageProc(s_format_id, text);
		}
	}

	return NULL;
}
/**
Load raw data and convert to FIBITMAP
@param RawProcessor Libraw handle
@param bitspersample Output bitdepth (8- or 16-bit)
@return Returns the loaded dib if successfull, returns NULL otherwise
*/
static FIBITMAP * 
libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) {
	FIBITMAP *dib = NULL;

	try {
		// set decoding parameters
		// -----------------------
		
		// (-6) 16-bit or 8-bit
		RawProcessor->imgdata.params.output_bps = bitspersample;
		// (-g power toe_slope)
		if(bitspersample == 16) {
			// set -g 1 1 for linear curve
			RawProcessor->imgdata.params.gamm[0] = 1;
			RawProcessor->imgdata.params.gamm[1] = 1;
		} else if(bitspersample == 8) {
			// by default settings for rec. BT.709 are used: power 2.222 (i.e. gamm[0]=1/2.222) and slope 4.5
			RawProcessor->imgdata.params.gamm[0] = 1/2.222;
			RawProcessor->imgdata.params.gamm[1] = 4.5;
		}
		// (-W) Don't use automatic increase of brightness by histogram
		RawProcessor->imgdata.params.no_auto_bright = 1;
		// (-a) Use automatic white balance obtained after averaging over the entire image
		RawProcessor->imgdata.params.use_auto_wb = 1;
		// (-q 3) Adaptive homogeneity-directed demosaicing algorithm (AHD)
		RawProcessor->imgdata.params.user_qual = 3;

		// -----------------------

		// unpack data
		if(RawProcessor->unpack() != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to unpack data";
		}

		// process data (... most consuming task ...)
		if(RawProcessor->dcraw_process() != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to process data";
		}

		// retrieve processed image
		dib = libraw_ConvertProcessedRawToDib(RawProcessor);
	
		return dib;

	} catch(const char *text) {
		FreeImage_OutputMessageProc(s_format_id, text);
		return NULL;
	}
}

/**
Load the Bayer matrix (unprocessed raw data) as a FIT_UINT16 image. 
Note that some formats don't have a Bayer matrix (e.g. Foveon, Canon sRAW, demosaiced DNG files). 
@param RawProcessor Libraw handle
@return Returns the loaded dib if successfull, returns NULL otherwise
*/
static FIBITMAP * 
libraw_LoadUnprocessedData(LibRaw *RawProcessor) {
	FIBITMAP *dib = NULL;

	try {
		// unpack data
		if(RawProcessor->unpack() != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to unpack data";
		}

		// check for a supported Bayer format
		if(!(RawProcessor->imgdata.idata.filters || RawProcessor->imgdata.idata.colors == 1)) {
			throw "LibRaw : only Bayer-pattern RAW files are supported";
		}

		// allocate output dib
		const unsigned width = RawProcessor->imgdata.sizes.raw_width;
		const unsigned height = RawProcessor->imgdata.sizes.raw_height;
		const size_t line_size = width * sizeof(WORD);
		const WORD *src_bits = (WORD*)RawProcessor->imgdata.rawdata.raw_image;

		if(src_bits) {
			dib = FreeImage_AllocateT(FIT_UINT16, width, height);
		}
		if(!dib) {
			throw FI_MSG_ERROR_DIB_MEMORY;
		}

		// retrieve the raw image
		for(unsigned y = 0; y < height; y++) {
			WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
			memcpy(dst_bits, src_bits, line_size);
			src_bits += width;
		}

		// store metadata needed for post-processing
		{
			char value[512];

			const libraw_image_sizes_t *sizes = &RawProcessor->imgdata.sizes;

			// image output width & height
			{
				sprintf(value, "%d", sizes->iwidth);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Width", value);
				
				sprintf(value, "%d", sizes->iheight);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Output.Height", value);
			}

			// image output frame
			{
				const unsigned f_left = sizes->left_margin;
				const unsigned f_top = sizes->top_margin;
				const unsigned f_width = sizes->width;
				const unsigned f_height = sizes->height;
				
				sprintf(value, "%d", f_left);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Left", value);

				sprintf(value, "%d", f_top);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Top", value);

				sprintf(value, "%d", f_width);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Width", value);

				sprintf(value, "%d", f_height);
				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.Frame.Height", value);
			}

			// Bayer pattern
			// Mask describing the order of color pixels in the matrix. 
			// This field describe 16 pixels (8 rows with two pixels in each, from left to right and from top to bottom). 

			if(RawProcessor->imgdata.idata.filters) {
				// description of colors numbered from 0 to 3 (RGBG,RGBE,GMCY, or GBTG)
				char *cdesc = RawProcessor->imgdata.idata.cdesc;
				if(!cdesc[3]) {
					cdesc[3] = 'G';
				}
				char *pattern = &value[0];
				for(int i = 0; i < 16; i++) {
					pattern[i] = cdesc[ RawProcessor->fcol(i >> 1, i & 1) ];
				}
				pattern[16] = 0;

				FreeImage_SetMetadataKeyValue(FIMD_COMMENTS, dib, "Raw.BayerPattern", value);
			}
		}
	
		return dib;

	} catch(const char *text) {
		FreeImage_Unload(dib);
		FreeImage_OutputMessageProc(s_format_id, text);
		return NULL;

src/Source/FreeImage/PluginRAW.cpp  view on Meta::CPAN

	return FALSE;
}

static BOOL DLL_CALLCONV 
SupportsExportType(FREE_IMAGE_TYPE type) {
	return FALSE;
}

static BOOL DLL_CALLCONV
SupportsICCProfiles() {
	return TRUE;
}

static BOOL DLL_CALLCONV
SupportsNoPixels() {
	return TRUE;
}

// ----------------------------------------------------------

static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	FIBITMAP *dib = NULL;
	LibRaw *RawProcessor = NULL;

	BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

	try {
		// do not declare RawProcessor on the stack as it may be huge (300 KB)
		RawProcessor = new(std::nothrow) LibRaw;
		if(!RawProcessor) {
			throw FI_MSG_ERROR_MEMORY;
		}

		// wrap the input datastream
		LibRaw_freeimage_datastream datastream(io, handle);

		// set decoding parameters
		// the following parameters affect data reading
		// --------------------------------------------

		// (-s [0..N-1]) Select one raw image from input file
		RawProcessor->imgdata.params.shot_select = 0;
		// (-w) Use camera white balance, if possible (otherwise, fallback to auto_wb)
		RawProcessor->imgdata.params.use_camera_wb = 1;
		// (-M) Use any color matrix from the camera metadata. This option only affects Olympus, Leaf, and Phase One cameras.
		RawProcessor->imgdata.params.use_camera_matrix = 1;
		// (-h) outputs the image in 50% size
		RawProcessor->imgdata.params.half_size = ((flags & RAW_HALFSIZE) == RAW_HALFSIZE) ? 1 : 0;

		// open the datastream
		if(RawProcessor->open_datastream(&datastream) != LIBRAW_SUCCESS) {
			throw "LibRaw : failed to open input stream (unknown format)";
		}

		if(header_only) {
			// header only mode
			dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor->imgdata.sizes.width, RawProcessor->imgdata.sizes.height);
		}
		else if((flags & RAW_UNPROCESSED) == RAW_UNPROCESSED) {
			// load raw data without post-processing (i.e. as a Bayer matrix)
			dib = libraw_LoadUnprocessedData(RawProcessor);
		}
		else if((flags & RAW_PREVIEW) == RAW_PREVIEW) {
			// try to get the embedded JPEG
			dib = libraw_LoadEmbeddedPreview(RawProcessor, 0);
			if(!dib) {
				// no JPEG preview: try to load as 8-bit/sample (i.e. RGB 24-bit)
				dib = libraw_LoadRawData(RawProcessor, 8);
			}
		} 
		else if((flags & RAW_DISPLAY) == RAW_DISPLAY) {
			// load raw data as 8-bit/sample (i.e. RGB 24-bit)
			dib = libraw_LoadRawData(RawProcessor, 8);
		} 
		else {
			// default: load raw data as linear 16-bit/sample (i.e. RGB 48-bit)
			dib = libraw_LoadRawData(RawProcessor, 16);
		}

		// save ICC profile if present
		if(dib && (NULL != RawProcessor->imgdata.color.profile)) {
			FreeImage_CreateICCProfile(dib, RawProcessor->imgdata.color.profile, RawProcessor->imgdata.color.profile_length);
		}

		// try to get JPEG embedded Exif metadata
		if(dib && !((flags & RAW_PREVIEW) == RAW_PREVIEW)) {
			FIBITMAP *metadata_dib = libraw_LoadEmbeddedPreview(RawProcessor, FIF_LOAD_NOPIXELS);
			if(metadata_dib) {
				FreeImage_CloneMetadata(dib, metadata_dib);
				FreeImage_Unload(metadata_dib);
			}
		}

		// clean-up internal memory allocations
		RawProcessor->recycle();
		delete RawProcessor;

		return dib;

	} catch(const char *text) {
		if(RawProcessor) {
			RawProcessor->recycle();
			delete RawProcessor;
		}
		if(dib) {
			FreeImage_Unload(dib);
		}
		FreeImage_OutputMessageProc(s_format_id, text);
	}

	return NULL;
}

// ==========================================================
//   Init
// ==========================================================

void DLL_CALLCONV
InitRAW(Plugin *plugin, int format_id) {
	s_format_id = format_id;



( run in 0.452 second using v1.01-cache-2.11-cpan-ceb78f64989 )