Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1048423003: Make SkPngCodec support rewinding properly. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | tests/CodexTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec_libpng.h" 8 #include "SkCodec_libpng.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 char buf[PNG_BYTES_TO_CHECK]; 194 char buf[PNG_BYTES_TO_CHECK];
195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { 195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) {
196 return false; 196 return false;
197 } 197 }
198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
199 return false; 199 return false;
200 } 200 }
201 return true; 201 return true;
202 } 202 }
203 203
204 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { 204 // Reads the header, and initializes the passed in fields, if not NULL (except
205 // stream, which is passed to the read function).
206 // Returns true on success, in which case the caller is responsible for calling
207 // png_destroy_read_struct. If it returns false, the passed in fields (except
208 // stream) are unchanged.
209 static bool read_header(SkStream* stream, png_structp* png_ptrp,
210 png_infop* info_ptrp, SkImageInfo* imageInfo) {
205 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 211 // The image is known to be a PNG. Decode enough to know the SkImageInfo.
206 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 212 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
207 sk_error_fn, sk_warning_fn); 213 sk_error_fn, sk_warning_fn);
208 if (!png_ptr) { 214 if (!png_ptr) {
209 return NULL; 215 return false;
210 } 216 }
211 217
212 AutoCleanPng autoClean(png_ptr); 218 AutoCleanPng autoClean(png_ptr);
213 219
214 png_infop info_ptr = png_create_info_struct(png_ptr); 220 png_infop info_ptr = png_create_info_struct(png_ptr);
215 if (info_ptr == NULL) { 221 if (info_ptr == NULL) {
216 return NULL; 222 return false;
217 } 223 }
218 224
219 autoClean.setInfoPtr(info_ptr); 225 autoClean.setInfoPtr(info_ptr);
220 226
221 // FIXME: Could we use the return value of setjmp to specify the type of 227 // FIXME: Could we use the return value of setjmp to specify the type of
222 // error? 228 // error?
223 if (setjmp(png_jmpbuf(png_ptr))) { 229 if (setjmp(png_jmpbuf(png_ptr))) {
224 return NULL; 230 return false;
225 } 231 }
226 232
227 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); 233 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
228 234
229 // FIXME: This is where the old code hooks up the Peeker. Does it need to 235 // FIXME: This is where the old code hooks up the Peeker. Does it need to
230 // be set this early? (i.e. where are the user chunks? early in the stream, 236 // be set this early? (i.e. where are the user chunks? early in the stream,
231 // potentially?) 237 // potentially?)
232 // If it does, we need to figure out a way to set it here. 238 // If it does, we need to figure out a way to set it here.
233 239
234 // The call to png_read_info() gives us all of the information from the 240 // The call to png_read_info() gives us all of the information from the
235 // PNG file before the first IDAT (image data chunk). 241 // PNG file before the first IDAT (image data chunk).
236 png_read_info(png_ptr, info_ptr); 242 png_read_info(png_ptr, info_ptr);
237 png_uint_32 origWidth, origHeight; 243 png_uint_32 origWidth, origHeight;
238 int bitDepth, colorType; 244 int bitDepth, colorType;
239 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 245 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
240 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 246 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
241 247
242 // sanity check for size 248 // sanity check for size
243 { 249 {
244 int64_t size = sk_64_mul(origWidth, origHeight); 250 int64_t size = sk_64_mul(origWidth, origHeight);
245 // now check that if we are 4-bytes per pixel, we also don't overflow 251 // now check that if we are 4-bytes per pixel, we also don't overflow
246 if (size < 0 || size > (0x7FFFFFFF >> 2)) { 252 if (size < 0 || size > (0x7FFFFFFF >> 2)) {
247 return NULL; 253 return false;
248 } 254 }
249 } 255 }
250 256
251 // Tell libpng to strip 16 bit/color files down to 8 bits/color 257 // Tell libpng to strip 16 bit/color files down to 8 bits/color
252 if (bitDepth == 16) { 258 if (bitDepth == 16) {
253 png_set_strip_16(png_ptr); 259 png_set_strip_16(png_ptr);
254 } 260 }
255 #ifdef PNG_READ_PACK_SUPPORTED 261 #ifdef PNG_READ_PACK_SUPPORTED
256 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 262 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
257 // byte into separate bytes (useful for paletted and grayscale images). 263 // byte into separate bytes (useful for paletted and grayscale images).
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 324
319 // Add filler (or alpha) byte (after each RGB triplet) if necessary. 325 // Add filler (or alpha) byte (after each RGB triplet) if necessary.
320 // FIXME: It seems like we could just use RGB as the SrcConfig here. 326 // FIXME: It seems like we could just use RGB as the SrcConfig here.
321 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { 327 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
322 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 328 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
323 } 329 }
324 } 330 }
325 331
326 // FIXME: Also need to check for sRGB (skbug.com/3471). 332 // FIXME: Also need to check for sRGB (skbug.com/3471).
327 333
328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, 334 if (imageInfo) {
329 skAlphaType); 335 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType,
330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); 336 skAlphaType);
337 }
331 autoClean.detach(); 338 autoClean.detach();
332 return codec; 339 if (png_ptrp) {
340 *png_ptrp = png_ptr;
341 }
342 if (info_ptrp) {
343 *info_ptrp = info_ptr;
344 }
345 return true;
346 }
347
348 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
349 png_structp png_ptr;
350 png_infop info_ptr;
351 SkImageInfo imageInfo;
352 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) {
353 return SkNEW_ARGS(SkPngCodec, (imageInfo, stream, png_ptr, info_ptr));
354 }
355 return NULL;
333 } 356 }
334 357
335 #define INVALID_NUMBER_PASSES -1 358 #define INVALID_NUMBER_PASSES -1
336 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, 359 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
337 png_structp png_ptr, png_infop info_ptr) 360 png_structp png_ptr, png_infop info_ptr)
338 : INHERITED(info, stream) 361 : INHERITED(info, stream)
339 , fPng_ptr(png_ptr) 362 , fPng_ptr(png_ptr)
340 , fInfo_ptr(info_ptr) 363 , fInfo_ptr(info_ptr)
341 , fSrcConfig(SkSwizzler::kUnknown) 364 , fSrcConfig(SkSwizzler::kUnknown)
342 , fNumberPasses(INVALID_NUMBER_PASSES) 365 , fNumberPasses(INVALID_NUMBER_PASSES)
343 , fReallyHasAlpha(false) 366 , fReallyHasAlpha(false)
344 {} 367 {}
345 368
346 SkPngCodec::~SkPngCodec() { 369 SkPngCodec::~SkPngCodec() {
347 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 370 this->destroyReadStruct();
371 }
372
373 void SkPngCodec::destroyReadStruct() {
374 if (fPng_ptr) {
375 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr
376 SkASSERT(fInfo_ptr);
377 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
378 fPng_ptr = NULL;
379 fInfo_ptr = NULL;
380 }
348 } 381 }
349 382
350 /////////////////////////////////////////////////////////////////////////////// 383 ///////////////////////////////////////////////////////////////////////////////
351 // Getting the pixels 384 // Getting the pixels
352 /////////////////////////////////////////////////////////////////////////////// 385 ///////////////////////////////////////////////////////////////////////////////
353 386
354 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { 387 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
355 // TODO: Support other conversions 388 // TODO: Support other conversions
356 if (dst.colorType() != src.colorType()) { 389 if (dst.colorType() != src.colorType()) {
357 return false; 390 return false;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return kSuccess; 450 return kSuccess;
418 } 451 }
419 452
420 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 453 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
421 size_t rowBytes, const Options& options, 454 size_t rowBytes, const Options& options,
422 SkPMColor ctable[], int* ctableCount) { 455 SkPMColor ctable[], int* ctableCount) {
423 SkCodec::RewindState rewindState = this->rewindIfNeeded(); 456 SkCodec::RewindState rewindState = this->rewindIfNeeded();
424 if (rewindState == kCouldNotRewind_RewindState) { 457 if (rewindState == kCouldNotRewind_RewindState) {
425 return kCouldNotRewind; 458 return kCouldNotRewind;
426 } else if (rewindState == kRewound_RewindState) { 459 } else if (rewindState == kRewound_RewindState) {
427 // TODO(scroggo): handle rewinds 460 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header succeeds,
428 return kCouldNotRewind; 461 // they will be repopulated, and if it fails, they will remain NULL.
462 // Any future accesses to fPng_ptr and fInfo_ptr will come through this
463 // function which will rewind and again attempt to reinitialize them.
464 this->destroyReadStruct();
465 png_structp png_ptr;
466 png_infop info_ptr;
467 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) {
468 fPng_ptr = png_ptr;
469 fInfo_ptr = info_ptr;
470 } else {
471 return kCouldNotRewind;
472 }
473
429 } 474 }
430 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { 475 if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
431 return kInvalidScale; 476 return kInvalidScale;
432 } 477 }
433 if (!conversion_possible(requestedInfo, this->getInfo())) { 478 if (!conversion_possible(requestedInfo, this->getInfo())) {
434 return kInvalidConversion; 479 return kInvalidConversion;
435 } 480 }
436 481
437 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, 482 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
438 options); 483 options);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 621
577 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); 622 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
578 if (fNumberPasses > 1) { 623 if (fNumberPasses > 1) {
579 // We cannot efficiently do scanline decoding. 624 // We cannot efficiently do scanline decoding.
580 return NULL; 625 return NULL;
581 } 626 }
582 627
583 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); 628 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this));
584 } 629 }
585 630
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | tests/CodexTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698