bool GraphicsContext3D::getImageData(Image* image, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) { UNUSED_PARAM(ignoreGammaAndColorProfile); if (!image) return false; QImage nativeImage; // Is image already loaded? If not, load it. if (image->data()) nativeImage = QImage::fromData(reinterpret_cast<const uchar*>(image->data()->data()), image->data()->size()).convertToFormat(QImage::Format_ARGB32); else { QPixmap* nativePixmap = image->nativeImageForCurrentFrame(); nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32); } AlphaOp neededAlphaOp = AlphaDoNothing; if (premultiplyAlpha) neededAlphaOp = AlphaDoPremultiply; unsigned int packedSize; // Output data is tightly packed (alignment == 1). if (computeImageSizeInBytes(format, type, image->width(), image->height(), 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) return false; outputVector.resize(packedSize); return packPixels(nativeImage.bits(), SourceFormatBGRA8, image->width(), image->height(), 0, format, type, neededAlphaOp, outputVector.data()); }
bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, Vector<uint8_t>& outputVector) { if (!image || !image->data()) return false; ImageSource decoder(false); decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; bool hasAlpha = decoder.frameHasAlphaAtIndex(0); OwnPtr<NativeImageSkia> pixels(decoder.createFrameAtIndex(0)); if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) return false; SkBitmap::Config skiaConfig = pixels->config(); if (skiaConfig != SkBitmap::kARGB_8888_Config) return false; SkBitmap& skiaImageRef = *pixels; SkAutoLockPixels lock(skiaImageRef); ASSERT(pixels->rowBytes() == pixels->width() * 4); outputVector.resize(pixels->rowBytes() * pixels->height()); AlphaOp neededAlphaOp = kAlphaDoNothing; if (hasAlpha && premultiplyAlpha) neededAlphaOp = kAlphaDoPremultiply; return packPixels(reinterpret_cast<const uint8_t*>(pixels->getPixels()), kSourceFormatBGRA8, pixels->width(), pixels->height(), 0, format, type, neededAlphaOp, outputVector.data()); }
TEST_F(WebGLImageConversionTest, ConvertRGBA8toR8) { uint8_t sourceData[40] = {0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56}; uint8_t expectedData[10] = {0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a}; uint8_t destinationData[10]; packPixels(sourceData, WebGLImageConversion::DataFormatR8, 10, destinationData); EXPECT_EQ(0, memcmp(expectedData, destinationData, sizeof(destinationData))); }
TEST_F(WebGLImageConversionTest, ConvertRGBA8ToRGB565) { uint8_t sourceData[40] = {0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56, 0x34, 0x56}; uint16_t expectedData[10] = {0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6, 0x32a6}; uint16_t destinationData[10]; packPixels(sourceData, WebGLImageConversion::DataFormatRGB565, 10, reinterpret_cast<uint8_t*>(&destinationData[0])); EXPECT_EQ(0, memcmp(expectedData, destinationData, sizeof(destinationData))); }
bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) { if (!image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. ImageSource decoder(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); AlphaOp alphaOp = AlphaDoNothing; RefPtr<cairo_surface_t> imageSurface; if (image->data()) { decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; OwnPtr<NativeImageCairo> nativeImage = adoptPtr(decoder.createFrameAtIndex(0)); imageSurface = nativeImage->surface(); } else { imageSurface = image->nativeImageForCurrentFrame()->surface(); if (!premultiplyAlpha) alphaOp = AlphaDoUnmultiply; } if (!imageSurface) return false; int width = cairo_image_surface_get_width(imageSurface.get()); int height = cairo_image_surface_get_height(imageSurface.get()); if (!width || !height) return false; if (cairo_image_surface_get_format(imageSurface.get()) != CAIRO_FORMAT_ARGB32) return false; unsigned int srcUnpackAlignment = 1; size_t bytesPerRow = cairo_image_surface_get_stride(imageSurface.get()); size_t bitsPerPixel = 32; unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } unsigned int packedSize; // Output data is tightly packed (alignment == 1). if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) return false; outputVector.resize(packedSize); return packPixels(cairo_image_surface_get_data(imageSurface.get()), SourceFormatBGRA8, width, height, srcUnpackAlignment, format, type, alphaOp, outputVector.data()); }
bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int height, GC3Denum format, GC3Denum type, unsigned int unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, Vector<uint8_t>& data) { // Assumes format, type, etc. have already been validated. DataFormat sourceDataFormat = getDataFormat(format, type); // Resize the output buffer. unsigned int componentsPerPixel, bytesPerComponent; if (!computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent)) return false; unsigned int bytesPerPixel = componentsPerPixel * bytesPerComponent; data.resize(width * height * bytesPerPixel); if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width, height, unpackAlignment, format, type, (premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing), data.data(), flipY)) return false; return true; }
bool GraphicsContext3D::packImageData( Image* image, const void* pixels, GC3Denum format, GC3Denum type, bool flipY, AlphaOp alphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector<uint8_t>& data) { if (!pixels) return false; unsigned packedSize; // Output data is tightly packed (alignment == 1). if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) return false; data.resize(packedSize); if (!packPixels(reinterpret_cast<const uint8_t*>(pixels), sourceFormat, width, height, sourceUnpackAlignment, format, type, alphaOp, data.data(), flipY)) return false; if (ImageObserver* observer = image->imageObserver()) observer->didDraw(image); return true; }
bool GraphicsContext3D::getImageData(Image* image, GC3Denum format, GC3Denum type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) { if (!image) return false; OwnPtr<NativeImageSkia> pixels; NativeImageSkia* skiaImage = 0; AlphaOp neededAlphaOp = AlphaDoNothing; bool hasAlpha = image->isBitmapImage() ? static_cast<BitmapImage*>(image)->frameHasAlphaAtIndex(0) : true; if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); // Attempt to get raw unpremultiplied image data decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; hasAlpha = decoder.frameHasAlphaAtIndex(0); pixels = adoptPtr(decoder.createFrameAtIndex(0)); if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) return false; SkBitmap::Config skiaConfig = pixels->config(); if (skiaConfig != SkBitmap::kARGB_8888_Config) return false; skiaImage = pixels.get(); if (hasAlpha && premultiplyAlpha) neededAlphaOp = AlphaDoPremultiply; } else { skiaImage = image->nativeImageForCurrentFrame(); if (!premultiplyAlpha && hasAlpha) neededAlphaOp = AlphaDoUnmultiply; } if (!skiaImage) return false; SkBitmap& skiaImageRef = *skiaImage; SkAutoLockPixels lock(skiaImageRef); ASSERT(skiaImage->rowBytes() == skiaImage->width() * 4); outputVector.resize(skiaImage->rowBytes() * skiaImage->height()); return packPixels(reinterpret_cast<const uint8_t*>(skiaImage->getPixels()), SourceFormatBGRA8, skiaImage->width(), skiaImage->height(), 0, format, type, neededAlphaOp, outputVector.data()); }
bool GraphicsContext3D::extractImageData(ImageData* imageData, GC3Denum format, GC3Denum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data) { if (!imageData) return false; int width = imageData->width(); int height = imageData->height(); unsigned int packedSize; // Output data is tightly packed (alignment == 1). if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) return false; data.resize(packedSize); if (!packPixels(imageData->data()->data(), DataFormatRGBA8, width, height, 0, format, type, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing, data.data(), flipY)) return false; return true; }
bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector) { if (!image) return false; OwnPtr<NativeImageSkia> pixels; NativeImageSkia* skiaImage = 0; AlphaOp neededAlphaOp = AlphaDoNothing; if (image->data()) { ImageSource decoder(ImageSource::AlphaNotPremultiplied, ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied); decoder.setData(image->data(), true); if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0)) return false; bool hasAlpha = decoder.frameHasAlphaAtIndex(0); pixels = adoptPtr(decoder.createFrameAtIndex(0)); if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height()) return false; SkBitmap::Config skiaConfig = pixels->config(); if (skiaConfig != SkBitmap::kARGB_8888_Config) return false; skiaImage = pixels.get(); if (hasAlpha && premultiplyAlpha) neededAlphaOp = AlphaDoPremultiply; } else { // This is a special case for texImage2D with HTMLCanvasElement input. skiaImage = image->nativeImageForCurrentFrame(); if (!premultiplyAlpha) neededAlphaOp = AlphaDoUnmultiply; } if (!skiaImage) return false; SkBitmap& skiaImageRef = *skiaImage; SkAutoLockPixels lock(skiaImageRef); ASSERT(skiaImage->rowBytes() == skiaImage->width() * 4); outputVector.resize(skiaImage->rowBytes() * skiaImage->height()); return packPixels(reinterpret_cast<const uint8_t*>(skiaImage->getPixels()), SourceFormatBGRA8, skiaImage->width(), skiaImage->height(), 0, format, type, neededAlphaOp, outputVector.data()); }
void IFFDecoder::loadBitmap(Common::SeekableReadStream &stream) { _numRelevantPlanes = MIN(_numRelevantPlanes, _header.numPlanes); if (_numRelevantPlanes != 1 && _numRelevantPlanes != 2 && _numRelevantPlanes != 4) _pixelPacking = false; uint16 outPitch = _header.width; if (_pixelPacking) outPitch /= (8 / _numRelevantPlanes); // FIXME: CLUT8 is not a proper format for packed bitmaps but there is no way to tell it to use 1, 2 or 4 bits per pixel _surface = new Graphics::Surface(); _surface->create(outPitch, _header.height, Graphics::PixelFormat::createFormatCLUT8()); if (_type == TYPE_ILBM) { uint32 scanlinePitch = ((_header.width + 15) >> 4) << 1; byte *scanlines = new byte[scanlinePitch * _header.numPlanes]; byte *data = (byte *)_surface->getPixels(); for (uint16 i = 0; i < _header.height; ++i) { byte *scanline = scanlines; for (uint16 j = 0; j < _header.numPlanes; ++j) { uint16 outSize = scanlinePitch; if (_header.compression) { Common::PackBitsReadStream packStream(stream); packStream.read(scanline, outSize); } else { stream.read(scanline, outSize); } scanline += outSize; } packPixels(scanlines, data, scanlinePitch, outPitch); data += outPitch; } delete[] scanlines; } else if (_type == TYPE_PBM) {
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; }