bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleToFit) { const int width = scaleToFit ? scaleToFit->width() : SkToInt(CGImageGetWidth(image)); const int height = scaleToFit ? scaleToFit->height() : SkToInt(CGImageGetHeight(image)); SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); SkBitmap tmp; if (!tmp.allocPixels(info)) { return false; } if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) { return false; } CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image); switch (cgInfo) { case kCGImageAlphaNone: case kCGImageAlphaNoneSkipLast: case kCGImageAlphaNoneSkipFirst: SkASSERT(SkBitmap::ComputeIsOpaque(tmp)); tmp.setAlphaType(kOpaque_SkAlphaType); break; default: // we don't know if we're opaque or not, so compute it. if (SkBitmap::ComputeIsOpaque(tmp)) { tmp.setAlphaType(kOpaque_SkAlphaType); } } *dst = tmp; return true; }
bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); if (NULL == imageSrc) { return false; } SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL); if (NULL == image) { return false; } SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image); const int width = SkToInt(CGImageGetWidth(image)); const int height = SkToInt(CGImageGetHeight(image)); bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } SkAutoLockPixels alp(*bm); if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) { return false; } CGImageAlphaInfo info = CGImageGetAlphaInfo(image); switch (info) { case kCGImageAlphaNone: case kCGImageAlphaNoneSkipLast: case kCGImageAlphaNoneSkipFirst: SkASSERT(SkBitmap::ComputeIsOpaque(*bm)); bm->setAlphaType(kOpaque_SkAlphaType); break; default: // we don't know if we're opaque or not, so compute it. if (SkBitmap::ComputeIsOpaque(*bm)) { bm->setAlphaType(kOpaque_SkAlphaType); } } if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) { // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied. // Convert to unpremultiplied. for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { uint32_t* addr = bm->getAddr32(i, j); *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr); } } bm->setAlphaType(kUnpremul_SkAlphaType); } return true; }
bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); if (NULL == imageSrc) { return false; } SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL); if (NULL == image) { return false; } SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image); const int width = CGImageGetWidth(image); const int height = CGImageGetHeight(image); bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } bm->lockPixels(); bm->eraseColor(SK_ColorTRANSPARENT); // use the same colorspace, so we don't change the pixels at all CGColorSpaceRef cs = CGImageGetColorSpace(image); CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO); if (NULL == cg) { // perhaps the image's colorspace does not work for a context, so try just rgb cs = CGColorSpaceCreateDeviceRGB(); cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO); CFRelease(cs); } CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image); CGContextRelease(cg); CGImageAlphaInfo info = CGImageGetAlphaInfo(image); switch (info) { case kCGImageAlphaNone: case kCGImageAlphaNoneSkipLast: case kCGImageAlphaNoneSkipFirst: SkASSERT(SkBitmap::ComputeIsOpaque(*bm)); bm->setIsOpaque(true); break; default: // we don't know if we're opaque or not, so compute it. bm->computeAndSetOpaquePredicate(); } bm->unlockPixels(); return true; }
cv::Mat &osx_cv::toMat( const CGImageRef &image, cv::Mat &out, osx::disp::RGBType destType ) { cv::Mat temp; size_t w = CGImageGetWidth(image), h = CGImageGetHeight(image); if (CGImageGetBitsPerPixel(image) != 32) { throw invalid_argument("`image` must be 32 bits per pixel"); } temp.create(int(h), int(w), CV_8UC4); CGColorSpaceRef colorSpace = CGImageGetColorSpace(image); CGContextRef context = CGBitmapContextCreate( temp.data, w, h, CGImageGetBitsPerComponent(image), CGImageGetBytesPerRow(image), colorSpace, CGImageGetAlphaInfo(image) ); CGContextDrawImage( context, CGRectMake(0, 0, (CGFloat)w, (CGFloat)h), image ); _cvtRGBColor(temp, out, CGImageGetAlphaInfo(image), destType); CGContextRelease(context); return out; }
CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, FX_INT32 deviceClass) { m_saveCount = 0; _context = context; _deviceClass = deviceClass; CGContextRetain(_context); CGRect r = CGContextGetClipBoundingBox(context); _width = FXSYS_round(r.size.width); _height = FXSYS_round(r.size.height); _renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE | FXRC_BIT_MASK | FXRC_ALPHA_MASK; if (_deviceClass != FXDC_DISPLAY) { } else { CGImageRef image = CGBitmapContextCreateImage(_context); if (image) { _renderCaps |= FXRC_GET_BITS; _width = CGImageGetWidth(image); _height = CGImageGetHeight(image); CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image); if (kCGImageAlphaPremultipliedFirst == alphaInfo || kCGImageAlphaPremultipliedLast == alphaInfo || kCGImageAlphaOnly == alphaInfo) { _renderCaps |= FXRC_ALPHA_OUTPUT; } } CGImageRelease(image); } CGAffineTransform ctm = CGContextGetCTM(_context); CGContextSaveGState(_context); m_saveCount++; if (ctm.d >= 0) { CGFloat offset_x, offset_y; offset_x = ctm.tx; offset_y = ctm.ty; CGContextTranslateCTM(_context, -offset_x, -offset_y); CGContextConcatCTM(_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, _height + offset_y)); } _foxitDevice2User = CGAffineTransformIdentity; _user2FoxitDevice = CGAffineTransformInvert(_foxitDevice2User); }
/* Once we have our image (CGImageRef), we need to get it into an osg::Image */ osg::Image* CreateOSGImageFromCGImage(CGImageRef image_ref) { /* This code is adapted from Apple's Documentation found here: * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html * Listing 9-4††Using a Quartz image as a texture source. * Unfortunately, this guide doesn't show what to do about * non-RGBA image formats so I'm making the rest up * (and it's probably all wrong). */ size_t the_width = CGImageGetWidth(image_ref); size_t the_height = CGImageGetHeight(image_ref); CGRect the_rect = {{0, 0}, {the_width, the_height}}; size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref); size_t bytes_per_row = CGImageGetBytesPerRow(image_ref); // size_t bits_per_component = CGImageGetBitsPerComponent(image_ref); size_t bits_per_component = 8; CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref); GLint internal_format; GLenum pixel_format; GLenum data_type; void* image_data = calloc(the_width * 4, the_height); CGColorSpaceRef color_space; CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref); switch(bits_per_pixel) { // Drat, if 8-bit, how do you distinguish // between a 256 color GIF, a LUMINANCE map // or an ALPHA map? case 8: { // I probably did the formats all wrong for this case, // especially the ALPHA case. if(kCGImageAlphaNone == alpha_info) { /* internal_format = GL_LUMINANCE; pixel_format = GL_LUMINANCE; */ internal_format = GL_RGBA8; pixel_format = GL_BGRA_EXT; data_type = GL_UNSIGNED_INT_8_8_8_8_REV; bytes_per_row = the_width*4; // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); // bitmap_info = kCGImageAlphaPremultipliedFirst; #if __BIG_ENDIAN__ bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */ #else bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ #endif } else { internal_format = GL_ALPHA; pixel_format = GL_ALPHA; data_type = GL_UNSIGNED_BYTE; // bytes_per_row = the_width; // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); color_space = CGColorSpaceCreateDeviceGray(); } break; } case 24: { internal_format = GL_RGBA8; pixel_format = GL_BGRA_EXT; data_type = GL_UNSIGNED_INT_8_8_8_8_REV; bytes_per_row = the_width*4; // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); // bitmap_info = kCGImageAlphaNone; #if __BIG_ENDIAN__ bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */ #else bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ #endif break; } // // Tatsuhiro Nishioka // 16 bpp grayscale (8 bit white and 8 bit alpha) causes invalid argument combination // in CGBitmapContextCreate. // I guess it is safer to handle 16 bit grayscale image as 32-bit RGBA image. // It works at least on FlightGear // case 16: case 32: case 48: case 64: { internal_format = GL_RGBA8; pixel_format = GL_BGRA_EXT; data_type = GL_UNSIGNED_INT_8_8_8_8_REV; bytes_per_row = the_width*4; // color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); color_space = CGColorSpaceCreateDeviceRGB(); // bitmap_info = kCGImageAlphaPremultipliedFirst; #if __BIG_ENDIAN__ bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */ #else bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */ #endif break; } default: { // OSG_WARN << "Unknown file type in " << fileName.c_str() << " with " << origDepth << std::endl; return NULL; break; } } // Sets up a context to be drawn to with image_data as the area to be drawn to CGContextRef bitmap_context = CGBitmapContextCreate( image_data, the_width, the_height, bits_per_component, bytes_per_row, color_space, bitmap_info ); CGContextTranslateCTM(bitmap_context, 0, the_height); CGContextScaleCTM(bitmap_context, 1.0, -1.0); // Draws the image into the context's image_data CGContextDrawImage(bitmap_context, the_rect, image_ref); CGContextRelease(bitmap_context); if (!image_data) return NULL; // alpha is premultiplied with rgba, undo it vImage_Buffer vb; vb.data = image_data; vb.height = the_height; vb.width = the_width; vb.rowBytes = the_width * 4; vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0); // changing it to GL_UNSIGNED_BYTE seems working, but I'm not sure if this is a right way. // data_type = GL_UNSIGNED_BYTE; osg::Image* osg_image = new osg::Image; osg_image->setImage( the_width, the_height, 1, internal_format, pixel_format, data_type, (unsigned char*)image_data, osg::Image::USE_MALLOC_FREE // Assumption: osg_image takes ownership of image_data and will free ); return osg_image; }
bool CBaseTexture::LoadFromFile(const CStdString& texturePath, unsigned int maxWidth, unsigned int maxHeight, bool autoRotate, unsigned int *originalWidth, unsigned int *originalHeight) { if (URIUtils::GetExtension(texturePath).Equals(".dds")) { // special case for DDS images CDDSImage image; if (image.ReadFile(texturePath)) { Update(image.GetWidth(), image.GetHeight(), 0, image.GetFormat(), image.GetData(), false); return true; } return false; } #if defined(__APPLE__) && defined(__arm__) XFILE::CFile file; UInt8 *imageBuff = NULL; int64_t imageBuffSize = 0; //open path and read data to buffer //this handles advancedsettings.xml pathsubstitution //and resulting networking if (file.Open(texturePath, 0)) { imageBuffSize =file.GetLength(); imageBuff = new UInt8[imageBuffSize]; imageBuffSize = file.Read(imageBuff, imageBuffSize); file.Close(); } else { CLog::Log(LOGERROR, "Texture manager unable to open file %s", texturePath.c_str()); return false; } if (imageBuffSize <= 0) { CLog::Log(LOGERROR, "Texture manager read texture file failed."); delete [] imageBuff; return false; } // create the image from buffer; CGImageSourceRef imageSource; // create a CFDataRef using CFDataCreateWithBytesNoCopy and kCFAllocatorNull for deallocator. // this allows us to do a nocopy reference and we handle the free of imageBuff CFDataRef cfdata = CFDataCreateWithBytesNoCopy(NULL, imageBuff, imageBuffSize, kCFAllocatorNull); imageSource = CGImageSourceCreateWithData(cfdata, NULL); if (imageSource == nil) { CLog::Log(LOGERROR, "Texture manager unable to load file: %s", CSpecialProtocol::TranslatePath(texturePath).c_str()); CFRelease(cfdata); delete [] imageBuff; return false; } CGImageRef image = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); int rotate = 0; if (autoRotate) { // get the orientation of the image for displaying it correctly CFDictionaryRef imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(imageSource,0, NULL); if (imagePropertiesDictionary != nil) { CFNumberRef orientation = (CFNumberRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyOrientation); if (orientation != nil) { int value = 0; CFNumberGetValue(orientation, kCFNumberIntType, &value); if (value) rotate = value - 1; } CFRelease(imagePropertiesDictionary); } } CFRelease(imageSource); unsigned int width = CGImageGetWidth(image); unsigned int height = CGImageGetHeight(image); m_hasAlpha = (CGImageGetAlphaInfo(image) != kCGImageAlphaNone); if (originalWidth) *originalWidth = width; if (originalHeight) *originalHeight = height; // check texture size limits and limit to screen size - preserving aspectratio of image if ( width > g_Windowing.GetMaxTextureSize() || height > g_Windowing.GetMaxTextureSize() ) { float aspect; if ( width > height ) { aspect = (float)width / (float)height; width = g_Windowing.GetWidth(); height = (float)width / (float)aspect; } else { aspect = (float)height / (float)width; height = g_Windowing.GetHeight(); width = (float)height / (float)aspect; } CLog::Log(LOGDEBUG, "Texture manager texture clamp:new texture size: %i x %i", width, height); } // use RGBA to skip swizzling Allocate(width, height, XB_FMT_RGBA8); m_orientation = rotate; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // hw convert jmpeg to RGBA CGContextRef context = CGBitmapContextCreate(m_pixels, width, height, 8, GetPitch(), colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); // Flip so that it isn't upside-down //CGContextTranslateCTM(context, 0, height); //CGContextScaleCTM(context, 1.0f, -1.0f); #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 CGContextClearRect(context, CGRectMake(0, 0, width, height)); #else #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 // (just a way of checking whether we're running in 10.5 or later) if (CGContextDrawLinearGradient == 0) CGContextClearRect(context, CGRectMake(0, 0, width, height)); else #endif CGContextSetBlendMode(context, kCGBlendModeCopy); #endif //CGContextSetBlendMode(context, kCGBlendModeCopy); CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); CGContextRelease(context); CGImageRelease(image); CFRelease(cfdata); delete [] imageBuff; #else DllImageLib dll; if (!dll.Load()) return false; ImageInfo image; memset(&image, 0, sizeof(image)); unsigned int width = maxWidth ? std::min(maxWidth, g_Windowing.GetMaxTextureSize()) : g_Windowing.GetMaxTextureSize(); unsigned int height = maxHeight ? std::min(maxHeight, g_Windowing.GetMaxTextureSize()) : g_Windowing.GetMaxTextureSize(); if(!dll.LoadImage(texturePath.c_str(), width, height, &image)) { CLog::Log(LOGERROR, "Texture manager unable to load file: %s", texturePath.c_str()); return false; } m_hasAlpha = NULL != image.alpha; Allocate(image.width, image.height, XB_FMT_A8R8G8B8); if (autoRotate && image.exifInfo.Orientation) m_orientation = image.exifInfo.Orientation - 1; if (originalWidth) *originalWidth = image.originalwidth; if (originalHeight) *originalHeight = image.originalheight; unsigned int dstPitch = GetPitch(); unsigned int srcPitch = ((image.width + 1)* 3 / 4) * 4; // bitmap row length is aligned to 4 bytes unsigned char *dst = m_pixels; unsigned char *src = image.texture + (m_imageHeight - 1) * srcPitch; for (unsigned int y = 0; y < m_imageHeight; y++) { unsigned char *dst2 = dst; unsigned char *src2 = src; for (unsigned int x = 0; x < m_imageWidth; x++, dst2 += 4, src2 += 3) { dst2[0] = src2[0]; dst2[1] = src2[1]; dst2[2] = src2[2]; dst2[3] = 0xff; } src -= srcPitch; dst += dstPitch; } if(image.alpha) { dst = m_pixels + 3; src = image.alpha + (m_imageHeight - 1) * m_imageWidth; for (unsigned int y = 0; y < m_imageHeight; y++) { unsigned char *dst2 = dst; unsigned char *src2 = src; for (unsigned int x = 0; x < m_imageWidth; x++, dst2+=4, src2++) *dst2 = *src2; src -= m_imageWidth; dst += dstPitch; } } dll.ReleaseImage(&image); #endif ClampToEdge(); return true; }
bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); if (NULL == imageSrc) { return false; } SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL); if (NULL == image) { return false; } SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image); const int width = SkToInt(CGImageGetWidth(image)); const int height = SkToInt(CGImageGetHeight(image)); bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } bm->lockPixels(); bm->eraseColor(SK_ColorTRANSPARENT); CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO); CFRelease(cs); CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image); CGContextRelease(cg); CGImageAlphaInfo info = CGImageGetAlphaInfo(image); switch (info) { case kCGImageAlphaNone: case kCGImageAlphaNoneSkipLast: case kCGImageAlphaNoneSkipFirst: SkASSERT(SkBitmap::ComputeIsOpaque(*bm)); bm->setAlphaType(kOpaque_SkAlphaType); break; default: // we don't know if we're opaque or not, so compute it. if (SkBitmap::ComputeIsOpaque(*bm)) { bm->setAlphaType(kOpaque_SkAlphaType); } } if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) { // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied. // Convert to unpremultiplied. for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { uint32_t* addr = bm->getAddr32(i, j); *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr); } } bm->setAlphaType(kUnpremul_SkAlphaType); } bm->unlockPixels(); return true; }
// Once we have our image, we need to get it into an SDL_Surface static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref) { /* This code is adapted from Apple's Documentation found here: * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html * Listing 9-4††Using a Quartz image as a texture source. * Unfortunately, this guide doesn't show what to do about * non-RGBA image formats so I'm making the rest up. * All this code should be scrutinized. */ size_t w = CGImageGetWidth(image_ref); size_t h = CGImageGetHeight(image_ref); CGRect rect = {{0, 0}, {w, h}}; CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image_ref); //size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref); size_t bits_per_component = 8; SDL_Surface* surface; Uint32 Amask; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; CGContextRef bitmap_context; CGBitmapInfo bitmap_info; CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); if (alpha == kCGImageAlphaNone || alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast) { bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; /* XRGB */ Amask = 0x00000000; } else { /* kCGImageAlphaFirst isn't supported */ //bitmap_info = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; /* ARGB */ bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; /* ARGB */ Amask = 0xFF000000; } Rmask = 0x00FF0000; Gmask = 0x0000FF00; Bmask = 0x000000FF; surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask, Bmask, Amask); if (surface) { // Sets up a context to be drawn to with surface->pixels as the area to be drawn to bitmap_context = CGBitmapContextCreate( surface->pixels, surface->w, surface->h, bits_per_component, surface->pitch, color_space, bitmap_info ); // Draws the image into the context's image_data CGContextDrawImage(bitmap_context, rect, image_ref); CGContextRelease(bitmap_context); // FIXME: Reverse the premultiplied alpha if ((bitmap_info & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst) { int i, j; Uint8 *p = (Uint8 *)surface->pixels; for (i = surface->h * surface->pitch/4; i--; ) { #if __LITTLE_ENDIAN__ Uint8 A = p[3]; if (A) { for (j = 0; j < 3; ++j) { p[j] = (p[j] * 255) / A; } } #else Uint8 A = p[0]; if (A) { for (j = 1; j < 4; ++j) { p[j] = (p[j] * 255) / A; } } #endif /* ENDIAN */ p += 4; } } } if (color_space) { CGColorSpaceRelease(color_space); } return surface; }
bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, Vector<uint8_t>& outputVector) { if (!image) return false; CGImageRef cgImage; RetainPtr<CGImageRef> decodedImage; if (image->data()) { ImageSource decoder(false); decoder.setData(image->data(), true); if (!decoder.frameCount()) return false; decodedImage = decoder.createFrameAtIndex(0); cgImage = decodedImage.get(); } else cgImage = image->nativeImageForCurrentFrame(); if (!cgImage) return false; size_t width = CGImageGetWidth(cgImage); size_t height = CGImageGetHeight(cgImage); if (!width || !height) return false; size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage); size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage); if (bitsPerComponent != 8 && bitsPerComponent != 16) return false; if (bitsPerPixel % bitsPerComponent) return false; size_t componentsPerPixel = bitsPerPixel / bitsPerComponent; SourceDataFormat srcDataFormat = kSourceFormatRGBA8; AlphaOp neededAlphaOp = kAlphaDoNothing; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: // This path is only accessible for MacOS earlier than 10.6.4. // This is a special case for texImage2D with HTMLCanvasElement input, // in which case image->data() should be null. ASSERT(!image->data()); if (!premultiplyAlpha) neededAlphaOp = kAlphaDoUnmultiply; switch (componentsPerPixel) { case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatAR8; else srcDataFormat = kSourceFormatAR16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatARGB8; else srcDataFormat = kSourceFormatARGB16; break; default: return false; } break; case kCGImageAlphaFirst: // This path is only accessible for MacOS earlier than 10.6.4. if (premultiplyAlpha) neededAlphaOp = kAlphaDoPremultiply; switch (componentsPerPixel) { case 1: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatA8; else srcDataFormat = kSourceFormatA16; break; case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatAR8; else srcDataFormat = kSourceFormatAR16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatARGB8; else srcDataFormat = kSourceFormatARGB16; break; default: return false; } break; case kCGImageAlphaNoneSkipFirst: // This path is only accessible for MacOS earlier than 10.6.4. switch (componentsPerPixel) { case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatAR8; else srcDataFormat = kSourceFormatAR16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatARGB8; else srcDataFormat = kSourceFormatARGB16; break; default: return false; } break; case kCGImageAlphaPremultipliedLast: // This is a special case for texImage2D with HTMLCanvasElement input, // in which case image->data() should be null. ASSERT(!image->data()); if (!premultiplyAlpha) neededAlphaOp = kAlphaDoUnmultiply; switch (componentsPerPixel) { case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRA8; else srcDataFormat = kSourceFormatRA16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRGBA8; else srcDataFormat = kSourceFormatRGBA16; break; default: return false; } break; case kCGImageAlphaLast: if (premultiplyAlpha) neededAlphaOp = kAlphaDoPremultiply; switch (componentsPerPixel) { case 1: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatA8; else srcDataFormat = kSourceFormatA16; break; case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRA8; else srcDataFormat = kSourceFormatRA16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRGBA8; else srcDataFormat = kSourceFormatRGBA16; break; default: return false; } break; case kCGImageAlphaNoneSkipLast: switch (componentsPerPixel) { case 2: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRA8; else srcDataFormat = kSourceFormatRA16; break; case 4: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRGBA8; else srcDataFormat = kSourceFormatRGBA16; break; default: return false; } break; case kCGImageAlphaNone: switch (componentsPerPixel) { case 1: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatR8; else srcDataFormat = kSourceFormatR16; break; case 3: if (bitsPerComponent == 8) srcDataFormat = kSourceFormatRGB8; else srcDataFormat = kSourceFormatRGB16; break; default: return false; } break; default: return false; } RetainPtr<CFDataRef> pixelData; pixelData.adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(cgImage))); if (!pixelData) return false; const UInt8* rgba = CFDataGetBytePtr(pixelData.get()); outputVector.resize(width * height * 4); unsigned int srcUnpackAlignment = 0; size_t bytesPerRow = CGImageGetBytesPerRow(cgImage); unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } bool rt = packPixels(rgba, srcDataFormat, width, height, srcUnpackAlignment, format, type, neededAlphaOp, outputVector.data()); return rt; }