Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginWebP.cpp view on Meta::CPAN
const BYTE *src_bitmap = output_buffer->u.RGBA.rgba;
const unsigned src_pitch = (unsigned)output_buffer->u.RGBA.stride;
switch(bpp) {
case 24:
for(unsigned y = 0; y < height; y++) {
const BYTE *src_bits = src_bitmap + y * src_pitch;
BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
for(unsigned x = 0; x < width; x++) {
dst_bits[FI_RGBA_BLUE] = src_bits[0]; // B
dst_bits[FI_RGBA_GREEN] = src_bits[1]; // G
dst_bits[FI_RGBA_RED] = src_bits[2]; // R
src_bits += 3;
dst_bits += 3;
}
}
break;
case 32:
for(unsigned y = 0; y < height; y++) {
const BYTE *src_bits = src_bitmap + y * src_pitch;
BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, height-1-y);
for(unsigned x = 0; x < width; x++) {
dst_bits[FI_RGBA_BLUE] = src_bits[0]; // B
dst_bits[FI_RGBA_GREEN] = src_bits[1]; // G
dst_bits[FI_RGBA_RED] = src_bits[2]; // R
dst_bits[FI_RGBA_ALPHA] = src_bits[3]; // A
src_bits += 4;
dst_bits += 4;
}
}
break;
}
// Free the decoder
WebPFreeDecBuffer(output_buffer);
return dib;
} catch (const char *text) {
if(dib) {
FreeImage_Unload(dib);
}
WebPFreeDecBuffer(output_buffer);
if(NULL != text) {
FreeImage_OutputMessageProc(s_format_id, text);
}
return NULL;
}
}
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
WebPMux *mux = NULL;
WebPMuxFrameInfo webp_frame = { 0 }; // raw image
WebPData color_profile; // ICC raw data
WebPData xmp_metadata; // XMP raw data
WebPData exif_metadata; // EXIF raw data
FIBITMAP *dib = NULL;
WebPMuxError error_status;
if(!handle) {
return NULL;
}
try {
// get the MUX object
mux = (WebPMux*)data;
if(!mux) {
throw (1);
}
// gets the feature flags from the mux object
uint32_t webp_flags = 0;
error_status = WebPMuxGetFeatures(mux, &webp_flags);
if(error_status != WEBP_MUX_OK) {
throw (1);
}
// get image data
error_status = WebPMuxGetFrame(mux, 1, &webp_frame);
if(error_status == WEBP_MUX_OK) {
// decode the data (can be limited to the header if flags uses FIF_LOAD_NOPIXELS)
dib = DecodeImage(&webp_frame.bitstream, flags);
if(!dib) {
throw (1);
}
// get ICC profile
if(webp_flags & ICCP_FLAG) {
error_status = WebPMuxGetChunk(mux, "ICCP", &color_profile);
if(error_status == WEBP_MUX_OK) {
FreeImage_CreateICCProfile(dib, (void*)color_profile.bytes, (long)color_profile.size);
}
}
// get XMP metadata
if(webp_flags & XMP_FLAG) {
error_status = WebPMuxGetChunk(mux, "XMP ", &xmp_metadata);
if(error_status == WEBP_MUX_OK) {
// create a tag
FITAG *tag = FreeImage_CreateTag();
if(tag) {
FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
FreeImage_SetTagLength(tag, (DWORD)xmp_metadata.size);
FreeImage_SetTagCount(tag, (DWORD)xmp_metadata.size);
FreeImage_SetTagType(tag, FIDT_ASCII);
FreeImage_SetTagValue(tag, xmp_metadata.bytes);
// store the tag
FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
// destroy the tag
FreeImage_DeleteTag(tag);
}
}
}
// get Exif metadata
if(webp_flags & EXIF_FLAG) {
error_status = WebPMuxGetChunk(mux, "EXIF", &exif_metadata);
if(error_status == WEBP_MUX_OK) {
// read the Exif raw data as a blob
jpeg_read_exif_profile_raw(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
// read and decode the Exif data
jpeg_read_exif_profile(dib, exif_metadata.bytes, (unsigned)exif_metadata.size);
}
}
}
WebPDataClear(&webp_frame.bitstream);
return dib;
} catch(int) {
WebPDataClear(&webp_frame.bitstream);
return NULL;
}
}
// --------------------------------------------------------------------------
/**
Encode a FIBITMAP to a WebP image
@param hmem Memory output stream, containing on return the encoded image
@param dib The FIBITMAP to encode
@param flags FreeImage save flags
@return Returns TRUE if successfull, returns FALSE otherwise
*/
static BOOL
EncodeImage(FIMEMORY *hmem, FIBITMAP *dib, int flags) {
WebPPicture picture; // Input buffer
WebPConfig config; // Coding parameters
BOOL bIsFlipped = FALSE;
try {
const unsigned width = FreeImage_GetWidth(dib);
const unsigned height = FreeImage_GetHeight(dib);
const unsigned bpp = FreeImage_GetBPP(dib);
const unsigned pitch = FreeImage_GetPitch(dib);
// check image type
FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
if( !((image_type == FIT_BITMAP) && ((bpp == 24) || (bpp == 32))) ) {
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
// check format limits
if(MAX(width, height) > WEBP_MAX_DIMENSION) {
FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
return FALSE;
}
// Initialize output I/O
if(WebPPictureInit(&picture) == 1) {
picture.writer = WebP_MemoryWriter;
picture.custom_ptr = hmem;
picture.width = (int)width;
picture.height = (int)height;
} else {
src/Source/FreeImage/PluginWebP.cpp view on Meta::CPAN
const BYTE *bits = FreeImage_GetBits(dib);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
switch(bpp) {
case 24:
WebPPictureImportBGR(&picture, bits, pitch);
break;
case 32:
WebPPictureImportBGRA(&picture, bits, pitch);
break;
}
#else
switch(bpp) {
case 24:
WebPPictureImportRGB(&picture, bits, pitch);
break;
case 32:
WebPPictureImportRGBA(&picture, bits, pitch);
break;
}
#endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
if(!WebPEncode(&config, &picture)) {
throw "Failed to encode image";
}
WebPPictureFree(&picture);
if(bIsFlipped) {
// invert dib scanlines
FreeImage_FlipVertical(dib);
}
return TRUE;
} catch (const char* text) {
WebPPictureFree(&picture);
if(bIsFlipped) {
// invert dib scanlines
FreeImage_FlipVertical(dib);
}
if(NULL != text) {
FreeImage_OutputMessageProc(s_format_id, text);
}
}
return FALSE;
}
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
WebPMux *mux = NULL;
FIMEMORY *hmem = NULL;
WebPData webp_image;
WebPData output_data = { 0 };
WebPMuxError error_status;
int copy_data = 1; // 1 : copy data into the mux, 0 : keep a link to local data
if(!dib || !handle || !data) {
return FALSE;
}
try {
// get the MUX object
mux = (WebPMux*)data;
if(!mux) {
return FALSE;
}
// --- prepare image data ---
// encode image as a WebP blob
hmem = FreeImage_OpenMemory();
if(!hmem || !EncodeImage(hmem, dib, flags)) {
throw (1);
}
// store the blob into the mux
BYTE *data = NULL;
DWORD data_size = 0;
FreeImage_AcquireMemory(hmem, &data, &data_size);
webp_image.bytes = data;
webp_image.size = data_size;
error_status = WebPMuxSetImage(mux, &webp_image, copy_data);
// no longer needed since copy_data == 1
FreeImage_CloseMemory(hmem);
hmem = NULL;
if(error_status != WEBP_MUX_OK) {
throw (1);
}
// --- set metadata ---
// set ICC color profile
{
FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
if (iccProfile->size && iccProfile->data) {
WebPData icc_profile;
icc_profile.bytes = (uint8_t*)iccProfile->data;
icc_profile.size = (size_t)iccProfile->size;
error_status = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
if(error_status != WEBP_MUX_OK) {
throw (1);
}
}
}
// set XMP metadata
{
FITAG *tag = NULL;
if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag)) {
WebPData xmp_profile;
xmp_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
xmp_profile.size = (size_t)FreeImage_GetTagLength(tag);
error_status = WebPMuxSetChunk(mux, "XMP ", &xmp_profile, copy_data);
if(error_status != WEBP_MUX_OK) {
throw (1);
}
}
}
// set Exif metadata
{
FITAG *tag = NULL;
if(FreeImage_GetMetadata(FIMD_EXIF_RAW, dib, g_TagLib_ExifRawFieldName, &tag)) {
WebPData exif_profile;
exif_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
exif_profile.size = (size_t)FreeImage_GetTagLength(tag);
error_status = WebPMuxSetChunk(mux, "EXIF", &exif_profile, copy_data);
if(error_status != WEBP_MUX_OK) {
throw (1);
}
}
}
// get data from mux in WebP RIFF format
error_status = WebPMuxAssemble(mux, &output_data);
if(error_status != WEBP_MUX_OK) {
FreeImage_OutputMessageProc(s_format_id, "Failed to create webp output file");
throw (1);
}
// write the file to the output stream
if(io->write_proc((void*)output_data.bytes, 1, (unsigned)output_data.size, handle) != output_data.size) {
FreeImage_OutputMessageProc(s_format_id, "Failed to write webp output file");
throw (1);
}
// free WebP output file
WebPDataClear(&output_data);
return TRUE;
} catch(int) {
if(hmem) {
FreeImage_CloseMemory(hmem);
}
WebPDataClear(&output_data);
return FALSE;
}
}
// ==========================================================
// Init
// ==========================================================
void DLL_CALLCONV
InitWEBP(Plugin *plugin, int format_id) {
s_format_id = format_id;
plugin->format_proc = Format;
plugin->description_proc = Description;
plugin->extension_proc = Extension;
plugin->regexpr_proc = RegExpr;
plugin->open_proc = Open;
plugin->close_proc = Close;
plugin->pagecount_proc = NULL;
plugin->pagecapability_proc = NULL;
plugin->load_proc = Load;
plugin->save_proc = Save;
plugin->validate_proc = Validate;
plugin->mime_proc = MimeType;
plugin->supports_export_bpp_proc = SupportsExportDepth;
plugin->supports_export_type_proc = SupportsExportType;
plugin->supports_icc_profiles_proc = SupportsICCProfiles;
plugin->supports_no_pixels_proc = SupportsNoPixels;
}
( run in 0.446 second using v1.01-cache-2.11-cpan-5735350b133 )