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 )