SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, const SkSurfaceProps& surfaceProps) { SkAlphaType newAT = origInfo.alphaType(); if (!valid_for_bitmap_device(origInfo, &newAT)) { return nullptr; } const SkImageInfo info = origInfo.makeAlphaType(newAT); SkBitmap bitmap; if (kUnknown_SkColorType == info.colorType()) { if (!bitmap.setInfo(info)) { return nullptr; } } else if (info.isOpaque()) { // If this bitmap is opaque, we don't have any sensible default color, // so we just return uninitialized pixels. if (!bitmap.tryAllocPixels(info)) { return nullptr; } } else { // This bitmap has transparency, so we'll zero the pixels (to transparent). // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). SkMallocPixelRef::ZeroedPRFactory factory; if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) { return nullptr; } } return new SkBitmapDevice(bitmap, surfaceProps); }
bool allocHandle(const SkImageInfo& info, Rec* rec) override { SkASSERT(info.colorType() == kN32_SkColorType); return Create(info.width(), info.height(), info.isOpaque(), rec); }
bool SkJpegEncoderMgr::setParams(const SkImageInfo& srcInfo, const SkJpegEncoder::Options& options) { auto chooseProc8888 = [&]() { if (kUnpremul_SkAlphaType != srcInfo.alphaType() || SkJpegEncoder::AlphaOption::kIgnore == options.fAlphaOption) { return (transform_scanline_proc) nullptr; } // Note that kRespect mode is only supported with sRGB or linear transfer functions. // The legacy code path is incidentally correct when the transfer function is linear. const bool isSRGBTransferFn = srcInfo.gammaCloseToSRGB() && (SkTransferFunctionBehavior::kRespect == options.fBlendBehavior); if (isSRGBTransferFn) { return transform_scanline_to_premul_linear; } else { return transform_scanline_to_premul_legacy; } }; J_COLOR_SPACE jpegColorType = JCS_EXT_RGBA; int numComponents = 0; switch (srcInfo.colorType()) { case kRGBA_8888_SkColorType: fProc = chooseProc8888(); jpegColorType = JCS_EXT_RGBA; numComponents = 4; break; case kBGRA_8888_SkColorType: fProc = chooseProc8888(); jpegColorType = JCS_EXT_BGRA; numComponents = 4; break; case kRGB_565_SkColorType: fProc = transform_scanline_565; jpegColorType = JCS_RGB; numComponents = 3; break; case kARGB_4444_SkColorType: if (SkJpegEncoder::AlphaOption::kBlendOnBlack == options.fAlphaOption) { return false; } fProc = transform_scanline_444; jpegColorType = JCS_RGB; numComponents = 3; break; case kGray_8_SkColorType: SkASSERT(srcInfo.isOpaque()); jpegColorType = JCS_GRAYSCALE; numComponents = 1; break; case kRGBA_F16_SkColorType: if (!srcInfo.colorSpace() || !srcInfo.colorSpace()->gammaIsLinear() || SkTransferFunctionBehavior::kRespect != options.fBlendBehavior) { return false; } if (kUnpremul_SkAlphaType != srcInfo.alphaType() || SkJpegEncoder::AlphaOption::kIgnore == options.fAlphaOption) { fProc = transform_scanline_F16_to_8888; } else { fProc = transform_scanline_F16_to_premul_8888; } jpegColorType = JCS_EXT_RGBA; numComponents = 4; break; default: return false; } fCInfo.image_width = srcInfo.width(); fCInfo.image_height = srcInfo.height(); fCInfo.in_color_space = jpegColorType; fCInfo.input_components = numComponents; jpeg_set_defaults(&fCInfo); if (kGray_8_SkColorType != srcInfo.colorType()) { switch (options.fDownsample) { case SkJpegEncoder::Downsample::k420: SkASSERT(2 == fCInfo.comp_info[0].h_samp_factor); SkASSERT(2 == fCInfo.comp_info[0].v_samp_factor); SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor); SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor); SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor); SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor); break; case SkJpegEncoder::Downsample::k422: fCInfo.comp_info[0].h_samp_factor = 2; fCInfo.comp_info[0].v_samp_factor = 1; fCInfo.comp_info[1].h_samp_factor = 1; fCInfo.comp_info[1].v_samp_factor = 1; fCInfo.comp_info[2].h_samp_factor = 1; fCInfo.comp_info[2].v_samp_factor = 1; break; case SkJpegEncoder::Downsample::k444: fCInfo.comp_info[0].h_samp_factor = 1; fCInfo.comp_info[0].v_samp_factor = 1; fCInfo.comp_info[1].h_samp_factor = 1; fCInfo.comp_info[1].v_samp_factor = 1; fCInfo.comp_info[2].h_samp_factor = 1; fCInfo.comp_info[2].v_samp_factor = 1; break; } } // Tells libjpeg-turbo to compute optimal Huffman coding tables // for the image. This improves compression at the cost of // slower encode performance. fCInfo.optimize_coding = TRUE; return true; }
bool SkPngEncoderMgr::setHeader(const SkImageInfo& srcInfo, const SkPngEncoder::Options& options) { if (setjmp(png_jmpbuf(fPngPtr))) { return false; } int pngColorType; png_color_8 sigBit; int bitDepth = 8; switch (srcInfo.colorType()) { case kRGBA_F16_SkColorType: case kRGBA_F32_SkColorType: sigBit.red = 16; sigBit.green = 16; sigBit.blue = 16; sigBit.alpha = 16; bitDepth = 16; pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; fPngBytesPerPixel = 8; break; case kGray_8_SkColorType: sigBit.gray = 8; pngColorType = PNG_COLOR_TYPE_GRAY; fPngBytesPerPixel = 1; SkASSERT(srcInfo.isOpaque()); break; case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: sigBit.red = 8; sigBit.green = 8; sigBit.blue = 8; sigBit.alpha = 8; pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; fPngBytesPerPixel = srcInfo.isOpaque() ? 3 : 4; break; case kRGB_888x_SkColorType: sigBit.red = 8; sigBit.green = 8; sigBit.blue = 8; pngColorType = PNG_COLOR_TYPE_RGB; fPngBytesPerPixel = 3; SkASSERT(srcInfo.isOpaque()); break; case kARGB_4444_SkColorType: if (kUnpremul_SkAlphaType == srcInfo.alphaType()) { return false; } sigBit.red = 4; sigBit.green = 4; sigBit.blue = 4; sigBit.alpha = 4; pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; fPngBytesPerPixel = srcInfo.isOpaque() ? 3 : 4; break; case kRGB_565_SkColorType: sigBit.red = 5; sigBit.green = 6; sigBit.blue = 5; pngColorType = PNG_COLOR_TYPE_RGB; fPngBytesPerPixel = 3; SkASSERT(srcInfo.isOpaque()); break; case kAlpha_8_SkColorType: // store as gray+alpha, but ignore gray sigBit.gray = kGraySigBit_GrayAlphaIsJustAlpha; sigBit.alpha = 8; pngColorType = PNG_COLOR_TYPE_GRAY_ALPHA; fPngBytesPerPixel = 2; break; case kRGBA_1010102_SkColorType: bitDepth = 16; sigBit.red = 10; sigBit.green = 10; sigBit.blue = 10; sigBit.alpha = 2; pngColorType = srcInfo.isOpaque() ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; fPngBytesPerPixel = 8; break; case kRGB_101010x_SkColorType: bitDepth = 16; sigBit.red = 10; sigBit.green = 10; sigBit.blue = 10; pngColorType = PNG_COLOR_TYPE_RGB; fPngBytesPerPixel = 6; break; default: return false; } png_set_IHDR(fPngPtr, fInfoPtr, srcInfo.width(), srcInfo.height(), bitDepth, pngColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_set_sBIT(fPngPtr, fInfoPtr, &sigBit); int filters = (int)options.fFilterFlags & (int)SkPngEncoder::FilterFlag::kAll; SkASSERT(filters == (int)options.fFilterFlags); png_set_filter(fPngPtr, PNG_FILTER_TYPE_BASE, filters); int zlibLevel = SkTMin(SkTMax(0, options.fZLibLevel), 9); SkASSERT(zlibLevel == options.fZLibLevel); png_set_compression_level(fPngPtr, zlibLevel); // Set comments in tEXt chunk const sk_sp<SkDataTable>& comments = options.fComments; if (comments != nullptr) { std::vector<png_text> png_texts(comments->count()); std::vector<SkString> clippedKeys; for (int i = 0; i < comments->count() / 2; ++i) { const char* keyword; const char* originalKeyword = comments->atStr(2 * i); const char* text = comments->atStr(2 * i + 1); if (strlen(originalKeyword) <= PNG_KEYWORD_MAX_LENGTH) { keyword = originalKeyword; } else { SkDEBUGFAILF("PNG tEXt keyword should be no longer than %d.", PNG_KEYWORD_MAX_LENGTH); clippedKeys.emplace_back(originalKeyword, PNG_KEYWORD_MAX_LENGTH); keyword = clippedKeys.back().c_str(); } // It seems safe to convert png_const_charp to png_charp for key/text, // and we don't have to provide text_length and other fields as we're providing // 0-terminated c_str with PNG_TEXT_COMPRESSION_NONE (no compression, no itxt). png_texts[i].compression = PNG_TEXT_COMPRESSION_NONE; png_texts[i].key = (png_charp)keyword; png_texts[i].text = (png_charp)text; } png_set_text(fPngPtr, fInfoPtr, png_texts.data(), png_texts.size()); } return true; }