1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // png_utils: Wrapper around libpng.
7*8975f5c5SAndroid Build Coastguard Worker //
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker #include "util/png_utils.h"
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker #include <array>
12*8975f5c5SAndroid Build Coastguard Worker #include <cstring>
13*8975f5c5SAndroid Build Coastguard Worker
14*8975f5c5SAndroid Build Coastguard Worker #include <png.h>
15*8975f5c5SAndroid Build Coastguard Worker
16*8975f5c5SAndroid Build Coastguard Worker namespace angle
17*8975f5c5SAndroid Build Coastguard Worker {
18*8975f5c5SAndroid Build Coastguard Worker namespace
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker class ScopedFILE
21*8975f5c5SAndroid Build Coastguard Worker {
22*8975f5c5SAndroid Build Coastguard Worker public:
ScopedFILE(FILE * fp)23*8975f5c5SAndroid Build Coastguard Worker ScopedFILE(FILE *fp) : mFP(fp) {}
~ScopedFILE()24*8975f5c5SAndroid Build Coastguard Worker ~ScopedFILE() { close(); }
25*8975f5c5SAndroid Build Coastguard Worker
get() const26*8975f5c5SAndroid Build Coastguard Worker FILE *get() const { return mFP; }
27*8975f5c5SAndroid Build Coastguard Worker
close()28*8975f5c5SAndroid Build Coastguard Worker void close()
29*8975f5c5SAndroid Build Coastguard Worker {
30*8975f5c5SAndroid Build Coastguard Worker if (mFP)
31*8975f5c5SAndroid Build Coastguard Worker {
32*8975f5c5SAndroid Build Coastguard Worker fclose(mFP);
33*8975f5c5SAndroid Build Coastguard Worker mFP = nullptr;
34*8975f5c5SAndroid Build Coastguard Worker }
35*8975f5c5SAndroid Build Coastguard Worker }
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker private:
38*8975f5c5SAndroid Build Coastguard Worker FILE *mFP;
39*8975f5c5SAndroid Build Coastguard Worker };
40*8975f5c5SAndroid Build Coastguard Worker } // namespace
41*8975f5c5SAndroid Build Coastguard Worker
SavePNGRGB(const char * fileName,const char * title,uint32_t width,uint32_t height,const std::vector<uint8_t> & data)42*8975f5c5SAndroid Build Coastguard Worker bool SavePNGRGB(const char *fileName,
43*8975f5c5SAndroid Build Coastguard Worker const char *title,
44*8975f5c5SAndroid Build Coastguard Worker uint32_t width,
45*8975f5c5SAndroid Build Coastguard Worker uint32_t height,
46*8975f5c5SAndroid Build Coastguard Worker const std::vector<uint8_t> &data)
47*8975f5c5SAndroid Build Coastguard Worker {
48*8975f5c5SAndroid Build Coastguard Worker ScopedFILE fp(fopen(fileName, "wb"));
49*8975f5c5SAndroid Build Coastguard Worker if (!fp.get())
50*8975f5c5SAndroid Build Coastguard Worker {
51*8975f5c5SAndroid Build Coastguard Worker fprintf(stderr, "Error opening '%s'.\n", fileName);
52*8975f5c5SAndroid Build Coastguard Worker return false;
53*8975f5c5SAndroid Build Coastguard Worker }
54*8975f5c5SAndroid Build Coastguard Worker
55*8975f5c5SAndroid Build Coastguard Worker png_struct *writeStruct =
56*8975f5c5SAndroid Build Coastguard Worker png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
57*8975f5c5SAndroid Build Coastguard Worker if (!writeStruct)
58*8975f5c5SAndroid Build Coastguard Worker {
59*8975f5c5SAndroid Build Coastguard Worker fprintf(stderr, "Error on png_create_write_struct.\n");
60*8975f5c5SAndroid Build Coastguard Worker return false;
61*8975f5c5SAndroid Build Coastguard Worker }
62*8975f5c5SAndroid Build Coastguard Worker
63*8975f5c5SAndroid Build Coastguard Worker png_info *infoStruct = png_create_info_struct(writeStruct);
64*8975f5c5SAndroid Build Coastguard Worker if (!infoStruct)
65*8975f5c5SAndroid Build Coastguard Worker {
66*8975f5c5SAndroid Build Coastguard Worker fprintf(stderr, "Error on png_create_info_struct.\n");
67*8975f5c5SAndroid Build Coastguard Worker return false;
68*8975f5c5SAndroid Build Coastguard Worker }
69*8975f5c5SAndroid Build Coastguard Worker
70*8975f5c5SAndroid Build Coastguard Worker if (setjmp(png_jmpbuf(writeStruct)))
71*8975f5c5SAndroid Build Coastguard Worker {
72*8975f5c5SAndroid Build Coastguard Worker fp.close();
73*8975f5c5SAndroid Build Coastguard Worker png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
74*8975f5c5SAndroid Build Coastguard Worker png_destroy_write_struct(&writeStruct, &infoStruct);
75*8975f5c5SAndroid Build Coastguard Worker return false;
76*8975f5c5SAndroid Build Coastguard Worker }
77*8975f5c5SAndroid Build Coastguard Worker
78*8975f5c5SAndroid Build Coastguard Worker png_init_io(writeStruct, fp.get());
79*8975f5c5SAndroid Build Coastguard Worker
80*8975f5c5SAndroid Build Coastguard Worker // Write header (8 bit colour depth)
81*8975f5c5SAndroid Build Coastguard Worker png_set_IHDR(writeStruct, infoStruct, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
82*8975f5c5SAndroid Build Coastguard Worker PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
83*8975f5c5SAndroid Build Coastguard Worker
84*8975f5c5SAndroid Build Coastguard Worker // Set title
85*8975f5c5SAndroid Build Coastguard Worker if (title != nullptr && strlen(title) > 0)
86*8975f5c5SAndroid Build Coastguard Worker {
87*8975f5c5SAndroid Build Coastguard Worker std::array<char, 50> mutableKey = {};
88*8975f5c5SAndroid Build Coastguard Worker strcpy(mutableKey.data(), "Title");
89*8975f5c5SAndroid Build Coastguard Worker std::array<char, 200> mutableText = {};
90*8975f5c5SAndroid Build Coastguard Worker strncpy(mutableText.data(), title, 199);
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker png_text titleText;
93*8975f5c5SAndroid Build Coastguard Worker titleText.compression = PNG_TEXT_COMPRESSION_NONE;
94*8975f5c5SAndroid Build Coastguard Worker titleText.key = mutableKey.data();
95*8975f5c5SAndroid Build Coastguard Worker titleText.text = mutableText.data();
96*8975f5c5SAndroid Build Coastguard Worker png_set_text(writeStruct, infoStruct, &titleText, 1);
97*8975f5c5SAndroid Build Coastguard Worker }
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker png_write_info(writeStruct, infoStruct);
100*8975f5c5SAndroid Build Coastguard Worker
101*8975f5c5SAndroid Build Coastguard Worker // RGB 3-byte stride.
102*8975f5c5SAndroid Build Coastguard Worker const uint32_t rowStride = width * 3;
103*8975f5c5SAndroid Build Coastguard Worker for (uint32_t row = 0; row < height; ++row)
104*8975f5c5SAndroid Build Coastguard Worker {
105*8975f5c5SAndroid Build Coastguard Worker uint32_t rowOffset = row * rowStride;
106*8975f5c5SAndroid Build Coastguard Worker png_write_row(writeStruct, &data[rowOffset]);
107*8975f5c5SAndroid Build Coastguard Worker }
108*8975f5c5SAndroid Build Coastguard Worker
109*8975f5c5SAndroid Build Coastguard Worker png_write_end(writeStruct, infoStruct);
110*8975f5c5SAndroid Build Coastguard Worker
111*8975f5c5SAndroid Build Coastguard Worker fp.close();
112*8975f5c5SAndroid Build Coastguard Worker png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
113*8975f5c5SAndroid Build Coastguard Worker png_destroy_write_struct(&writeStruct, &infoStruct);
114*8975f5c5SAndroid Build Coastguard Worker return true;
115*8975f5c5SAndroid Build Coastguard Worker }
116*8975f5c5SAndroid Build Coastguard Worker } // namespace angle
117