Alien-FreeImage

 view release on metacpan or  search on metacpan

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

		(type == FIT_RGBA16) ||
		(type == FIT_FLOAT)  ||
		(type == FIT_RGBF)   ||
		(type == FIT_RGBAF)
	);
}

static BOOL DLL_CALLCONV
SupportsICCProfiles() {
	return TRUE;
}

static BOOL DLL_CALLCONV
SupportsNoPixels() {
	return TRUE;
}

// ==========================================================
//	Open & Close
// ==========================================================

static void * DLL_CALLCONV
Open(FreeImageIO *io, fi_handle handle, BOOL read) {
	WMPStream *pStream = NULL;	// stream interface
	if(io && handle) {
		// allocate the FreeImageIO stream wrapper
		FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)malloc(sizeof(FreeImageJXRIO));
		if(jxr_io) {
			jxr_io->io = io;
			jxr_io->handle = handle;
			// create a JXR stream wrapper
			if(_jxr_io_Create(&pStream, jxr_io) != WMP_errSuccess) {
				free(jxr_io);
				return NULL;
			}
		}
	}
	return pStream;
}

static void DLL_CALLCONV
Close(FreeImageIO *io, fi_handle handle, void *data) {
	WMPStream *pStream = (WMPStream*)data;
	if(pStream) {
		// free the FreeImageIO stream wrapper
		FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)pStream->state.pvObj;
		free(jxr_io);
		// free the JXR stream wrapper
		pStream->fMem = TRUE;
		_jxr_io_Close(&pStream);
	}
}

// ==========================================================
//	Load
// ==========================================================

/**
Set decoder parameters
@param pDecoder Decoder handle
@param flags FreeImage load flags
*/
static void 
SetDecoderParameters(PKImageDecode *pDecoder, int flags) {
	// load image & alpha for formats with alpha
	pDecoder->WMP.wmiSCP.uAlphaMode = 2;
	// more options to come ...
}

/**
Copy or convert & copy decoded pixels into the dib
@param pDecoder Decoder handle
@param out_guid_format Target guid format
@param dib Output dib
@param width Image width
@param height Image height
@return Returns 0 if successful, returns ERR otherwise
*/
static ERR
CopyPixels(PKImageDecode *pDecoder, PKPixelFormatGUID out_guid_format, FIBITMAP *dib, int width, int height) {
	PKFormatConverter *pConverter = NULL;	// pixel format converter
	ERR error_code = 0;	// error code as returned by the interface
	BYTE *pb = NULL;	// local buffer used for pixel format conversion
	
	// image dimensions
	const PKRect rect = {0, 0, width, height};

	try {
		// get input file pixel format ...
		PKPixelFormatGUID in_guid_format;
		error_code = pDecoder->GetPixelFormat(pDecoder, &in_guid_format);
		JXR_CHECK(error_code);
		
		// is a format conversion needed ?

		if(IsEqualGUID(out_guid_format, in_guid_format)) {
			// no conversion, load bytes "as is" ...

			// get a pointer to dst pixel data
			BYTE *dib_bits = FreeImage_GetBits(dib);

			// get dst pitch (count of BYTE for stride)
			const unsigned cbStride = FreeImage_GetPitch(dib);			

			// decode and copy bits to dst array
			error_code = pDecoder->Copy(pDecoder, &rect, dib_bits, cbStride);
			JXR_CHECK(error_code);		
		}
		else {
			// we need to use the conversion API ...
			
			// allocate the pixel format converter
			error_code = PKCodecFactory_CreateFormatConverter(&pConverter);
			JXR_CHECK(error_code);
			
			// set the conversion function
			error_code = pConverter->Initialize(pConverter, pDecoder, NULL, out_guid_format);
			JXR_CHECK(error_code);
			
			// get the maximum stride
			unsigned cbStride = 0;
			{
				PKPixelInfo pPIFrom;
				PKPixelInfo pPITo;

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

				unsigned cbStrideTo = ((pPITo.cbitUnit + 7) >> 3) * width;
				cbStride = MAX(cbStrideFrom, cbStrideTo);
			}

			// allocate a local decoder / encoder buffer
			error_code = PKAllocAligned((void **) &pb, cbStride * height, 128);
			JXR_CHECK(error_code);

			// copy / convert pixels
			error_code = pConverter->Copy(pConverter, &rect, pb, cbStride);
			JXR_CHECK(error_code);

			// now copy pixels into the dib
			const size_t line_size = FreeImage_GetLine(dib);
			for(int y = 0; y < height; y++) {
				BYTE *src_bits = (BYTE*)(pb + y * cbStride);
				BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, y);
				memcpy(dst_bits, src_bits, line_size);
			}
			
			// free the local buffer
			PKFreeAligned((void **) &pb);

			// free the pixel format converter
			PKFormatConverter_Release(&pConverter);
		}

		// FreeImage DIB are upside-down relative to usual graphic conventions
		FreeImage_FlipVertical(dib);

		// post-processing ...
		// -------------------

		// swap RGB as needed

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
		if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppRGB) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppRGB)) {
			SwapRedBlue32(dib);
		}
#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
		if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppBGR) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppBGR)) {
			SwapRedBlue32(dib);
		}
#endif
		
		return WMP_errSuccess;

	} catch(...) {
		// free the local buffer
		PKFreeAligned((void **) &pb);
		// free the pixel format converter
		PKFormatConverter_Release(&pConverter);

		return error_code;
	}
}

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

static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
	PKImageDecode *pDecoder = NULL;	// decoder interface
	ERR error_code = 0;				// error code as returned by the interface
	PKPixelFormatGUID guid_format;	// loaded pixel format (== input file pixel format if no conversion needed)
	
	FREE_IMAGE_TYPE image_type = FIT_UNKNOWN;	// input image type
	unsigned bpp = 0;							// input image bit depth
	FIBITMAP *dib = NULL;
	
	// get the I/O stream wrapper
	WMPStream *pDecodeStream = (WMPStream*)data;

	if(!handle || !pDecodeStream) {
		return NULL;
	}

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

	try {
		int width, height;	// image dimensions (in pixels)

		// create a JXR decoder interface and initialize function pointers with *_WMP functions
		error_code = PKImageDecode_Create_WMP(&pDecoder);
		JXR_CHECK(error_code);

		// attach the stream to the decoder ...
		// ... then read the image container and the metadata
		error_code = pDecoder->Initialize(pDecoder, pDecodeStream);
		JXR_CHECK(error_code);

		// set decoder parameters
		SetDecoderParameters(pDecoder, flags);

		// get dst image format specifications
		unsigned red_mask = 0, green_mask = 0, blue_mask = 0;
		error_code = GetInputPixelFormat(pDecoder, &guid_format, &image_type, &bpp, &red_mask, &green_mask, &blue_mask);
		JXR_CHECK(error_code);

		// get image dimensions
		pDecoder->GetSize(pDecoder, &width, &height);

		// allocate dst image
		{			
			dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, bpp, red_mask, green_mask, blue_mask);
			if(!dib) {
				throw FI_MSG_ERROR_DIB_MEMORY;
			}
			if(FreeImage_GetBPP(dib) == 1) {
				// BD_1 - build a FIC_MINISBLACK palette
				RGBQUAD *pal = FreeImage_GetPalette(dib);
				pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
				pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
			}
		}

		// get image resolution
		{
			float resX, resY;	// image resolution (in dots per inch)
			// convert from English units, i.e. dots per inch to universal units, i.e. dots per meter
			pDecoder->GetResolution(pDecoder, &resX, &resY);
			FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX / 0.0254F + 0.5F));
			FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY / 0.0254F + 0.5F));
		}

		// get metadata & ICC profile
		error_code = ReadMetadata(pDecoder, dib);
		JXR_CHECK(error_code);

		if(header_only) {
			// header only mode ...
			
			// free the decoder
			pDecoder->Release(&pDecoder);
			assert(pDecoder == NULL);

			return dib;
		}
		
		// copy pixels into the dib, perform pixel conversion if needed
		error_code = CopyPixels(pDecoder, guid_format, dib, width, height);
		JXR_CHECK(error_code);

		// free the decoder
		pDecoder->Release(&pDecoder);
		assert(pDecoder == NULL);

		return dib;

	} catch (const char *message) {
		// unload the dib
		FreeImage_Unload(dib);
		// free the decoder

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

@param wmiSCP Encoder parameters
@param pixelInfo Image specifications
@param fltImageQuality Image output quality in [0..1), 1 means lossless
*/
static void 
SetCompression(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, float fltImageQuality) {
    if(fltImageQuality < 1.0F) {
        // overlap
		if(fltImageQuality >= 0.5F) {
			wmiSCP->olOverlap = OL_ONE;
		} else {
			wmiSCP->olOverlap = OL_TWO;
		}
		// chroma sub-sampling
		if(fltImageQuality >= 0.5F || pixelInfo->uBitsPerSample > 8) {
			wmiSCP->cfColorFormat = YUV_444;
		} else {
			wmiSCP->cfColorFormat = YUV_420;
		}

	    // bit depth
		if(pixelInfo->bdBitDepth == BD_1) {
			wmiSCP->uiDefaultQPIndex = (U8)(8 - 5.0F * fltImageQuality + 0.5F);
		}
		else {
			// remap [0.8, 0.866, 0.933, 1.0] to [0.8, 0.9, 1.0, 1.1]
            // to use 8-bit DPK QP table (0.933 == Photoshop JPEG 100)
            if(fltImageQuality > 0.8F && pixelInfo->bdBitDepth == BD_8 && wmiSCP->cfColorFormat != YUV_420 && wmiSCP->cfColorFormat != YUV_422) {
				fltImageQuality = 0.8F + (fltImageQuality - 0.8F) * 1.5F;
			}

            const int qi = (int) (10.0F * fltImageQuality);
            const float qf = 10.0F * fltImageQuality - (float)qi;
			
			const int *pQPs = 
				(wmiSCP->cfColorFormat == YUV_420 || wmiSCP->cfColorFormat == YUV_422) ?
				DPK_QPS_420[qi] :
				(pixelInfo->bdBitDepth == BD_8 ? DPK_QPS_8[qi] :
				(pixelInfo->bdBitDepth == BD_16 ? DPK_QPS_16[qi] :
				(pixelInfo->bdBitDepth == BD_16F ? DPK_QPS_16f[qi] :
				DPK_QPS_32f[qi])));
				
			wmiSCP->uiDefaultQPIndex = (U8) (0.5F + (float) pQPs[0] * (1.0F - qf) + (float) (pQPs + 6)[0] * qf);
			wmiSCP->uiDefaultQPIndexU = (U8) (0.5F + (float) pQPs[1] * (1.0F - qf) + (float) (pQPs + 6)[1] * qf);
			wmiSCP->uiDefaultQPIndexV = (U8) (0.5F + (float) pQPs[2] * (1.0F - qf) + (float) (pQPs + 6)[2] * qf);
            wmiSCP->uiDefaultQPIndexYHP = (U8) (0.5F + (float) pQPs[3] * (1.0F - qf) + (float) (pQPs + 6)[3] * qf);
			wmiSCP->uiDefaultQPIndexUHP = (U8) (0.5F + (float) pQPs[4] * (1.0F - qf) + (float) (pQPs + 6)[4] * qf);
			wmiSCP->uiDefaultQPIndexVHP = (U8) (0.5F + (float) pQPs[5] * (1.0F - qf) + (float) (pQPs + 6)[5] * qf);
		}
	} // fltImageQuality < 1.0F
    else {
		// lossless mode
		wmiSCP->uiDefaultQPIndex = 1;
	}
}

/**
Set encoder parameters
@param wmiSCP Encoder parameters
@param pixelInfo Image specifications
@param flags FreeImage save flags
@param bHasAlpha TRUE if an alpha layer is present
*/
static void 
SetEncoderParameters(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, int flags, BOOL bHasAlpha) {
	float fltImageQuality = 1.0F;

	// all values have been set to zero by the API
	// update default values for some attributes
    wmiSCP->cfColorFormat = YUV_444;		// color format
    wmiSCP->bdBitDepth = BD_LONG;			// internal bit depth
    wmiSCP->bfBitstreamFormat = SPATIAL;	// compressed image data in spatial order
    wmiSCP->bProgressiveMode = FALSE;		// sequential mode
    wmiSCP->olOverlap = OL_ONE;				// single level overlap processing 
	wmiSCP->cNumOfSliceMinus1H = 0;			// # of horizontal slices
	wmiSCP->cNumOfSliceMinus1V = 0;			// # of vertical slices
    wmiSCP->sbSubband = SB_ALL;				// keep all subbands
    wmiSCP->uAlphaMode = 0;					// 0:no alpha 1: alpha only else: something + alpha 
    wmiSCP->uiDefaultQPIndex = 1;			// quantization for grey or rgb layer(s), 1: lossless
    wmiSCP->uiDefaultQPIndexAlpha = 1;		// quantization for alpha layer, 1: lossless

	// process the flags
	// -----------------

	// progressive mode
	if((flags & JXR_PROGRESSIVE) == JXR_PROGRESSIVE) {
		// turn on progressive mode (instead of sequential mode)
		wmiSCP->bProgressiveMode = TRUE;
	}

	// quality in [0.01 - 1.0), 1.0 means lossless - default is 0.80
	int quality = flags & 0x7F;
	if(quality == 0) {
		// defaut to 0.80
		fltImageQuality = 0.8F;
	} else if((flags & JXR_LOSSLESS) == JXR_LOSSLESS) {
		fltImageQuality = 1.0F;
	} else {
		quality = (quality >= 100) ? 100 : quality;
		fltImageQuality = quality / 100.0F;
	}
	SetCompression(wmiSCP, pixelInfo, fltImageQuality);

	// alpha compression
	if(bHasAlpha) {
		wmiSCP->uAlphaMode = 2;	// encode with a planar alpha channel
	}
}

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

static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	BOOL bIsFlipped = FALSE;		// FreeImage DIB are upside-down relative to usual graphic conventions
	PKPixelFormatGUID guid_format;	// image format
	PKPixelInfo pixelInfo;			// image specifications
	BOOL bHasAlpha = FALSE;			// is alpha layer present ?

	PKImageEncode *pEncoder = NULL;		// encoder interface
	ERR error_code = 0;					// error code as returned by the interface

	// get the I/O stream wrapper
	WMPStream *pEncodeStream = (WMPStream*)data;

	if(!dib || !handle || !pEncodeStream) {
		return FALSE;
	}

	try {
		// get image dimensions
		unsigned width = FreeImage_GetWidth(dib);
		unsigned height = FreeImage_GetHeight(dib);

		// check JPEG-XR limits
		if((width < MB_WIDTH_PIXEL) || (height < MB_HEIGHT_PIXEL)) {
			FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
			throw (const char*)NULL;
		}

		// get output pixel format
		error_code = GetOutputPixelFormat(dib, &guid_format, &bHasAlpha);
		JXR_CHECK(error_code);
		pixelInfo.pGUIDPixFmt = &guid_format;
		error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
		JXR_CHECK(error_code);

		// create a JXR encoder interface and initialize function pointers with *_WMP functions
		error_code = PKImageEncode_Create_WMP(&pEncoder);
		JXR_CHECK(error_code);

		// attach the stream to the encoder and set all encoder parameters to zero ...
		error_code = pEncoder->Initialize(pEncoder, pEncodeStream, &pEncoder->WMP.wmiSCP, sizeof(CWMIStrCodecParam));
		JXR_CHECK(error_code);

		// ... then configure the encoder
		SetEncoderParameters(&pEncoder->WMP.wmiSCP, &pixelInfo, flags, bHasAlpha);

		// set pixel format
		pEncoder->SetPixelFormat(pEncoder, guid_format);

		// set image size
		pEncoder->SetSize(pEncoder, width, height);
		
		// set resolution (convert from universal units to English units)
		float resX = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterX(dib));
		float resY = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterY(dib));
		pEncoder->SetResolution(pEncoder, resX, resY);

		// set metadata
		WriteMetadata(pEncoder, dib);

		// write metadata & pixels
		// -----------------------

		// dib coordinates are upside-down relative to usual conventions
		bIsFlipped = FreeImage_FlipVertical(dib);

		// get a pointer to dst pixel data
		BYTE *dib_bits = FreeImage_GetBits(dib);

		// get dst pitch (count of BYTE for stride)
		const unsigned cbStride = FreeImage_GetPitch(dib);

		// write metadata + pixels on output
		error_code = pEncoder->WritePixels(pEncoder, height, dib_bits, cbStride);
		JXR_CHECK(error_code);

		// recover dib coordinates
		FreeImage_FlipVertical(dib);

		// free the encoder
		pEncoder->Release(&pEncoder);
		assert(pEncoder == NULL);
		
		return TRUE;

	} catch (const char *message) {
		if(bIsFlipped) {
			// recover dib coordinates
			FreeImage_FlipVertical(dib);
		}
		if(pEncoder) {
			// free the encoder
			pEncoder->Release(&pEncoder);
			assert(pEncoder == NULL);
		}
		if(NULL != message) {
			FreeImage_OutputMessageProc(s_format_id, message);
		}
	}

	return FALSE;
}

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



( run in 1.382 second using v1.01-cache-2.11-cpan-63c85eba8c4 )