CGImageRef MCImage::makeicon(uint4 p_width, uint4 p_height) { CGImageRef t_icon = NULL; MCImageBitmap *t_bitmap = nil; if (lockbitmap(t_bitmap, false)) { MCImageBitmap *t_scaled = nil; if (p_width != t_bitmap->width || p_height != t_bitmap->height) /* UNCHECKED */ MCImageScaleBitmap(t_bitmap, p_width, p_height, resizequality, t_scaled); /* UNCHECKED */ MCImageBitmapToCGImage(t_scaled != nil ? t_scaled : t_bitmap, true, false, t_icon); MCImageFreeBitmap(t_scaled); unlockbitmap(t_bitmap); } return t_icon; }
// decode image data to a series of frames, ignoring all the other bits & pieces bool MCImageDecode(IO_handle p_stream, MCImageFrame *&r_frames, uindex_t &r_frame_count) { bool t_success = true; MCImageFrame *t_frames = nil; uindex_t t_frame_count = 0; MCImageBitmap *t_bitmap = nil; MCImageCompressedBitmap *t_compressed = nil; MCPoint t_hotspot; char *t_name = nil; if (t_success) t_success = MCImageImport(p_stream, nil, t_hotspot, t_name, t_compressed, t_bitmap); if (t_success) { if (t_compressed != nil) t_success = MCImageDecompress(t_compressed, r_frames, r_frame_count); else { t_success = MCMemoryNewArray(1, r_frames); if (t_success) { r_frames[0].image = t_bitmap; t_bitmap = nil; r_frame_count = 1; } } } MCImageFreeCompressedBitmap(t_compressed); MCImageFreeBitmap(t_bitmap); MCCStringFree(t_name); return t_success; }
bool MCImageDecodePNG(IO_handle p_stream, MCImageBitmap *&r_bitmap) { bool t_success = true; MCImageBitmap *t_bitmap = nil; png_structp t_png = nil; png_infop t_info = nil; png_infop t_end_info = nil; t_success = nil != (t_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)); if (t_success) t_success = nil != (t_info = png_create_info_struct(t_png)); if (t_success) t_success = nil != (t_end_info = png_create_info_struct(t_png)); if (setjmp(png_jmpbuf(t_png))) { t_success = false; } if (t_success) { png_set_read_fn(t_png, p_stream, stream_read); png_read_info(t_png, t_info); } png_uint_32 t_width, t_height; int t_bit_depth, t_color_type; int t_interlace_method, t_compression_method, t_filter_method; int t_interlace_passes; if (t_success) { png_get_IHDR(t_png, t_info, &t_width, &t_height, &t_bit_depth, &t_color_type, &t_interlace_method, &t_compression_method, &t_filter_method); } if (t_success) t_success = MCImageBitmapCreate(t_width, t_height, t_bitmap); if (t_success) { bool t_need_alpha = false; t_interlace_passes = png_set_interlace_handling(t_png); if (t_color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(t_png); if (t_color_type == PNG_COLOR_TYPE_GRAY || t_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(t_png); if (png_get_valid(t_png, t_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(t_png); t_need_alpha = true; /* OVERHAUL - REVISIT - assume image has transparent pixels if tRNS is present */ t_bitmap->has_transparency = true; } if (t_color_type & PNG_COLOR_MASK_ALPHA) { t_need_alpha = true; /* OVERHAUL - REVISIT - assume image has alpha if color type allows it */ t_bitmap->has_alpha = t_bitmap->has_transparency = true; } else if (!t_need_alpha) png_set_add_alpha(t_png, 0xFF, MCswapbytes ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE); if (t_bit_depth == 16) png_set_strip_16(t_png); if (MCswapbytes) png_set_bgr(t_png); else png_set_swap_alpha(t_png); } // MW-2009-12-10: Support for color profiles MCColorTransformRef t_color_xform; t_color_xform = nil; // Try to get an embedded ICC profile... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_iCCP)) { png_charp t_ccp_name; png_bytep t_ccp_profile; int t_ccp_compression_type; png_uint_32 t_ccp_profile_length; png_get_iCCP(t_png, t_info, &t_ccp_name, &t_ccp_compression_type, &t_ccp_profile, &t_ccp_profile_length); MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceEmbedded; t_csinfo . embedded . data = t_ccp_profile; t_csinfo . embedded . data_size = t_ccp_profile_length; t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Next try an sRGB style profile... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_sRGB)) { int t_intent; png_get_sRGB(t_png, t_info, &t_intent); MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceStandardRGB; t_csinfo . standard . intent = (MCColorSpaceIntent)t_intent; t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Finally try for cHRM + gAMA... if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_cHRM) && png_get_valid(t_png, t_info, PNG_INFO_gAMA)) { MCColorSpaceInfo t_csinfo; t_csinfo . type = kMCColorSpaceCalibratedRGB; png_get_cHRM(t_png, t_info, &t_csinfo . calibrated . white_x, &t_csinfo . calibrated . white_y, &t_csinfo . calibrated . red_x, &t_csinfo . calibrated . red_y, &t_csinfo . calibrated . green_x, &t_csinfo . calibrated . green_y, &t_csinfo . calibrated . blue_x, &t_csinfo . calibrated . blue_y); png_get_gAMA(t_png, t_info, &t_csinfo . calibrated . gamma); t_color_xform = MCscreen -> createcolortransform(t_csinfo); } // Could not create any kind, so fallback to gamma transform. if (t_success && t_color_xform == nil) { double image_gamma; if (png_get_gAMA(t_png, t_info, &image_gamma)) png_set_gamma(t_png, MCgamma, image_gamma); else png_set_gamma(t_png, MCgamma, 0.45); } if (t_success) { for (uindex_t t_pass = 0; t_pass < t_interlace_passes; t_pass++) { png_bytep t_data_ptr = (png_bytep)t_bitmap->data; for (uindex_t i = 0; i < t_height; i++) { png_read_row(t_png, t_data_ptr, nil); t_data_ptr += t_bitmap->stride; } } } if (t_success) png_read_end(t_png, t_end_info); if (t_png != nil) png_destroy_read_struct(&t_png, &t_info, &t_end_info); // transform colours using extracted colour profile if (t_success && t_color_xform != nil) MCImageBitmapApplyColorTransform(t_bitmap, t_color_xform); if (t_color_xform != nil) MCscreen -> destroycolortransform(t_color_xform); if (t_success) r_bitmap = t_bitmap; else { if (t_bitmap != nil) MCImageFreeBitmap(t_bitmap); } return t_success; }
void MCGImageImageRep::ReleaseBitmap() { if (m_bitmap != nil) MCImageFreeBitmap(m_bitmap); m_bitmap = nil; }
bool MCGIFImageLoader::LoadFrames(MCBitmapFrame *&r_frames, uint32_t &r_count) { bool t_success; t_success = true; MCImageBitmap *t_canvas; t_canvas = nil; // restoration info MCImageBitmap *t_restore_image = nil; int t_disposal_mode = DISPOSAL_UNSPECIFIED; MCRectangle t_disposal_region = kMCEmptyRectangle; // The list of frames. MCBitmapFrame *t_frames = nil; t_success = GIF_OK == DGifSlurp(m_gif); // Fetch the width and height of the virtual canvas. int32_t t_width, t_height; if (t_success) { t_width = m_gif -> SWidth; t_height = m_gif -> SHeight; // create the canvas image t_success = MCImageBitmapCreate(t_width, t_height, t_canvas); } // The current frame count. The number of frames is the same as the // number of images in the GIF. uint32_t t_frame_count; t_frame_count = 0; // If true, the new image will be merged with the old - otherwise the mask // replaces it. bool t_overlay; t_overlay = false; // Loop through all the images, making frames as we go. for(uindex_t i = 0; t_success && i < m_gif -> ImageCount; i++) { // Process the disposal. switch (t_disposal_mode) { case DISPOSE_BACKGROUND: gif_fill_image_region(t_canvas, t_disposal_region, 0); break; case DISPOSE_PREVIOUS: if (t_restore_image != nil) gif_paste_image(t_canvas, t_restore_image, t_disposal_region.x, t_disposal_region.y); break; case DISPOSE_DO_NOT: t_overlay = true; break; default: t_overlay = false; break; } // Fetch the image information. GraphicsControlBlock t_image_gcb; MCRectangle t_image_region; ColorMapObject *t_image_colors = nil; int32_t t_image_transparency; int32_t t_image_delay; int32_t t_image_disposal; GifByteType *t_image_raster; // First the information from the image description. t_image_region.x = m_gif -> SavedImages[i] . ImageDesc . Left; t_image_region.y = m_gif -> SavedImages[i] . ImageDesc . Top; t_image_region.width = m_gif -> SavedImages[i] . ImageDesc . Width; t_image_region.height = m_gif -> SavedImages[i] . ImageDesc . Height; t_image_colors = m_gif -> SavedImages[i] . ImageDesc . ColorMap; t_image_raster = m_gif -> SavedImages[i] . RasterBits; if (t_image_colors == nil) t_image_colors = m_gif -> SColorMap; // Then the information from the GCB. if (GIF_OK == DGifSavedExtensionToGCB(m_gif, i, &t_image_gcb)) { t_image_transparency = t_image_gcb . TransparentColor; t_image_delay = t_image_gcb . DelayTime; t_image_disposal = t_image_gcb . DisposalMode; } else { t_image_transparency = -1; t_image_delay = 0; t_image_disposal = DISPOSAL_UNSPECIFIED; } // If disposal is 'previous' then cache the portion of the canvas we are // about to affect. if (t_image_disposal == DISPOSE_PREVIOUS) { if (t_restore_image != nil) { if (t_disposal_mode != DISPOSE_PREVIOUS || !MCU_equal_rect(t_disposal_region, t_image_region)) { MCImageFreeBitmap(t_restore_image); t_restore_image = nil; } } if (t_restore_image == nil) t_success = MCImageCopyBitmapRegion(t_canvas, t_image_region, t_restore_image); } if (t_success) { // Render the image into the canvas. gif_draw_image_into_canvas(t_canvas, t_image_raster, t_image_region.x, t_image_region.y, t_image_region.width, t_image_region.height, t_image_colors, t_image_transparency, t_overlay); // Generate our frame. t_success = MCMemoryResizeArray(t_frame_count + 1, t_frames, t_frame_count); } MCImageBitmap *t_frame_bitmap = nil; if (t_success) t_success = MCImageCopyBitmap(t_canvas, t_frame_bitmap); if (t_success) { MCImageBitmapCheckTransparency(t_frame_bitmap); t_frames[t_frame_count - 1].image = t_frame_bitmap; t_frames[t_frame_count - 1].duration = t_image_delay * 10; // convert 1/100 seconds to milliseconds t_frames[t_frame_count - 1].x_scale = t_frames[t_frame_count - 1].y_scale = 1.0; } t_disposal_region = t_image_region; t_disposal_mode = t_image_disposal; } MCImageFreeBitmap(t_canvas); MCImageFreeBitmap(t_restore_image); if (t_success) { r_frames = t_frames; r_count = t_frame_count; } else MCImageFreeFrames(t_frames, t_frame_count); return t_success; }
bool MCEncodedImageRep::LoadImageFrames(MCImageFrame *&r_frames, uindex_t &r_frame_count, bool &r_frames_premultiplied) { bool t_success = true; // IM-2013-02-18 - switching this back to using MCImageImport as we need to // determine the compression type for m_compression IO_handle t_stream = nil; IO_handle t_mask_stream = nil; MCImageCompressedBitmap *t_compressed = nil; MCImageBitmap *t_bitmap = nil; MCPoint t_hotspot = {1, 1}; char *t_name = nil; t_success = GetDataStream(t_stream) && MCImageImport(t_stream, t_mask_stream, t_hotspot, t_name, t_compressed, t_bitmap); if (t_stream != nil) MCS_close(t_stream); MCImageFrame *t_frames; t_frames = nil; uindex_t t_frame_count; t_frame_count = 0; if (t_success) { if (t_compressed != nil) t_success = MCImageDecompress(t_compressed, t_frames, t_frame_count); else { t_success = MCMemoryNewArray(1, t_frames); if (t_success) { t_frames[0].image = t_bitmap; t_frames[0].density = 1.0; t_bitmap = nil; t_frame_count = 1; } } } if (t_success) { m_width = t_frames[0].image->width; m_height = t_frames[0].image->height; if (t_compressed != nil) m_compression = t_compressed->compression; m_have_geometry = true; r_frames = t_frames; r_frame_count = t_frame_count; r_frames_premultiplied = false; } MCCStringFree(t_name); MCImageFreeBitmap(t_bitmap); MCImageFreeCompressedBitmap(t_compressed); return t_success; }
IO_stat MCImage::import(MCStringRef newname, IO_handle stream, IO_handle mstream) { bool t_success = true; MCImageCompressedBitmap *t_compressed = nil; MCImageBitmap *t_bitmap = nil; MCStringRef t_name = nil; MCPoint t_hotspot = {1, 1}; t_success = MCImageImport(stream, mstream, t_hotspot, t_name, t_compressed, t_bitmap); if (t_success) { if (t_compressed == nil) t_success = setbitmap(t_bitmap, 1.0); else t_success = setcompressedbitmap(t_compressed); } MCImageFreeCompressedBitmap(t_compressed); MCImageFreeBitmap(t_bitmap); uindex_t t_width, t_height; if (t_success) t_success = getsourcegeometry(t_width, t_height); if (t_success) { xhot = t_hotspot.x; yhot = t_hotspot.y; bool t_resize = true; t_resize = !(flags & F_LOCK_LOCATION); if (t_resize) { rect.width = t_width; rect.height = t_height; } if (m_rep->GetFrameCount() > 1) { if ((flags & F_REPEAT_COUNT) == 0) repeatcount = -1; irepeatcount = repeatcount; state |= CS_DO_START; } if (isunnamed() && t_name != nil) { MCNewAutoNameRef t_name_nameref; /* UNCHECKED */ MCNameCreate(t_name, &t_name_nameref); setname(*t_name_nameref); } if (isunnamed() && newname != nil) { MCNewAutoNameRef t_name_nameref; uindex_t t_offset; if (MCStringLastIndexOfChar(newname, PATH_SEPARATOR, UINDEX_MAX, kMCCompareExact, t_offset)) { /* UNCHECKED */ MCStringCopySubstring(newname, MCRangeMakeMinMax(t_offset + 1, MCStringGetLength(newname)), t_name); /* UNCHECKED */ MCNameCreate(t_name, &t_name_nameref); } else /* UNCHECKED */ MCNameCreate(newname, &t_name_nameref); setname(*t_name_nameref); } } MCValueRelease(t_name); return t_success ? IO_NORMAL : IO_ERROR; }
// if the image is in a directly supported format return the raw data otherwise decode & return the bitmap bool MCImageImport(IO_handle p_stream, IO_handle p_mask_stream, MCPoint &r_hotspot, MCStringRef&r_name, MCImageCompressedBitmap *&r_compressed, MCImageBitmap *&r_bitmap) { bool t_success; t_success = true; // IM-2014-07-31: [[ ImageLoader ]] Update to use MCImageLoader class MCImageLoaderFormat t_format; if (t_success) t_success = MCImageLoader::IdentifyFormat(p_stream, t_format); if (t_success) { uint32_t t_compression; if (MCImageLoaderFormatToCompression(t_format, t_compression)) { t_success = MCImageCreateCompressedBitmap(t_compression, r_compressed); if (t_success) { uint32_t t_width, t_height; t_width = t_height = 0; if (t_success && t_compression == F_PICT) t_success = MCImageGetMetafileGeometry(p_stream, t_width, t_height); if (t_success) t_success = read_all(p_stream, r_compressed->data, r_compressed->size); r_compressed->width = t_width; r_compressed->height = t_height; } } else { MCImageLoader *t_loader; t_loader = nil; t_success = MCImageLoader::LoaderForStreamWithFormat(p_stream, t_format, t_loader); uint32_t t_xhot, t_yhot; MCAutoStringRef t_name; MCBitmapFrame *t_frames; t_frames = nil; uint32_t t_count; t_count = 0; if (t_success) t_success = t_loader->GetHotSpot(t_xhot, t_yhot); if (t_success) t_success = t_loader->GetName(&t_name); if (t_success) t_success = t_loader->TakeFrames(t_frames, t_count); if (t_success && p_mask_stream != nil && t_loader->GetFormat() == kMCImageFormatNetPBM) { MCImageBitmap *t_mask = nil; t_success = MCImageDecodeNetPBM(p_mask_stream, t_mask) && MCImageBitmapApplyMask(t_frames[0].image, t_mask); MCImageFreeBitmap(t_mask); } if (t_success) { r_hotspot.x = t_xhot; r_hotspot.y = t_yhot; r_name = MCValueRetain(*t_name); r_bitmap = t_frames[0].image; t_frames[0].image = nil; } else r_name = MCValueRetain(kMCEmptyString); MCImageFreeFrames(t_frames, t_count); if (t_loader != nil) delete t_loader; } } return t_success; }
IO_stat MCImage::import(const char *newname, IO_handle stream, IO_handle mstream) { bool t_success = true; MCImageCompressedBitmap *t_compressed = nil; MCImageBitmap *t_bitmap = nil; char *t_name = nil; MCPoint t_hotspot = {1, 1}; t_success = MCImageImport(stream, mstream, t_hotspot, t_name, t_compressed, t_bitmap); if (t_success) { if (t_compressed == nil) t_success = setbitmap(t_bitmap); else t_success = setcompressedbitmap(t_compressed); } MCImageFreeCompressedBitmap(t_compressed); MCImageFreeBitmap(t_bitmap); uindex_t t_width, t_height; if (t_success) t_success = m_rep->GetGeometry(t_width, t_height); if (t_success) { xhot = t_hotspot.x; yhot = t_hotspot.y; bool t_resize = true; t_resize = !(flags & F_LOCK_LOCATION); if (t_resize) { rect.width = t_width; rect.height = t_height; } if (m_rep->GetFrameCount() > 1) { if ((flags & F_REPEAT_COUNT) == 0) repeatcount = -1; irepeatcount = repeatcount; state |= CS_DO_START; } if (isunnamed() && t_name != nil) setname_cstring(t_name); if (isunnamed() && newname != nil) { const char *tname = strrchr(newname, PATH_SEPARATOR); if (tname != NULL) tname += 1; else tname = newname; setname_cstring(tname); } } MCCStringFree(t_name); return t_success ? IO_NORMAL : IO_ERROR; }
// if the image is in a directly supported format return the raw data otherwise decode & return the bitmap bool MCImageImport(IO_handle p_stream, IO_handle p_mask_stream, MCPoint &r_hotspot, char *&r_name, MCImageCompressedBitmap *&r_compressed, MCImageBitmap *&r_bitmap) { bool t_success = true; uindex_t t_width = 0, t_height = 0; uint8_t t_head[8]; uindex_t t_size = 8; uint32_t t_compression = F_RLE; if (t_success) t_success = MCS_read(t_head, sizeof(uint8_t), t_size, p_stream) == IO_NORMAL && t_size == 8 && MCS_seek_cur(p_stream, -8) == IO_NORMAL; if (t_success) { if (memcmp(t_head, "GIF87a", 6) == 0) t_compression = F_GIF; else if (memcmp(t_head, "GIF89a", 6) == 0) t_compression = F_GIF; else if (memcmp(t_head, "\211PNG", 4) == 0) t_compression = F_PNG; else if (memcmp(t_head, "\xff\xd8", 2) == 0) t_compression = F_JPEG; else if (MCImageGetMetafileGeometry(p_stream, t_width, t_height)) t_compression = F_PICT; if (t_compression != F_RLE) { t_success = MCImageCreateCompressedBitmap(t_compression, r_compressed); if (t_success) { if (t_success) t_success = read_all(p_stream, r_compressed->data, r_compressed->size); r_compressed->width = t_width; r_compressed->height = t_height; } } else { MCImageBitmap *t_bitmap = nil; if (memcmp(t_head, "BM", 2) == 0) t_success = MCImageDecodeBMP(p_stream, r_hotspot, t_bitmap); else if (memcmp(t_head, "#define", 7) == 0) t_success = MCImageDecodeXBM(p_stream, r_hotspot, r_name, t_bitmap); else if (memcmp(t_head, "/* XPM", 6) == 0) t_success = MCImageDecodeXPM(p_stream, t_bitmap); else if (t_head[0] == 'P' && (t_head[1] >= '1' && t_head[1] <= '6')) { t_success = MCImageDecodeNetPBM(p_stream, t_bitmap); // may have a mask image if (t_success && p_mask_stream != nil) { MCImageBitmap *t_mask = nil; t_success = MCImageDecodeNetPBM(p_mask_stream, t_mask) && MCImageBitmapApplyMask(t_bitmap, t_mask); MCImageFreeBitmap(t_mask); } } else // if all else fails, assume it's an XWD t_success = MCImageDecodeXWD(p_stream, r_name, t_bitmap); if (t_success) r_bitmap = t_bitmap; else MCImageFreeBitmap(t_bitmap); } } return t_success; }
bool MCTransformedImageRep::LoadImageFrames(MCImageFrame *&r_frames, uindex_t &r_frame_count) { uindex_t t_target_width, t_target_height; if (!GetGeometry(t_target_width, t_target_height)) return false; bool t_success = true; MCImageFrame *t_frames = nil; uindex_t t_frame_count = 0; t_frame_count = m_source->GetFrameCount(); t_success = MCMemoryNewArray(t_frame_count, t_frames); for (uindex_t i = 0; t_success && i < t_frame_count; i++) { MCImageFrame *t_src_frame = nil; t_success = m_source->LockImageFrame(i, t_src_frame); if (t_success) { t_frames[i].duration = t_src_frame->duration; if (m_angle != 0) { // rotate MCImageBitmap *t_bitmap = nil; MCImageBitmap *t_rotated = nil; t_success = MCImageCopyBitmap(t_src_frame->image, t_bitmap); if (t_success) { MCImageBitmapPremultiply(t_bitmap); t_success = MCImageRotateBitmap(t_bitmap, m_angle, m_quality, 0x0, t_rotated); } MCImageFreeBitmap(t_bitmap); bool t_scaled = false; if (t_success && (t_rotated->width != t_target_width || t_rotated->height != t_target_height)) { MCImageBitmap *t_sbitmap = nil; t_success = MCImageScaleBitmap(t_rotated, t_target_width, t_target_height, m_quality, t_sbitmap); MCImageFreeBitmap(t_rotated); t_rotated = t_sbitmap; t_scaled = true; } if (t_success) { if (t_scaled && (m_quality == INTERPOLATION_BICUBIC)) MCImageBitmapUnpremultiplyChecking(t_rotated); else MCImageBitmapUnpremultiply(t_rotated); t_frames[i].image = t_rotated; } else MCImageFreeBitmap(t_rotated); } else { // resize if (t_src_frame->image->width == t_target_width && t_src_frame->image->height == t_target_height) t_success = MCImageCopyBitmap(t_src_frame->image, t_frames[i].image); else t_success = MCImageScaleBitmap(t_src_frame->image, t_target_width, t_target_height, m_quality, t_frames[i].image); } } m_source->UnlockImageFrame(i, t_src_frame); } if (t_success) { r_frames = t_frames; r_frame_count = t_frame_count; } else MCImageFreeFrames(t_frames, t_frame_count); return t_success; }