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