| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "picture_utils.h" |
| #include "SkBitmap.h" |
| #include "SkColorPriv.h" |
| #include "SkHalf.h" |
| #include "SkImageEncoder.h" |
| #include "SkOSFile.h" |
| #include "SkOSPath.h" |
| #include "SkPM4fPriv.h" |
| #include "SkPicture.h" |
| #include "SkStream.h" |
| #include "SkString.h" |
| |
| #include "sk_tool_utils.h" |
| |
| namespace sk_tools { |
| void force_all_opaque(const SkBitmap& bitmap) { |
| SkASSERT(kN32_SkColorType == bitmap.colorType()); |
| if (kN32_SkColorType == bitmap.colorType()) { |
| return; |
| } |
| |
| SkAutoLockPixels lock(bitmap); |
| for (int y = 0; y < bitmap.height(); y++) { |
| for (int x = 0; x < bitmap.width(); x++) { |
| *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); |
| } |
| } |
| } |
| |
| void replace_char(SkString* str, const char oldChar, const char newChar) { |
| if (nullptr == str) { |
| return; |
| } |
| for (size_t i = 0; i < str->size(); ++i) { |
| if (oldChar == str->operator[](i)) { |
| str->operator[](i) = newChar; |
| } |
| } |
| } |
| |
| bool is_percentage(const char* const string) { |
| SkString skString(string); |
| return skString.endsWith("%"); |
| } |
| |
| void setup_bitmap(SkBitmap* bitmap, int width, int height) { |
| bitmap->allocN32Pixels(width, height); |
| bitmap->eraseColor(SK_ColorTRANSPARENT); |
| } |
| |
| bool write_bitmap_to_disk(const SkBitmap& bm, const SkString& dirPath, |
| const char *subdirOrNull, const SkString& baseName) { |
| SkString partialPath; |
| if (subdirOrNull) { |
| partialPath = SkOSPath::Join(dirPath.c_str(), subdirOrNull); |
| sk_mkdir(partialPath.c_str()); |
| } else { |
| partialPath.set(dirPath); |
| } |
| SkString fullPath = SkOSPath::Join(partialPath.c_str(), baseName.c_str()); |
| if (sk_tool_utils::EncodeImageToFile(fullPath.c_str(), bm, SkEncodedImageFormat::kPNG, 100)) { |
| return true; |
| } else { |
| SkDebugf("Failed to write the bitmap to %s.\n", fullPath.c_str()); |
| return false; |
| } |
| } |
| |
| sk_sp<SkData> encode_bitmap_for_png(SkBitmap bitmap) { |
| const int w = bitmap.width(), |
| h = bitmap.height(); |
| // PNG wants unpremultiplied 8-bit RGBA pixels (16-bit could work fine too). |
| // We leave the gamma of these bytes unspecified, to continue the status quo, |
| // which we think generally is to interpret them as sRGB. |
| |
| SkAutoTMalloc<uint32_t> rgba(w*h); |
| |
| auto srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| if (bitmap. colorType() == kN32_SkColorType && |
| bitmap.colorSpace() == srgbColorSpace.get()) { |
| // These are premul sRGB 8-bit pixels in SkPMColor order. |
| // We want unpremul sRGB 8-bit pixels in RGBA order. We'll get there via floats. |
| bitmap.lockPixels(); |
| auto px = (const uint32_t*)bitmap.getPixels(); |
| if (!px) { |
| return nullptr; |
| } |
| for (int i = 0; i < w*h; i++) { |
| Sk4f fs = Sk4f_fromS32(px[i]); // Convert up to linear floats. |
| #if defined(SK_PMCOLOR_IS_BGRA) |
| fs = SkNx_shuffle<2,1,0,3>(fs); // Shuffle to RGBA, if not there already. |
| #endif |
| float invA = 1.0f / fs[3]; |
| fs = fs * Sk4f(invA, invA, invA, 1); // Unpremultiply. |
| rgba[i] = Sk4f_toS32(fs); // Pack down to sRGB bytes. |
| } |
| |
| } else if (bitmap.colorType() == kRGBA_F16_SkColorType) { |
| // These are premul linear half-float pixels in RGBA order. |
| // We want unpremul sRGB 8-bit pixels in RGBA order. We'll get there via floats. |
| bitmap.lockPixels(); |
| auto px = (const uint64_t*)bitmap.getPixels(); |
| if (!px) { |
| return nullptr; |
| } |
| for (int i = 0; i < w*h; i++) { |
| // Convert up to linear floats. |
| Sk4f fs(SkHalfToFloat(static_cast<SkHalf>(px[i] >> (0 * 16))), |
| SkHalfToFloat(static_cast<SkHalf>(px[i] >> (1 * 16))), |
| SkHalfToFloat(static_cast<SkHalf>(px[i] >> (2 * 16))), |
| SkHalfToFloat(static_cast<SkHalf>(px[i] >> (3 * 16)))); |
| fs = Sk4f::Max(0.0f, Sk4f::Min(fs, 1.0f)); // Clamp |
| float invA = 1.0f / fs[3]; |
| fs = fs * Sk4f(invA, invA, invA, 1); // Unpremultiply. |
| rgba[i] = Sk4f_toS32(fs); // Pack down to sRGB bytes. |
| } |
| |
| } else { |
| // We "should" gamma correct in here but we don't. |
| // We want Gold to show exactly what our clients are seeing, broken gamma. |
| |
| // Convert smaller formats up to premul linear 8-bit (in SkPMColor order). |
| if (bitmap.colorType() != kN32_SkColorType) { |
| SkBitmap n32; |
| if (!bitmap.copyTo(&n32, kN32_SkColorType)) { |
| return nullptr; |
| } |
| bitmap = n32; |
| } |
| |
| // Convert premul linear 8-bit to unpremul linear 8-bit RGBA. |
| if (!bitmap.readPixels(SkImageInfo::Make(w,h, kRGBA_8888_SkColorType, |
| kUnpremul_SkAlphaType), |
| rgba, 4*w, 0,0)) { |
| return nullptr; |
| } |
| } |
| |
| return SkData::MakeFromMalloc(rgba.release(), w*h*sizeof(uint32_t)); |
| } |
| |
| } // namespace sk_tools |