1 // Copyright 2019 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4 #include "include/codec/SkCodec.h"
5 #include "include/core/SkBitmap.h"
6 #include "include/encode/SkPngEncoder.h"
7 #include "src/core/SkOSFile.h"
8
update(SkBitmap* maxBitmap, SkBitmap* minBitmap, const SkBitmap& bm)9 static bool update(SkBitmap* maxBitmap, SkBitmap* minBitmap, const SkBitmap& bm) {
10 SkASSERT(!bm.drawsNothing());
11 SkASSERT(4 == bm.bytesPerPixel());
12 if (maxBitmap->drawsNothing()) {
13 maxBitmap->allocPixels(bm.info());
14 maxBitmap->eraseColor(0x00000000);
15 minBitmap->allocPixels(bm.info());
16 minBitmap->eraseColor(0xFFFFFFFF);
17 }
18 if (maxBitmap->dimensions() != bm.dimensions()) {
19 return false;
20 }
21 SkASSERT_RELEASE(maxBitmap->info() == bm.info());
22 const SkPixmap& pmin = minBitmap->pixmap();
23 const SkPixmap& pmax = maxBitmap->pixmap();
24 const SkPixmap& pm = bm.pixmap();
25 for (int y = 0; y < pm.height(); ++y) {
26 for (int x = 0; x < pm.width(); ++x) {
27 uint32_t* minPtr = pmin.writable_addr32(x, y);
28 uint32_t* maxPtr = pmax.writable_addr32(x, y);
29 uint8_t minColor[4], maxColor[4], color[4];
30 memcpy(minColor, minPtr, 4);
31 memcpy(maxColor, maxPtr, 4);
32 memcpy(color, pm.addr32(x, y), 4);
33 for (unsigned i = 0; i < 4; ++i) {
34 minColor[i] = std::min(minColor[i], color[i]);
35 maxColor[i] = std::max(maxColor[i], color[i]);
36 }
37 memcpy(minPtr, minColor, 4);
38 memcpy(maxPtr, maxColor, 4);
39 }
40 }
41 return true;
42 }
43
decode_to_srgb_8888_unpremul(const char* path)44 static SkBitmap decode_to_srgb_8888_unpremul(const char* path) {
45 SkBitmap dst;
46 if (auto codec = SkCodec::MakeFromData(SkData::MakeFromFileName(path))) {
47 SkISize size = codec->getInfo().dimensions();
48 SkASSERT(!size.isEmpty());
49 dst.allocPixels(SkImageInfo::Make(
50 size.width(), size.height(), kRGBA_8888_SkColorType,
51 kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()));
52 if (SkCodec::kSuccess != codec->getPixels(dst.pixmap())) {
53 dst.reset();
54 }
55 }
56 return dst;
57 }
58
encode_png(const char* path, const SkPixmap& pixmap)59 bool encode_png(const char* path, const SkPixmap& pixmap) {
60 if (!pixmap.addr()) {
61 return false;
62 }
63 SkPngEncoder::Options encOpts;
64 encOpts.fZLibLevel = 9; // slow encode;
65 SkFILEWStream o(path);
66 return o.isValid() && SkPngEncoder::Encode(&o, pixmap, encOpts);
67 }
68
main(int argc, char** argv)69 int main(int argc, char** argv) {
70 SkASSERT_RELEASE(argc > 2);
71 const char* src_dir = argv[1];
72 const char* dst_dir = argv[2];
73 SkBitmap maxBitmap, minBitmap;
74 SkOSFile::Iter iter(src_dir);
75 SkString name;
76 while (iter.next(&name)) {
77 name.prependf("%s/", src_dir);
78 SkBitmap bm = decode_to_srgb_8888_unpremul(name.c_str());
79 if (bm.drawsNothing()) {
80 SkDebugf("'%s' failed to decode.\n", name.c_str());
81 continue;
82 }
83 if (!update(&maxBitmap, &minBitmap, bm)) {
84 SkDebugf("'%s' has unmatched dimensions.\n", name.c_str());
85 continue;
86 }
87 }
88 SkASSERT_RELEASE(sk_mkdir(dst_dir));
89 if ((maxBitmap.drawsNothing()) || (maxBitmap.drawsNothing())) {
90 SkDebugf("Failure: '%s' '%s'\n", src_dir, dst_dir);
91 return 1;
92 }
93 encode_png(SkStringPrintf("%s/min.png", dst_dir).c_str(), minBitmap.pixmap());
94 encode_png(SkStringPrintf("%s/max.png", dst_dir).c_str(), maxBitmap.pixmap());
95 return 0;
96 }
97