blob: 13e45ab609d37f48c7ce586442d716acd99f74d0 [file] [log] [blame]
scroggof24f2242015-03-03 08:59:20 -08001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
msarettad8bcfe2016-03-07 07:09:03 -08008#include "SkBitmap.h"
msarett74114382015-03-16 11:55:18 -07009#include "SkCodecPriv.h"
scroggof24f2242015-03-03 08:59:20 -080010#include "SkColorPriv.h"
Matt Sarettc434f512016-10-13 18:24:20 -040011#include "SkColorSpace.h"
Matt Sarett5dfb4e42017-01-04 09:41:09 -050012#include "SkColorSpacePriv.h"
scroggof24f2242015-03-03 08:59:20 -080013#include "SkColorTable.h"
scroggof24f2242015-03-03 08:59:20 -080014#include "SkMath.h"
msarett13a91232016-02-01 08:03:29 -080015#include "SkOpts.h"
msarettbe1d5552016-01-21 09:05:23 -080016#include "SkPngCodec.h"
msarett55447952016-07-22 14:07:23 -070017#include "SkPoint3.h"
scroggof24f2242015-03-03 08:59:20 -080018#include "SkSize.h"
19#include "SkStream.h"
20#include "SkSwizzler.h"
scroggo565901d2015-12-10 10:44:13 -080021#include "SkTemplates.h"
bungeman5d2cd6e2016-02-23 07:34:25 -080022#include "SkUtils.h"
scroggof24f2242015-03-03 08:59:20 -080023
mtklein63213812016-08-24 09:55:56 -070024#include "png.h"
Leon Scroggins III83239652017-04-21 13:47:12 -040025#include <algorithm>
mtklein63213812016-08-24 09:55:56 -070026
mtkleindc90b532016-07-28 14:45:28 -070027// This warning triggers false postives way too often in here.
28#if defined(__GNUC__) && !defined(__clang__)
29 #pragma GCC diagnostic ignored "-Wclobbered"
30#endif
31
scroggo8e6c7ad2016-09-16 08:20:38 -070032// FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6
33#define PNG_JMPBUF(x) png_jmpbuf((png_structp) x)
34
scroggof24f2242015-03-03 08:59:20 -080035///////////////////////////////////////////////////////////////////////////////
scroggof24f2242015-03-03 08:59:20 -080036// Callback functions
37///////////////////////////////////////////////////////////////////////////////
38
scroggo8e6c7ad2016-09-16 08:20:38 -070039// When setjmp is first called, it returns 0, meaning longjmp was not called.
40constexpr int kSetJmpOkay = 0;
41// An error internal to libpng.
42constexpr int kPngError = 1;
43// Passed to longjmp when we have decoded as many lines as we need.
44constexpr int kStopDecoding = 2;
45
scroggof24f2242015-03-03 08:59:20 -080046static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
scroggo230d4ac2015-03-26 07:15:55 -070047 SkCodecPrintf("------ png error %s\n", msg);
scroggo8e6c7ad2016-09-16 08:20:38 -070048 longjmp(PNG_JMPBUF(png_ptr), kPngError);
scroggof24f2242015-03-03 08:59:20 -080049}
50
scroggo0eed6df2015-03-26 10:07:56 -070051void sk_warning_fn(png_structp, png_const_charp msg) {
52 SkCodecPrintf("----- png warning %s\n", msg);
53}
54
scroggocf98fa92015-11-23 08:14:40 -080055#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
56static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
57 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
58 // readChunk() returning true means continue decoding
59 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1;
60}
61#endif
62
scroggof24f2242015-03-03 08:59:20 -080063///////////////////////////////////////////////////////////////////////////////
64// Helpers
65///////////////////////////////////////////////////////////////////////////////
66
67class AutoCleanPng : public SkNoncopyable {
68public:
scroggo8e6c7ad2016-09-16 08:20:38 -070069 /*
70 * This class does not take ownership of stream or reader, but if codecPtr
71 * is non-NULL, and decodeBounds succeeds, it will have created a new
72 * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as
73 * the png_ptr and info_ptr.
74 */
75 AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader,
76 SkCodec** codecPtr)
scroggof24f2242015-03-03 08:59:20 -080077 : fPng_ptr(png_ptr)
scroggo8e6c7ad2016-09-16 08:20:38 -070078 , fInfo_ptr(nullptr)
scroggo8e6c7ad2016-09-16 08:20:38 -070079 , fStream(stream)
80 , fChunkReader(reader)
81 , fOutCodec(codecPtr)
82 {}
scroggof24f2242015-03-03 08:59:20 -080083
84 ~AutoCleanPng() {
halcanary96fcdcc2015-08-27 07:41:13 -070085 // fInfo_ptr will never be non-nullptr unless fPng_ptr is.
scroggof24f2242015-03-03 08:59:20 -080086 if (fPng_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -070087 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
msarett13a91232016-02-01 08:03:29 -080088 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
scroggof24f2242015-03-03 08:59:20 -080089 }
90 }
91
92 void setInfoPtr(png_infop info_ptr) {
halcanary96fcdcc2015-08-27 07:41:13 -070093 SkASSERT(nullptr == fInfo_ptr);
scroggof24f2242015-03-03 08:59:20 -080094 fInfo_ptr = info_ptr;
95 }
96
scroggo8e6c7ad2016-09-16 08:20:38 -070097 /**
98 * Reads enough of the input stream to decode the bounds.
99 * @return false if the stream is not a valid PNG (or too short).
100 * true if it read enough of the stream to determine the bounds.
101 * In the latter case, the stream may have been read beyond the
102 * point to determine the bounds, and the png_ptr will have saved
103 * any extra data. Further, if the codecPtr supplied to the
104 * constructor was not NULL, it will now point to a new SkCodec,
105 * which owns (or refs, in the case of the SkPngChunkReader) the
106 * inputs. If codecPtr was NULL, the png_ptr and info_ptr are
107 * unowned, and it is up to the caller to destroy them.
108 */
109 bool decodeBounds();
110
111private:
112 png_structp fPng_ptr;
113 png_infop fInfo_ptr;
scroggo8e6c7ad2016-09-16 08:20:38 -0700114 SkStream* fStream;
115 SkPngChunkReader* fChunkReader;
116 SkCodec** fOutCodec;
117
Leon Scroggins III83239652017-04-21 13:47:12 -0400118 void infoCallback(size_t idatLength);
scroggo8e6c7ad2016-09-16 08:20:38 -0700119
scroggo8e6c7ad2016-09-16 08:20:38 -0700120 void releasePngPtrs() {
halcanary96fcdcc2015-08-27 07:41:13 -0700121 fPng_ptr = nullptr;
122 fInfo_ptr = nullptr;
scroggof24f2242015-03-03 08:59:20 -0800123 }
scroggof24f2242015-03-03 08:59:20 -0800124};
125#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
126
Leon Scroggins III83239652017-04-21 13:47:12 -0400127static inline bool is_chunk(const png_byte* chunk, const char* tag) {
128 return memcmp(chunk + 4, tag, 4) == 0;
129}
130
131static inline bool process_data(png_structp png_ptr, png_infop info_ptr,
132 SkStream* stream, void* buffer, size_t bufferSize, size_t length) {
133 while (length > 0) {
134 const size_t bytesToProcess = std::min(bufferSize, length);
Leon Scroggins IIIb6446502017-04-24 09:32:50 -0400135 const size_t bytesRead = stream->read(buffer, bytesToProcess);
136 png_process_data(png_ptr, info_ptr, (png_bytep) buffer, bytesRead);
137 if (bytesRead < bytesToProcess) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400138 return false;
139 }
Leon Scroggins III83239652017-04-21 13:47:12 -0400140 length -= bytesToProcess;
141 }
142 return true;
143}
144
scroggo8e6c7ad2016-09-16 08:20:38 -0700145bool AutoCleanPng::decodeBounds() {
146 if (setjmp(PNG_JMPBUF(fPng_ptr))) {
147 return false;
148 }
149
Leon Scroggins III83239652017-04-21 13:47:12 -0400150 png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700151
152 // Arbitrary buffer size, though note that it matches (below)
153 // SkPngCodec::processData(). FIXME: Can we better suit this to the size of
154 // the PNG header?
155 constexpr size_t kBufferSize = 4096;
156 char buffer[kBufferSize];
157
Leon Scroggins III83239652017-04-21 13:47:12 -0400158 {
159 // Parse the signature.
160 if (fStream->read(buffer, 8) < 8) {
161 return false;
162 }
163
164 png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, 8);
165 }
166
scroggo8e6c7ad2016-09-16 08:20:38 -0700167 while (true) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400168 // Parse chunk length and type.
169 if (fStream->read(buffer, 8) < 8) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700170 // We have read to the end of the input without decoding bounds.
171 break;
172 }
173
Leon Scroggins III83239652017-04-21 13:47:12 -0400174 png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
175 const size_t length = png_get_uint_32(chunk);
176
177 if (is_chunk(chunk, "IDAT")) {
178 this->infoCallback(length);
179 return true;
180 }
181
182 png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
183 // Process the full chunk + CRC.
184 if (!process_data(fPng_ptr, fInfo_ptr, fStream, buffer, kBufferSize, length + 4)) {
185 return false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700186 }
187 }
188
Leon Scroggins III83239652017-04-21 13:47:12 -0400189 return false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700190}
191
192void SkPngCodec::processData() {
193 switch (setjmp(PNG_JMPBUF(fPng_ptr))) {
194 case kPngError:
195 // There was an error. Stop processing data.
196 // FIXME: Do we need to discard png_ptr?
197 return;
198 case kStopDecoding:
199 // We decoded all the lines we want.
200 return;
201 case kSetJmpOkay:
202 // Everything is okay.
203 break;
204 default:
205 // No other values should be passed to longjmp.
206 SkASSERT(false);
207 }
208
209 // Arbitrary buffer size
210 constexpr size_t kBufferSize = 4096;
211 char buffer[kBufferSize];
212
Leon Scroggins III83239652017-04-21 13:47:12 -0400213 bool iend = false;
scroggo8e6c7ad2016-09-16 08:20:38 -0700214 while (true) {
Leon Scroggins III83239652017-04-21 13:47:12 -0400215 size_t length;
216 if (fDecodedIdat) {
217 // Parse chunk length and type.
218 if (this->stream()->read(buffer, 8) < 8) {
219 break;
220 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700221
Leon Scroggins III83239652017-04-21 13:47:12 -0400222 png_byte* chunk = reinterpret_cast<png_byte*>(buffer);
223 png_process_data(fPng_ptr, fInfo_ptr, chunk, 8);
224 if (is_chunk(chunk, "IEND")) {
225 iend = true;
226 }
227
228 length = png_get_uint_32(chunk);
229 } else {
230 length = fIdatLength;
231 png_byte idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'};
232 png_save_uint_32(idat, length);
233 png_process_data(fPng_ptr, fInfo_ptr, idat, 8);
234 fDecodedIdat = true;
235 }
236
237 // Process the full chunk + CRC.
238 if (!process_data(fPng_ptr, fInfo_ptr, this->stream(), buffer, kBufferSize, length + 4)
239 || iend) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700240 break;
241 }
242 }
243}
244
Matt Sarett562e6812016-11-08 16:13:43 -0500245static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
246
msarettd1ec89b2016-08-03 12:59:27 -0700247// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
Leon Scroggins571b30f2017-07-11 17:35:31 +0000248bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
scroggof24f2242015-03-03 08:59:20 -0800249
msarett13a91232016-02-01 08:03:29 -0800250 int numColors;
251 png_color* palette;
252 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
scroggo05245902015-03-25 11:11:52 -0700253 return false;
scroggof24f2242015-03-03 08:59:20 -0800254 }
255
msarettdcd5e652016-08-22 08:48:40 -0700256 // Contents depend on tableColorType and our choice of if/when to premultiply:
257 // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA }
258 SkPMColor colorTable[256];
Matt Sarett562e6812016-11-08 16:13:43 -0500259 SkColorType tableColorType = this->colorXform() ? kXformSrcColorType : dstInfo.colorType();
scroggof24f2242015-03-03 08:59:20 -0800260
msarett13a91232016-02-01 08:03:29 -0800261 png_bytep alphas;
262 int numColorsWithAlpha = 0;
263 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
msarettdcd5e652016-08-22 08:48:40 -0700264 // If we are performing a color xform, it will handle the premultiply. Otherwise,
265 // we'll do it here.
Matt Sarett61eedeb2016-11-04 13:19:48 -0400266 bool premultiply = !this->colorXform() && needs_premul(dstInfo, this->getEncodedInfo());
msarettdcd5e652016-08-22 08:48:40 -0700267
msarett13a91232016-02-01 08:03:29 -0800268 // Choose which function to use to create the color table. If the final destination's
269 // colortype is unpremultiplied, the color table will store unpremultiplied colors.
msarettdcd5e652016-08-22 08:48:40 -0700270 PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType);
msarett13a91232016-02-01 08:03:29 -0800271
272 for (int i = 0; i < numColorsWithAlpha; i++) {
273 // We don't have a function in SkOpts that combines a set of alphas with a set
274 // of RGBs. We could write one, but it's hardly worth it, given that this
275 // is such a small fraction of the total decode time.
msarettdcd5e652016-08-22 08:48:40 -0700276 colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
msarett13a91232016-02-01 08:03:29 -0800277 palette++;
278 }
scroggof24f2242015-03-03 08:59:20 -0800279 }
280
msarett13a91232016-02-01 08:03:29 -0800281 if (numColorsWithAlpha < numColors) {
282 // The optimized code depends on a 3-byte png_color struct with the colors
283 // in RGB order. These checks make sure it is safe to use.
284 static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken.");
285#ifdef SK_DEBUG
286 SkASSERT(&palette->red < &palette->green);
287 SkASSERT(&palette->green < &palette->blue);
288#endif
289
msarettdcd5e652016-08-22 08:48:40 -0700290 if (is_rgba(tableColorType)) {
291 SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette,
msarett34e0ec42016-04-22 16:27:24 -0700292 numColors - numColorsWithAlpha);
293 } else {
msarettdcd5e652016-08-22 08:48:40 -0700294 SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette,
msarett34e0ec42016-04-22 16:27:24 -0700295 numColors - numColorsWithAlpha);
296 }
scroggof24f2242015-03-03 08:59:20 -0800297 }
298
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400299 if (this->colorXform() && !this->xformOnDecode()) {
300 this->applyColorXform(colorTable, colorTable, numColors);
msarettdcd5e652016-08-22 08:48:40 -0700301 }
302
msarett13a91232016-02-01 08:03:29 -0800303 // Pad the color table with the last color in the table (or black) in the case that
304 // invalid pixel indices exceed the number of colors in the table.
305 const int maxColors = 1 << fBitDepth;
306 if (numColors < maxColors) {
msarettdcd5e652016-08-22 08:48:40 -0700307 SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK;
308 sk_memset32(colorTable + numColors, lastColor, maxColors - numColors);
scroggof24f2242015-03-03 08:59:20 -0800309 }
310
msarettdcd5e652016-08-22 08:48:40 -0700311 fColorTable.reset(new SkColorTable(colorTable, maxColors));
scroggo05245902015-03-25 11:11:52 -0700312 return true;
scroggof24f2242015-03-03 08:59:20 -0800313}
314
315///////////////////////////////////////////////////////////////////////////////
316// Creation
317///////////////////////////////////////////////////////////////////////////////
318
scroggodb30be22015-12-08 18:54:13 -0800319bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) {
320 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead);
scroggof24f2242015-03-03 08:59:20 -0800321}
322
scroggo8e6c7ad2016-09-16 08:20:38 -0700323#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
324
msarett6a738212016-03-04 13:27:35 -0800325static float png_fixed_point_to_float(png_fixed_point x) {
326 // We multiply by the same factor that libpng used to convert
327 // fixed point -> double. Since we want floats, we choose to
328 // do the conversion ourselves rather than convert
329 // fixed point -> double -> float.
330 return ((float) x) * 0.00001f;
331}
332
msarett128245c2016-03-30 12:01:47 -0700333static float png_inverted_fixed_point_to_float(png_fixed_point x) {
334 // This is necessary because the gAMA chunk actually stores 1/gamma.
335 return 1.0f / png_fixed_point_to_float(x);
336}
337
scroggo8e6c7ad2016-09-16 08:20:38 -0700338#endif // LIBPNG >= 1.6
339
msarett6a738212016-03-04 13:27:35 -0800340// Returns a colorSpace object that represents any color space information in
raftiasd737bee2016-12-08 10:53:24 -0500341// the encoded data. If the encoded data contains an invalid/unsupported color space,
342// this will return NULL. If there is no color space information, it will guess sRGB
Matt Sarett523116d2017-01-12 18:36:38 -0500343sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr,
344 SkColorSpace_Base::ICCTypeFlag iccType) {
msarett6a738212016-03-04 13:27:35 -0800345
msarette2443222016-03-04 14:20:49 -0800346#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
347
msarett6a738212016-03-04 13:27:35 -0800348 // First check for an ICC profile
349 png_bytep profile;
350 png_uint_32 length;
351 // The below variables are unused, however, we need to pass them in anyway or
352 // png_get_iCCP() will return nothing.
353 // Could knowing the |name| of the profile ever be interesting? Maybe for debugging?
354 png_charp name;
355 // The |compression| is uninteresting since:
356 // (1) libpng has already decompressed the profile for us.
357 // (2) "deflate" is the only mode of decompression that libpng supports.
358 int compression;
359 if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
360 &length)) {
Matt Sarett523116d2017-01-12 18:36:38 -0500361 return SkColorSpace_Base::MakeICC(profile, length, iccType);
msarett6a738212016-03-04 13:27:35 -0800362 }
363
364 // Second, check for sRGB.
365 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
366
367 // sRGB chunks also store a rendering intent: Absolute, Relative,
368 // Perceptual, and Saturation.
369 // FIXME (msarett): Extract this information from the sRGB chunk once
370 // we are able to handle this information in
371 // SkColorSpace.
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500372 return SkColorSpace::MakeSRGB();
msarett6a738212016-03-04 13:27:35 -0800373 }
374
375 // Next, check for chromaticities.
msaretta5a31dd2016-10-11 09:41:16 -0700376 png_fixed_point chrm[8];
msarett6a738212016-03-04 13:27:35 -0800377 png_fixed_point gamma;
msaretta5a31dd2016-10-11 09:41:16 -0700378 if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
379 &chrm[5], &chrm[6], &chrm[7]))
msarett55447952016-07-22 14:07:23 -0700380 {
msaretta5a31dd2016-10-11 09:41:16 -0700381 SkColorSpacePrimaries primaries;
382 primaries.fRX = png_fixed_point_to_float(chrm[2]);
383 primaries.fRY = png_fixed_point_to_float(chrm[3]);
384 primaries.fGX = png_fixed_point_to_float(chrm[4]);
385 primaries.fGY = png_fixed_point_to_float(chrm[5]);
386 primaries.fBX = png_fixed_point_to_float(chrm[6]);
387 primaries.fBY = png_fixed_point_to_float(chrm[7]);
388 primaries.fWX = png_fixed_point_to_float(chrm[0]);
389 primaries.fWY = png_fixed_point_to_float(chrm[1]);
msarett55447952016-07-22 14:07:23 -0700390
391 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
msaretta5a31dd2016-10-11 09:41:16 -0700392 if (!primaries.toXYZD50(&toXYZD50)) {
msarett55447952016-07-22 14:07:23 -0700393 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
394 }
msarett6a738212016-03-04 13:27:35 -0800395
msarett128245c2016-03-30 12:01:47 -0700396 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
Matt Sarett99e3f7d2016-10-28 12:51:08 -0400397 SkColorSpaceTransferFn fn;
398 fn.fA = 1.0f;
399 fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
400 fn.fG = png_inverted_fixed_point_to_float(gamma);
msarettffc2aea2016-05-02 11:12:14 -0700401
Matt Sarett99e3f7d2016-10-28 12:51:08 -0400402 return SkColorSpace::MakeRGB(fn, toXYZD50);
msarett6a738212016-03-04 13:27:35 -0800403 }
msarett128245c2016-03-30 12:01:47 -0700404
msarettc4ce6b52016-06-16 07:37:41 -0700405 // Default to sRGB gamma if the image has color space information,
406 // but does not specify gamma.
Brian Osman526972e2016-10-24 09:24:02 -0400407 return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
msarett6a738212016-03-04 13:27:35 -0800408 }
409
410 // Last, check for gamma.
411 if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
Matt Sarett99e3f7d2016-10-28 12:51:08 -0400412 SkColorSpaceTransferFn fn;
413 fn.fA = 1.0f;
414 fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
415 fn.fG = png_inverted_fixed_point_to_float(gamma);
msarett6a738212016-03-04 13:27:35 -0800416
msarettc4ce6b52016-06-16 07:37:41 -0700417 // Since there is no cHRM, we will guess sRGB gamut.
msarett55447952016-07-22 14:07:23 -0700418 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
419 toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
msarettc4ce6b52016-06-16 07:37:41 -0700420
Matt Sarett99e3f7d2016-10-28 12:51:08 -0400421 return SkColorSpace::MakeRGB(fn, toXYZD50);
msarett6a738212016-03-04 13:27:35 -0800422 }
423
msarette2443222016-03-04 14:20:49 -0800424#endif // LIBPNG >= 1.6
425
raftiasd737bee2016-12-08 10:53:24 -0500426 // Report that there is no color space information in the PNG.
427 // Guess sRGB in this case.
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500428 return SkColorSpace::MakeSRGB();
msarett6a738212016-03-04 13:27:35 -0800429}
430
msarett400a93b2016-09-01 18:32:52 -0700431void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
432 switch (fXformMode) {
433 case kSwizzleOnly_XformMode:
msarett400a93b2016-09-01 18:32:52 -0700434 break;
435 case kColorOnly_XformMode:
436 // Intentional fall through. A swizzler hasn't been created yet, but one will
437 // be created later if we are sampling. We'll go ahead and allocate
438 // enough memory to swizzle if necessary.
439 case kSwizzleColor_XformMode: {
Matt Sarett34c69d62017-01-19 17:42:23 -0500440 const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel();
441
442 // If we have more than 8-bits (per component) of precision, we will keep that
443 // extra precision. Otherwise, we will swizzle to RGBA_8888 before transforming.
444 const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4;
445 const size_t colorXformBytes = dstInfo.width() * bytesPerPixel;
scroggo8e6c7ad2016-09-16 08:20:38 -0700446 fStorage.reset(colorXformBytes);
Matt Sarett379938e2017-01-12 18:34:29 -0500447 fColorXformSrcRow = fStorage.get();
msarett400a93b2016-09-01 18:32:52 -0700448 break;
449 }
450 }
msarettd1ec89b2016-08-03 12:59:27 -0700451}
452
Matt Sarett379938e2017-01-12 18:34:29 -0500453static SkColorSpaceXform::ColorFormat png_select_xform_format(const SkEncodedInfo& info) {
Matt Sarett34c69d62017-01-19 17:42:23 -0500454 // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
455 if (16 == info.bitsPerComponent()) {
456 if (SkEncodedInfo::kRGBA_Color == info.color()) {
457 return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
458 } else if (SkEncodedInfo::kRGB_Color == info.color()) {
459 return SkColorSpaceXform::kRGB_U16_BE_ColorFormat;
460 }
Matt Sarett379938e2017-01-12 18:34:29 -0500461 }
462
463 return SkColorSpaceXform::kRGBA_8888_ColorFormat;
464}
465
scroggo8e6c7ad2016-09-16 08:20:38 -0700466void SkPngCodec::applyXformRow(void* dst, const void* src) {
msarett400a93b2016-09-01 18:32:52 -0700467 switch (fXformMode) {
468 case kSwizzleOnly_XformMode:
469 fSwizzler->swizzle(dst, (const uint8_t*) src);
470 break;
471 case kColorOnly_XformMode:
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400472 this->applyColorXform(dst, src, fXformWidth);
msarett400a93b2016-09-01 18:32:52 -0700473 break;
474 case kSwizzleColor_XformMode:
475 fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src);
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400476 this->applyColorXform(dst, fColorXformSrcRow, fXformWidth);
msarett400a93b2016-09-01 18:32:52 -0700477 break;
478 }
msarettdcd5e652016-08-22 08:48:40 -0700479}
480
scroggo8e6c7ad2016-09-16 08:20:38 -0700481class SkPngNormalDecoder : public SkPngCodec {
scroggo05245902015-03-25 11:11:52 -0700482public:
Mike Reedede7bac2017-07-23 15:30:02 -0400483 SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
484 std::unique_ptr<SkStream> stream, SkPngChunkReader* reader,
485 png_structp png_ptr, png_infop info_ptr, int bitDepth)
486 : INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
scroggoff9f7bb2016-10-10 11:35:01 -0700487 , fRowsWrittenToOutput(0)
scroggo8e6c7ad2016-09-16 08:20:38 -0700488 , fDst(nullptr)
489 , fRowBytes(0)
490 , fFirstRow(0)
491 , fLastRow(0)
scroggo1c005e42015-08-04 09:24:45 -0700492 {}
493
scroggo8e6c7ad2016-09-16 08:20:38 -0700494 static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
495 GetDecoder(png_ptr)->allRowsCallback(row, rowNum);
scroggo05245902015-03-25 11:11:52 -0700496 }
497
scroggo8e6c7ad2016-09-16 08:20:38 -0700498 static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) {
499 GetDecoder(png_ptr)->rowCallback(row, rowNum);
msarettd1ec89b2016-08-03 12:59:27 -0700500 }
501
emmaleer0a4c3cb2015-06-22 10:40:21 -0700502private:
scroggoff9f7bb2016-10-10 11:35:01 -0700503 int fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700504 void* fDst;
505 size_t fRowBytes;
506
507 // Variables for partial decode
508 int fFirstRow; // FIXME: Move to baseclass?
509 int fLastRow;
scroggo4f2a88c2016-10-17 14:32:41 -0700510 int fRowsNeeded;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700511
scroggo46c57472015-09-30 08:57:13 -0700512 typedef SkPngCodec INHERITED;
scroggo8e6c7ad2016-09-16 08:20:38 -0700513
514 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
515 return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
516 }
517
518 Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
519 const int height = this->getInfo().height();
Leon Scroggins III83239652017-04-21 13:47:12 -0400520 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, AllRowsCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700521 fDst = dst;
522 fRowBytes = rowBytes;
523
scroggoff9f7bb2016-10-10 11:35:01 -0700524 fRowsWrittenToOutput = 0;
scroggoc46cdd42016-10-10 06:45:32 -0700525 fFirstRow = 0;
526 fLastRow = height - 1;
scroggo8e6c7ad2016-09-16 08:20:38 -0700527
528 this->processData();
529
scroggoff9f7bb2016-10-10 11:35:01 -0700530 if (fRowsWrittenToOutput == height) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700531 return SkCodec::kSuccess;
532 }
533
534 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700535 *rowsDecoded = fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700536 }
537
538 return SkCodec::kIncompleteInput;
539 }
540
541 void allRowsCallback(png_bytep row, int rowNum) {
scroggoff9f7bb2016-10-10 11:35:01 -0700542 SkASSERT(rowNum == fRowsWrittenToOutput);
543 fRowsWrittenToOutput++;
scroggo8e6c7ad2016-09-16 08:20:38 -0700544 this->applyXformRow(fDst, row);
545 fDst = SkTAddOffset<void>(fDst, fRowBytes);
546 }
547
548 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
Leon Scroggins III83239652017-04-21 13:47:12 -0400549 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, RowCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700550 fFirstRow = firstRow;
551 fLastRow = lastRow;
552 fDst = dst;
553 fRowBytes = rowBytes;
scroggoff9f7bb2016-10-10 11:35:01 -0700554 fRowsWrittenToOutput = 0;
scroggo4f2a88c2016-10-17 14:32:41 -0700555 fRowsNeeded = fLastRow - fFirstRow + 1;
scroggo8e6c7ad2016-09-16 08:20:38 -0700556 }
557
558 SkCodec::Result decode(int* rowsDecoded) override {
scroggo4f2a88c2016-10-17 14:32:41 -0700559 if (this->swizzler()) {
560 const int sampleY = this->swizzler()->sampleY();
561 fRowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
562 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700563 this->processData();
564
scroggo4f2a88c2016-10-17 14:32:41 -0700565 if (fRowsWrittenToOutput == fRowsNeeded) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700566 return SkCodec::kSuccess;
567 }
568
569 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700570 *rowsDecoded = fRowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700571 }
572
573 return SkCodec::kIncompleteInput;
574 }
575
576 void rowCallback(png_bytep row, int rowNum) {
577 if (rowNum < fFirstRow) {
578 // Ignore this row.
579 return;
580 }
581
582 SkASSERT(rowNum <= fLastRow);
scroggo4f2a88c2016-10-17 14:32:41 -0700583 SkASSERT(fRowsWrittenToOutput < fRowsNeeded);
scroggo8e6c7ad2016-09-16 08:20:38 -0700584
585 // If there is no swizzler, all rows are needed.
scroggo4f2a88c2016-10-17 14:32:41 -0700586 if (!this->swizzler() || this->swizzler()->rowNeeded(rowNum - fFirstRow)) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700587 this->applyXformRow(fDst, row);
588 fDst = SkTAddOffset<void>(fDst, fRowBytes);
scroggoff9f7bb2016-10-10 11:35:01 -0700589 fRowsWrittenToOutput++;
scroggo8e6c7ad2016-09-16 08:20:38 -0700590 }
591
scroggo4f2a88c2016-10-17 14:32:41 -0700592 if (fRowsWrittenToOutput == fRowsNeeded) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700593 // Fake error to stop decoding scanlines.
594 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
595 }
596 }
emmaleer0a4c3cb2015-06-22 10:40:21 -0700597};
598
scroggo8e6c7ad2016-09-16 08:20:38 -0700599class SkPngInterlacedDecoder : public SkPngCodec {
600public:
601 SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
Mike Reedede7bac2017-07-23 15:30:02 -0400602 std::unique_ptr<SkStream> stream, SkPngChunkReader* reader, png_structp png_ptr,
603 png_infop info_ptr, int bitDepth, int numberPasses)
604 : INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
scroggo8e6c7ad2016-09-16 08:20:38 -0700605 , fNumberPasses(numberPasses)
606 , fFirstRow(0)
607 , fLastRow(0)
608 , fLinesDecoded(0)
609 , fInterlacedComplete(false)
610 , fPng_rowbytes(0)
611 {}
612
613 static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
614 auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
615 decoder->interlacedRowCallback(row, rowNum, pass);
616 }
617
scroggo8e6c7ad2016-09-16 08:20:38 -0700618private:
619 const int fNumberPasses;
620 int fFirstRow;
621 int fLastRow;
622 void* fDst;
623 size_t fRowBytes;
624 int fLinesDecoded;
625 bool fInterlacedComplete;
626 size_t fPng_rowbytes;
627 SkAutoTMalloc<png_byte> fInterlaceBuffer;
628
629 typedef SkPngCodec INHERITED;
630
scroggo8e6c7ad2016-09-16 08:20:38 -0700631 // FIXME: Currently sharing interlaced callback for all rows and subset. It's not
632 // as expensive as the subset version of non-interlaced, but it still does extra
633 // work.
634 void interlacedRowCallback(png_bytep row, int rowNum, int pass) {
Leon Scroggins III600effb2017-04-24 15:44:45 -0400635 if (rowNum < fFirstRow || rowNum > fLastRow || fInterlacedComplete) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700636 // Ignore this row
637 return;
638 }
639
640 png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes;
641 png_progressive_combine_row(this->png_ptr(), oldRow, row);
642
643 if (0 == pass) {
644 // The first pass initializes all rows.
645 SkASSERT(row);
646 SkASSERT(fLinesDecoded == rowNum - fFirstRow);
647 fLinesDecoded++;
648 } else {
649 SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1);
650 if (fNumberPasses - 1 == pass && rowNum == fLastRow) {
Leon Scroggins III600effb2017-04-24 15:44:45 -0400651 // Last pass, and we have read all of the rows we care about.
scroggo8e6c7ad2016-09-16 08:20:38 -0700652 fInterlacedComplete = true;
Leon Scroggins III600effb2017-04-24 15:44:45 -0400653 if (fLastRow != this->getInfo().height() - 1 ||
654 (this->swizzler() && this->swizzler()->sampleY() != 1)) {
655 // Fake error to stop decoding scanlines. Only stop if we're not decoding the
656 // whole image, in which case processing the rest of the image might be
657 // expensive. When decoding the whole image, read through the IEND chunk to
658 // preserve Android behavior of leaving the input stream in the right place.
659 longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding);
660 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700661 }
662 }
663 }
664
665 SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override {
666 const int height = this->getInfo().height();
667 this->setUpInterlaceBuffer(height);
Leon Scroggins III83239652017-04-21 13:47:12 -0400668 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback,
scroggo8e6c7ad2016-09-16 08:20:38 -0700669 nullptr);
670
671 fFirstRow = 0;
672 fLastRow = height - 1;
673 fLinesDecoded = 0;
674
675 this->processData();
676
677 png_bytep srcRow = fInterlaceBuffer.get();
678 // FIXME: When resuming, this may rewrite rows that did not change.
679 for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) {
680 this->applyXformRow(dst, srcRow);
681 dst = SkTAddOffset<void>(dst, rowBytes);
682 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes);
683 }
684 if (fInterlacedComplete) {
685 return SkCodec::kSuccess;
686 }
687
688 if (rowsDecoded) {
689 *rowsDecoded = fLinesDecoded;
690 }
691
692 return SkCodec::kIncompleteInput;
693 }
694
695 void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override {
696 // FIXME: We could skip rows in the interlace buffer that we won't put in the output.
697 this->setUpInterlaceBuffer(lastRow - firstRow + 1);
Leon Scroggins III83239652017-04-21 13:47:12 -0400698 png_set_progressive_read_fn(this->png_ptr(), this, nullptr, InterlacedRowCallback, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700699 fFirstRow = firstRow;
700 fLastRow = lastRow;
701 fDst = dst;
702 fRowBytes = rowBytes;
703 fLinesDecoded = 0;
704 }
705
706 SkCodec::Result decode(int* rowsDecoded) override {
707 this->processData();
708
709 // Now apply Xforms on all the rows that were decoded.
710 if (!fLinesDecoded) {
scroggoe61b3b42016-10-10 07:17:32 -0700711 if (rowsDecoded) {
712 *rowsDecoded = 0;
713 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700714 return SkCodec::kIncompleteInput;
715 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700716
scroggo4f2a88c2016-10-17 14:32:41 -0700717 const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1;
718 const int rowsNeeded = get_scaled_dimension(fLastRow - fFirstRow + 1, sampleY);
scroggoff9f7bb2016-10-10 11:35:01 -0700719 int rowsWrittenToOutput = 0;
720
scroggo8e6c7ad2016-09-16 08:20:38 -0700721 // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it
722 // may be too tricky/expensive to handle that correctly.
scroggoe9ea3492016-10-18 09:14:11 -0700723
724 // Offset srcRow by get_start_coord rows. We do not need to account for fFirstRow,
725 // since the first row in fInterlaceBuffer corresponds to fFirstRow.
726 png_bytep srcRow = SkTAddOffset<png_byte>(fInterlaceBuffer.get(),
727 fPng_rowbytes * get_start_coord(sampleY));
scroggo8e6c7ad2016-09-16 08:20:38 -0700728 void* dst = fDst;
scroggoe9ea3492016-10-18 09:14:11 -0700729 for (; rowsWrittenToOutput < rowsNeeded; rowsWrittenToOutput++) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700730 this->applyXformRow(dst, srcRow);
731 dst = SkTAddOffset<void>(dst, fRowBytes);
732 srcRow = SkTAddOffset<png_byte>(srcRow, fPng_rowbytes * sampleY);
733 }
734
735 if (fInterlacedComplete) {
736 return SkCodec::kSuccess;
737 }
738
739 if (rowsDecoded) {
scroggoff9f7bb2016-10-10 11:35:01 -0700740 *rowsDecoded = rowsWrittenToOutput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700741 }
742 return SkCodec::kIncompleteInput;
743 }
744
745 void setUpInterlaceBuffer(int height) {
746 fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr());
747 fInterlaceBuffer.reset(fPng_rowbytes * height);
748 fInterlacedComplete = false;
749 }
750};
751
msarettac6c7502016-04-25 09:30:24 -0700752// Reads the header and initializes the output fields, if not NULL.
753//
754// @param stream Input data. Will be read to get enough information to properly
755// setup the codec.
756// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
757// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
758// expected to continue to own it for the lifetime of the png_ptr.
759// @param outCodec Optional output variable. If non-NULL, will be set to a new
760// SkPngCodec on success.
761// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
762// png_structp on success.
763// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
764// png_infop on success;
Leon Scroggins III588fb042017-07-14 16:32:31 -0400765// @return if kSuccess, the caller is responsible for calling
msarettac6c7502016-04-25 09:30:24 -0700766// png_destroy_read_struct(png_ptrp, info_ptrp).
Leon Scroggins III588fb042017-07-14 16:32:31 -0400767// Otherwise, the passed in fields (except stream) are unchanged.
768static SkCodec::Result read_header(SkStream* stream, SkPngChunkReader* chunkReader,
769 SkCodec** outCodec,
770 png_structp* png_ptrp, png_infop* info_ptrp) {
msarettac6c7502016-04-25 09:30:24 -0700771 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
772 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
773 sk_error_fn, sk_warning_fn);
774 if (!png_ptr) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400775 return SkCodec::kInternalError;
msarettac6c7502016-04-25 09:30:24 -0700776 }
777
scroggo8e6c7ad2016-09-16 08:20:38 -0700778 AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec);
msarettac6c7502016-04-25 09:30:24 -0700779
780 png_infop info_ptr = png_create_info_struct(png_ptr);
781 if (info_ptr == nullptr) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400782 return SkCodec::kInternalError;
msarettac6c7502016-04-25 09:30:24 -0700783 }
784
785 autoClean.setInfoPtr(info_ptr);
786
scroggo8e6c7ad2016-09-16 08:20:38 -0700787 if (setjmp(PNG_JMPBUF(png_ptr))) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400788 return SkCodec::kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -0700789 }
790
msarettac6c7502016-04-25 09:30:24 -0700791#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
792 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in.
793 // This needs to be installed before we read the png header. Android may store ninepatch
794 // chunks in the header.
795 if (chunkReader) {
796 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
797 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk);
798 }
799#endif
800
scroggo8e6c7ad2016-09-16 08:20:38 -0700801 const bool decodedBounds = autoClean.decodeBounds();
802
803 if (!decodedBounds) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400804 return SkCodec::kIncompleteInput;
scroggo8e6c7ad2016-09-16 08:20:38 -0700805 }
806
807 // On success, decodeBounds releases ownership of png_ptr and info_ptr.
808 if (png_ptrp) {
809 *png_ptrp = png_ptr;
810 }
811 if (info_ptrp) {
812 *info_ptrp = info_ptr;
813 }
814
815 // decodeBounds takes care of setting outCodec
816 if (outCodec) {
817 SkASSERT(*outCodec);
818 }
Leon Scroggins III588fb042017-07-14 16:32:31 -0400819 return SkCodec::kSuccess;
scroggo8e6c7ad2016-09-16 08:20:38 -0700820}
821
Leon Scroggins III83239652017-04-21 13:47:12 -0400822void AutoCleanPng::infoCallback(size_t idatLength) {
msarettac6c7502016-04-25 09:30:24 -0700823 png_uint_32 origWidth, origHeight;
824 int bitDepth, encodedColorType;
Leon Scroggins III83239652017-04-21 13:47:12 -0400825 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
msarettac6c7502016-04-25 09:30:24 -0700826 &encodedColorType, nullptr, nullptr, nullptr);
827
Matt Sarett7a1cc672016-12-14 11:48:31 -0500828 // TODO: Should we support 16-bits of precision for gray images?
829 if (bitDepth == 16 && (PNG_COLOR_TYPE_GRAY == encodedColorType ||
830 PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType)) {
831 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400832 png_set_strip_16(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700833 }
834
835 // Now determine the default colorType and alphaType and set the required transforms.
836 // Often, we depend on SkSwizzler to perform any transforms that we need. However, we
837 // still depend on libpng for many of the rare and PNG-specific cases.
838 SkEncodedInfo::Color color;
839 SkEncodedInfo::Alpha alpha;
840 switch (encodedColorType) {
841 case PNG_COLOR_TYPE_PALETTE:
842 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
843 // byte into separate bytes (useful for paletted and grayscale images).
844 if (bitDepth < 8) {
845 // TODO: Should we use SkSwizzler here?
Matt Sarett7a1cc672016-12-14 11:48:31 -0500846 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400847 png_set_packing(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700848 }
849
850 color = SkEncodedInfo::kPalette_Color;
851 // Set the alpha depending on if a transparency chunk exists.
Leon Scroggins III83239652017-04-21 13:47:12 -0400852 alpha = png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS) ?
msarettac6c7502016-04-25 09:30:24 -0700853 SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha;
854 break;
855 case PNG_COLOR_TYPE_RGB:
Leon Scroggins III83239652017-04-21 13:47:12 -0400856 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
msarettac6c7502016-04-25 09:30:24 -0700857 // Convert to RGBA if transparency chunk exists.
Leon Scroggins III83239652017-04-21 13:47:12 -0400858 png_set_tRNS_to_alpha(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700859 color = SkEncodedInfo::kRGBA_Color;
860 alpha = SkEncodedInfo::kBinary_Alpha;
861 } else {
862 color = SkEncodedInfo::kRGB_Color;
863 alpha = SkEncodedInfo::kOpaque_Alpha;
864 }
865 break;
866 case PNG_COLOR_TYPE_GRAY:
867 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
868 if (bitDepth < 8) {
869 // TODO: Should we use SkSwizzler here?
Matt Sarett7a1cc672016-12-14 11:48:31 -0500870 bitDepth = 8;
Leon Scroggins III83239652017-04-21 13:47:12 -0400871 png_set_expand_gray_1_2_4_to_8(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700872 }
873
Leon Scroggins III83239652017-04-21 13:47:12 -0400874 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
875 png_set_tRNS_to_alpha(fPng_ptr);
msarettac6c7502016-04-25 09:30:24 -0700876 color = SkEncodedInfo::kGrayAlpha_Color;
877 alpha = SkEncodedInfo::kBinary_Alpha;
878 } else {
879 color = SkEncodedInfo::kGray_Color;
880 alpha = SkEncodedInfo::kOpaque_Alpha;
881 }
882 break;
883 case PNG_COLOR_TYPE_GRAY_ALPHA:
884 color = SkEncodedInfo::kGrayAlpha_Color;
885 alpha = SkEncodedInfo::kUnpremul_Alpha;
886 break;
887 case PNG_COLOR_TYPE_RGBA:
888 color = SkEncodedInfo::kRGBA_Color;
889 alpha = SkEncodedInfo::kUnpremul_Alpha;
890 break;
891 default:
892 // All the color types have been covered above.
893 SkASSERT(false);
894 color = SkEncodedInfo::kRGBA_Color;
895 alpha = SkEncodedInfo::kUnpremul_Alpha;
896 }
scroggo8e6c7ad2016-09-16 08:20:38 -0700897
898 const int numberPasses = png_set_interlace_handling(fPng_ptr);
899
scroggo8e6c7ad2016-09-16 08:20:38 -0700900 if (fOutCodec) {
901 SkASSERT(nullptr == *fOutCodec);
Matt Sarett523116d2017-01-12 18:36:38 -0500902 SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
903 if (SkEncodedInfo::kGray_Color == color || SkEncodedInfo::kGrayAlpha_Color == color) {
904 iccType |= SkColorSpace_Base::kGray_ICCTypeFlag;
905 }
906 sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr, iccType);
msarettf34cd632016-05-25 10:13:53 -0700907 if (!colorSpace) {
raftiasd737bee2016-12-08 10:53:24 -0500908 // Treat unsupported/invalid color spaces as sRGB.
Matt Sarett77a7a1b2017-02-07 13:56:11 -0500909 colorSpace = SkColorSpace::MakeSRGB();
msarettf34cd632016-05-25 10:13:53 -0700910 }
scroggod8d68552016-06-06 11:26:17 -0700911
Matt Sarett7a1cc672016-12-14 11:48:31 -0500912 SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, bitDepth);
msarett549ca322016-08-17 08:54:08 -0700913 SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);
914
915 if (SkEncodedInfo::kOpaque_Alpha == alpha) {
916 png_color_8p sigBits;
scroggo8e6c7ad2016-09-16 08:20:38 -0700917 if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
msarett549ca322016-08-17 08:54:08 -0700918 if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
919 // Recommend a decode to 565 if the sBIT indicates 565.
920 imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
921 }
922 }
923 }
scroggod8d68552016-06-06 11:26:17 -0700924
msarettac6c7502016-04-25 09:30:24 -0700925 if (1 == numberPasses) {
Mike Reedede7bac2017-07-23 15:30:02 -0400926 *fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo,
927 std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
msarettac6c7502016-04-25 09:30:24 -0700928 } else {
Mike Reedede7bac2017-07-23 15:30:02 -0400929 *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo,
930 std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
931 numberPasses);
msarettac6c7502016-04-25 09:30:24 -0700932 }
Leon Scroggins III83239652017-04-21 13:47:12 -0400933 static_cast<SkPngCodec*>(*fOutCodec)->setIdatLength(idatLength);
msarettac6c7502016-04-25 09:30:24 -0700934 }
935
scroggo8e6c7ad2016-09-16 08:20:38 -0700936 // Release the pointers, which are now owned by the codec or the caller is expected to
937 // take ownership.
938 this->releasePngPtrs();
msarettac6c7502016-04-25 09:30:24 -0700939}
940
msarett549ca322016-08-17 08:54:08 -0700941SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
Mike Reedede7bac2017-07-23 15:30:02 -0400942 std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader,
943 void* png_ptr, void* info_ptr, int bitDepth)
944 : INHERITED(encodedInfo, imageInfo, png_select_xform_format(encodedInfo), std::move(stream))
msarettac6c7502016-04-25 09:30:24 -0700945 , fPngChunkReader(SkSafeRef(chunkReader))
946 , fPng_ptr(png_ptr)
947 , fInfo_ptr(info_ptr)
msarettd1ec89b2016-08-03 12:59:27 -0700948 , fColorXformSrcRow(nullptr)
msarettac6c7502016-04-25 09:30:24 -0700949 , fBitDepth(bitDepth)
Leon Scroggins III83239652017-04-21 13:47:12 -0400950 , fIdatLength(0)
951 , fDecodedIdat(false)
msarettac6c7502016-04-25 09:30:24 -0700952{}
953
954SkPngCodec::~SkPngCodec() {
955 this->destroyReadStruct();
956}
957
958void SkPngCodec::destroyReadStruct() {
959 if (fPng_ptr) {
960 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
961 SkASSERT(fInfo_ptr);
mtklein6dc5b9a2016-08-24 12:22:32 -0700962 png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr);
msarettac6c7502016-04-25 09:30:24 -0700963 fPng_ptr = nullptr;
964 fInfo_ptr = nullptr;
965 }
966}
967
968///////////////////////////////////////////////////////////////////////////////
969// Getting the pixels
970///////////////////////////////////////////////////////////////////////////////
971
Leon Scroggins571b30f2017-07-11 17:35:31 +0000972SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700973 if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) {
msarettd1ec89b2016-08-03 12:59:27 -0700974 SkCodecPrintf("Failed on png_read_update_info.\n");
Matt Sarettd59948a2017-04-26 10:59:48 -0400975 return kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -0700976 }
977 png_read_update_info(fPng_ptr, fInfo_ptr);
978
Matt Sarett313c4632016-10-20 12:35:23 -0400979 // Reset fSwizzler and this->colorXform(). We can't do this in onRewind() because the
msarett400a93b2016-09-01 18:32:52 -0700980 // interlaced scanline decoder may need to rewind.
981 fSwizzler.reset(nullptr);
msarett400a93b2016-09-01 18:32:52 -0700982
Matt Sarettcf3f2342017-03-23 15:32:25 -0400983 if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) {
Matt Sarettd59948a2017-04-26 10:59:48 -0400984 return kInvalidConversion;
msarett400a93b2016-09-01 18:32:52 -0700985 }
msarettd3317422016-08-22 13:00:05 -0700986
Matt Sarett34c69d62017-01-19 17:42:23 -0500987 // If SkColorSpaceXform directly supports the encoded PNG format, we should skip format
988 // conversion in the swizzler (or skip swizzling altogether).
989 bool skipFormatConversion = false;
990 switch (this->getEncodedInfo().color()) {
991 case SkEncodedInfo::kRGB_Color:
992 if (this->getEncodedInfo().bitsPerComponent() != 16) {
993 break;
994 }
995
996 // Fall through
997 case SkEncodedInfo::kRGBA_Color:
998 skipFormatConversion = this->colorXform();
999 break;
1000 default:
1001 break;
1002 }
Matt Sarett379938e2017-01-12 18:34:29 -05001003 if (skipFormatConversion && !options.fSubset) {
msarett400a93b2016-09-01 18:32:52 -07001004 fXformMode = kColorOnly_XformMode;
Matt Sarettd59948a2017-04-26 10:59:48 -04001005 return kSuccess;
msarettd1ec89b2016-08-03 12:59:27 -07001006 }
1007
msarettac6c7502016-04-25 09:30:24 -07001008 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
Leon Scroggins571b30f2017-07-11 17:35:31 +00001009 if (!this->createColorTable(dstInfo)) {
Matt Sarettd59948a2017-04-26 10:59:48 -04001010 return kInvalidInput;
msarettac6c7502016-04-25 09:30:24 -07001011 }
1012 }
1013
Matt Sarett379938e2017-01-12 18:34:29 -05001014 this->initializeSwizzler(dstInfo, options, skipFormatConversion);
Matt Sarettd59948a2017-04-26 10:59:48 -04001015 return kSuccess;
msarett400a93b2016-09-01 18:32:52 -07001016}
1017
msarettc0444612016-09-16 11:45:58 -07001018void SkPngCodec::initializeXformParams() {
1019 switch (fXformMode) {
1020 case kColorOnly_XformMode:
msarettc0444612016-09-16 11:45:58 -07001021 fXformWidth = this->dstInfo().width();
1022 break;
1023 case kSwizzleColor_XformMode:
msarettc0444612016-09-16 11:45:58 -07001024 fXformWidth = this->swizzler()->swizzleWidth();
1025 break;
1026 default:
1027 break;
1028 }
scroggo8e6c7ad2016-09-16 08:20:38 -07001029}
1030
Matt Sarett379938e2017-01-12 18:34:29 -05001031void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
1032 bool skipFormatConversion) {
msarett400a93b2016-09-01 18:32:52 -07001033 SkImageInfo swizzlerInfo = dstInfo;
1034 Options swizzlerOptions = options;
1035 fXformMode = kSwizzleOnly_XformMode;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -04001036 if (this->colorXform() && this->xformOnDecode()) {
Matt Sarett562e6812016-11-08 16:13:43 -05001037 swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
msarett400a93b2016-09-01 18:32:52 -07001038 if (kPremul_SkAlphaType == dstInfo.alphaType()) {
1039 swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
1040 }
1041
1042 fXformMode = kSwizzleColor_XformMode;
1043
1044 // Here, we swizzle into temporary memory, which is not zero initialized.
1045 // FIXME (msarett):
1046 // Is this a problem?
1047 swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized;
1048 }
1049
msarettac6c7502016-04-25 09:30:24 -07001050 const SkPMColor* colors = get_color_ptr(fColorTable.get());
msarettd1ec89b2016-08-03 12:59:27 -07001051 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo,
Matt Sarett379938e2017-01-12 18:34:29 -05001052 swizzlerOptions, nullptr, skipFormatConversion));
msarettac6c7502016-04-25 09:30:24 -07001053 SkASSERT(fSwizzler);
msarett400a93b2016-09-01 18:32:52 -07001054}
1055
1056SkSampler* SkPngCodec::getSampler(bool createIfNecessary) {
1057 if (fSwizzler || !createIfNecessary) {
Ben Wagner145dbcd2016-11-03 14:40:50 -04001058 return fSwizzler.get();
msarett400a93b2016-09-01 18:32:52 -07001059 }
1060
Matt Sarett379938e2017-01-12 18:34:29 -05001061 this->initializeSwizzler(this->dstInfo(), this->options(), true);
Ben Wagner145dbcd2016-11-03 14:40:50 -04001062 return fSwizzler.get();
msarettac6c7502016-04-25 09:30:24 -07001063}
1064
msarettac6c7502016-04-25 09:30:24 -07001065bool SkPngCodec::onRewind() {
1066 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header
1067 // succeeds, they will be repopulated, and if it fails, they will
1068 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will
1069 // come through this function which will rewind and again attempt
1070 // to reinitialize them.
1071 this->destroyReadStruct();
1072
scroggo46c57472015-09-30 08:57:13 -07001073 png_structp png_ptr;
1074 png_infop info_ptr;
Leon Scroggins III588fb042017-07-14 16:32:31 -04001075 if (kSuccess != read_header(this->stream(), fPngChunkReader.get(), nullptr,
1076 &png_ptr, &info_ptr)) {
msarettac6c7502016-04-25 09:30:24 -07001077 return false;
scroggo05245902015-03-25 11:11:52 -07001078 }
1079
msarettac6c7502016-04-25 09:30:24 -07001080 fPng_ptr = png_ptr;
1081 fInfo_ptr = info_ptr;
Leon Scroggins III83239652017-04-21 13:47:12 -04001082 fDecodedIdat = false;
msarettac6c7502016-04-25 09:30:24 -07001083 return true;
1084}
msarett6a738212016-03-04 13:27:35 -08001085
msarettd1ec89b2016-08-03 12:59:27 -07001086SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
1087 size_t rowBytes, const Options& options,
msarettac6c7502016-04-25 09:30:24 -07001088 int* rowsDecoded) {
Matt Sarettd59948a2017-04-26 10:59:48 -04001089 if (!conversion_possible(dstInfo, this->getInfo())) {
msarettac6c7502016-04-25 09:30:24 -07001090 return kInvalidConversion;
1091 }
msarettd1ec89b2016-08-03 12:59:27 -07001092
Leon Scroggins571b30f2017-07-11 17:35:31 +00001093 Result result = this->initializeXforms(dstInfo, options);
Matt Sarettd59948a2017-04-26 10:59:48 -04001094 if (kSuccess != result) {
1095 return result;
1096 }
1097
msarettac6c7502016-04-25 09:30:24 -07001098 if (options.fSubset) {
msarettac6c7502016-04-25 09:30:24 -07001099 return kUnimplemented;
scroggo05245902015-03-25 11:11:52 -07001100 }
1101
msarett400a93b2016-09-01 18:32:52 -07001102 this->allocateStorage(dstInfo);
msarettc0444612016-09-16 11:45:58 -07001103 this->initializeXformParams();
scroggo8e6c7ad2016-09-16 08:20:38 -07001104 return this->decodeAllRows(dst, rowBytes, rowsDecoded);
1105}
msarettac6c7502016-04-25 09:30:24 -07001106
scroggo8e6c7ad2016-09-16 08:20:38 -07001107SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo,
Leon Scroggins571b30f2017-07-11 17:35:31 +00001108 void* dst, size_t rowBytes, const SkCodec::Options& options) {
Matt Sarettd59948a2017-04-26 10:59:48 -04001109 if (!conversion_possible(dstInfo, this->getInfo())) {
scroggo8e6c7ad2016-09-16 08:20:38 -07001110 return kInvalidConversion;
1111 }
scroggo8e6c7ad2016-09-16 08:20:38 -07001112
Leon Scroggins571b30f2017-07-11 17:35:31 +00001113 Result result = this->initializeXforms(dstInfo, options);
Matt Sarettd59948a2017-04-26 10:59:48 -04001114 if (kSuccess != result) {
1115 return result;
1116 }
1117
scroggo8e6c7ad2016-09-16 08:20:38 -07001118 this->allocateStorage(dstInfo);
1119
1120 int firstRow, lastRow;
1121 if (options.fSubset) {
1122 firstRow = options.fSubset->top();
1123 lastRow = options.fSubset->bottom() - 1;
1124 } else {
1125 firstRow = 0;
1126 lastRow = dstInfo.height() - 1;
1127 }
1128 this->setRange(firstRow, lastRow, dst, rowBytes);
scroggod8d68552016-06-06 11:26:17 -07001129 return kSuccess;
scroggo6fb23912016-06-02 14:16:43 -07001130}
1131
scroggo8e6c7ad2016-09-16 08:20:38 -07001132SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) {
1133 // FIXME: Only necessary on the first call.
msarettc0444612016-09-16 11:45:58 -07001134 this->initializeXformParams();
scroggo8e6c7ad2016-09-16 08:20:38 -07001135
1136 return this->decode(rowsDecoded);
1137}
1138
msarettf7eb6fc2016-09-13 09:04:11 -07001139uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const {
msarettac6c7502016-04-25 09:30:24 -07001140 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
1141 if (colorPtr) {
msarettc0444612016-09-16 11:45:58 -07001142 SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(),
msarettf7eb6fc2016-09-13 09:04:11 -07001143 this->getInfo().alphaType());
1144 return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0,
Matt Sarett19aff5d2017-04-03 16:01:10 -04001145 this->colorXform(), true);
msarettac6c7502016-04-25 09:30:24 -07001146 }
msarettf7eb6fc2016-09-13 09:04:11 -07001147 return INHERITED::onGetFillValue(dstInfo);
msarettac6c7502016-04-25 09:30:24 -07001148}
1149
Mike Reedede7bac2017-07-23 15:30:02 -04001150std::unique_ptr<SkCodec> SkPngCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
1151 Result* result, SkPngChunkReader* chunkReader) {
scroggo8e6c7ad2016-09-16 08:20:38 -07001152 SkCodec* outCodec = nullptr;
Mike Reedede7bac2017-07-23 15:30:02 -04001153 *result = read_header(stream.get(), chunkReader, &outCodec, nullptr, nullptr);
Leon Scroggins III588fb042017-07-14 16:32:31 -04001154 if (kSuccess == *result) {
msarettac6c7502016-04-25 09:30:24 -07001155 // Codec has taken ownership of the stream.
1156 SkASSERT(outCodec);
Mike Reedede7bac2017-07-23 15:30:02 -04001157 stream.release();
msarettac6c7502016-04-25 09:30:24 -07001158 }
Mike Reedede7bac2017-07-23 15:30:02 -04001159 return std::unique_ptr<SkCodec>(outCodec);
scroggo05245902015-03-25 11:11:52 -07001160}