1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This is a duplicate of chromium's src/tools/imagediff/image_diff_png.cc
6 // that has been modified to build in a pdfium environment, which itself
7 // was duplicated as follows:
8
9 // This is a duplicate of ui/gfx/codec/png_codec.cc, after removing code related
10 // to Skia, that we can use when running layout tests with minimal dependencies.
11
12 #include "testing/image_diff/image_diff_png.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <string>
18
19 #include "third_party/base/compiler_specific.h"
20 #include "third_party/base/logging.h"
21
22 #ifdef USE_SYSTEM_ZLIB
23 #include <zlib.h>
24 #else
25 #include "third_party/zlib/zlib.h"
26 #endif
27
28 #ifdef USE_SYSTEM_LIBPNG
29 #include <png.h>
30 #else
31 #include "third_party/libpng16/png.h"
32 #endif
33
34 namespace image_diff_png {
35
36 namespace {
37
38 enum ColorFormat {
39 // 3 bytes per pixel (packed), in RGB order regardless of endianness.
40 // This is the native JPEG format.
41 FORMAT_RGB,
42
43 // 3 bytes per pixel, in BGR order regardless of endianness.
44 FORMAT_BGR,
45
46 // 4 bytes per pixel, in RGBA order in memory regardless of endianness.
47 FORMAT_RGBA,
48
49 // 4 bytes per pixel, in BGRA order in memory regardless of endianness.
50 // This is the default Windows DIB order.
51 FORMAT_BGRA,
52
53 // 1 byte per pixel.
54 FORMAT_GRAY,
55 };
56
57 // Represents a comment in the tEXt ancillary chunk of the png.
58 struct Comment {
59 std::string key;
60 std::string text;
61 };
62
63 // Converts BGRA->RGBA and RGBA->BGRA.
ConvertBetweenBGRAandRGBA(const uint8_t * input,int pixel_width,uint8_t * output,bool * is_opaque)64 void ConvertBetweenBGRAandRGBA(const uint8_t* input,
65 int pixel_width,
66 uint8_t* output,
67 bool* is_opaque) {
68 for (int x = 0; x < pixel_width; x++) {
69 const uint8_t* pixel_in = &input[x * 4];
70 uint8_t* pixel_out = &output[x * 4];
71 pixel_out[0] = pixel_in[2];
72 pixel_out[1] = pixel_in[1];
73 pixel_out[2] = pixel_in[0];
74 pixel_out[3] = pixel_in[3];
75 }
76 }
77
ConvertBGRtoRGB(const uint8_t * bgr,int pixel_width,uint8_t * rgb,bool * is_opaque)78 void ConvertBGRtoRGB(const uint8_t* bgr,
79 int pixel_width,
80 uint8_t* rgb,
81 bool* is_opaque) {
82 for (int x = 0; x < pixel_width; x++) {
83 const uint8_t* pixel_in = &bgr[x * 3];
84 uint8_t* pixel_out = &rgb[x * 3];
85 pixel_out[0] = pixel_in[2];
86 pixel_out[1] = pixel_in[1];
87 pixel_out[2] = pixel_in[0];
88 }
89 }
90
ConvertRGBAtoRGB(const uint8_t * rgba,int pixel_width,uint8_t * rgb,bool * is_opaque)91 void ConvertRGBAtoRGB(const uint8_t* rgba,
92 int pixel_width,
93 uint8_t* rgb,
94 bool* is_opaque) {
95 for (int x = 0; x < pixel_width; x++) {
96 const uint8_t* pixel_in = &rgba[x * 4];
97 uint8_t* pixel_out = &rgb[x * 3];
98 pixel_out[0] = pixel_in[0];
99 pixel_out[1] = pixel_in[1];
100 pixel_out[2] = pixel_in[2];
101 }
102 }
103
104 // Decoder
105 //
106 // This code is based on WebKit libpng interface (PNGImageDecoder), which is
107 // in turn based on the Mozilla png decoder.
108
109 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2.
110 constexpr double kDefaultGamma = 2.2;
111
112 // Maximum gamma accepted by PNG library.
113 constexpr double kMaxGamma = 21474.83;
114
115 constexpr double kInverseGamma = 1.0 / kDefaultGamma;
116
117 class PngDecoderState {
118 public:
PngDecoderState(ColorFormat ofmt,std::vector<uint8_t> * out)119 PngDecoderState(ColorFormat ofmt, std::vector<uint8_t>* out)
120 : output_format(ofmt), output(out) {}
121
122 const ColorFormat output_format;
123 int output_channels = 0;
124
125 // Used during the reading of an SkBitmap. Defaults to true until we see a
126 // pixel with anything other than an alpha of 255.
127 bool is_opaque = true;
128
129 // An intermediary buffer for decode output.
130 std::vector<uint8_t>* const output;
131
132 // Called to convert a row from the library to the correct output format.
133 // When null, no conversion is necessary.
134 void (*row_converter)(const uint8_t* in,
135 int w,
136 uint8_t* out,
137 bool* is_opaque) = nullptr;
138
139 // Size of the image, set in the info callback.
140 int width = 0;
141 int height = 0;
142
143 // Set to true when we've found the end of the data.
144 bool done = false;
145 };
146
ConvertRGBtoRGBA(const uint8_t * rgb,int pixel_width,uint8_t * rgba,bool * is_opaque)147 void ConvertRGBtoRGBA(const uint8_t* rgb,
148 int pixel_width,
149 uint8_t* rgba,
150 bool* is_opaque) {
151 for (int x = 0; x < pixel_width; x++) {
152 const uint8_t* pixel_in = &rgb[x * 3];
153 uint8_t* pixel_out = &rgba[x * 4];
154 pixel_out[0] = pixel_in[0];
155 pixel_out[1] = pixel_in[1];
156 pixel_out[2] = pixel_in[2];
157 pixel_out[3] = 0xff;
158 }
159 }
160
ConvertRGBtoBGRA(const uint8_t * rgb,int pixel_width,uint8_t * bgra,bool * is_opaque)161 void ConvertRGBtoBGRA(const uint8_t* rgb,
162 int pixel_width,
163 uint8_t* bgra,
164 bool* is_opaque) {
165 for (int x = 0; x < pixel_width; x++) {
166 const uint8_t* pixel_in = &rgb[x * 3];
167 uint8_t* pixel_out = &bgra[x * 4];
168 pixel_out[0] = pixel_in[2];
169 pixel_out[1] = pixel_in[1];
170 pixel_out[2] = pixel_in[0];
171 pixel_out[3] = 0xff;
172 }
173 }
174
175 // Called when the png header has been read. This code is based on the WebKit
176 // PNGImageDecoder
DecodeInfoCallback(png_struct * png_ptr,png_info * info_ptr)177 void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) {
178 PngDecoderState* state =
179 static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
180
181 int bit_depth, color_type, interlace_type, compression_type;
182 int filter_type, channels;
183 png_uint_32 w, h;
184 png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
185 &interlace_type, &compression_type, &filter_type);
186
187 // Bounds check. When the image is unreasonably big, we'll error out and
188 // end up back at the setjmp call when we set up decoding. "Unreasonably big"
189 // means "big enough that w * h * 32bpp might overflow an int"; we choose this
190 // threshold to match WebKit and because a number of places in code assume
191 // that an image's size (in bytes) fits in a (signed) int.
192 unsigned long long total_size =
193 static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h);
194 if (total_size > ((1 << 29) - 1))
195 longjmp(png_jmpbuf(png_ptr), 1);
196 state->width = static_cast<int>(w);
197 state->height = static_cast<int>(h);
198
199 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
200 if (color_type == PNG_COLOR_TYPE_PALETTE ||
201 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8))
202 png_set_expand(png_ptr);
203
204 // Transparency for paletted images.
205 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
206 png_set_expand(png_ptr);
207
208 // Convert 16-bit to 8-bit.
209 if (bit_depth == 16)
210 png_set_strip_16(png_ptr);
211
212 // Expand grayscale to RGB.
213 if (color_type == PNG_COLOR_TYPE_GRAY ||
214 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
215 png_set_gray_to_rgb(png_ptr);
216
217 // Deal with gamma and keep it under our control.
218 double gamma;
219 if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
220 if (gamma <= 0.0 || gamma > kMaxGamma) {
221 gamma = kInverseGamma;
222 png_set_gAMA(png_ptr, info_ptr, gamma);
223 }
224 png_set_gamma(png_ptr, kDefaultGamma, gamma);
225 } else {
226 png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
227 }
228
229 // Tell libpng to send us rows for interlaced pngs.
230 if (interlace_type == PNG_INTERLACE_ADAM7)
231 png_set_interlace_handling(png_ptr);
232
233 // Update our info now
234 png_read_update_info(png_ptr, info_ptr);
235 channels = png_get_channels(png_ptr, info_ptr);
236
237 // Pick our row format converter necessary for this data.
238 if (channels == 3) {
239 switch (state->output_format) {
240 case FORMAT_RGB:
241 state->row_converter = nullptr; // no conversion necessary
242 state->output_channels = 3;
243 break;
244 case FORMAT_RGBA:
245 state->row_converter = &ConvertRGBtoRGBA;
246 state->output_channels = 4;
247 break;
248 case FORMAT_BGRA:
249 state->row_converter = &ConvertRGBtoBGRA;
250 state->output_channels = 4;
251 break;
252 case FORMAT_GRAY:
253 state->row_converter = nullptr;
254 state->output_channels = 1;
255 break;
256 default:
257 NOTREACHED();
258 break;
259 }
260 } else if (channels == 4) {
261 switch (state->output_format) {
262 case FORMAT_RGB:
263 state->row_converter = &ConvertRGBAtoRGB;
264 state->output_channels = 3;
265 break;
266 case FORMAT_RGBA:
267 state->row_converter = nullptr; // no conversion necessary
268 state->output_channels = 4;
269 break;
270 case FORMAT_BGRA:
271 state->row_converter = &ConvertBetweenBGRAandRGBA;
272 state->output_channels = 4;
273 break;
274 default:
275 NOTREACHED();
276 break;
277 }
278 } else {
279 NOTREACHED();
280 longjmp(png_jmpbuf(png_ptr), 1);
281 }
282
283 state->output->resize(state->width * state->output_channels * state->height);
284 }
285
DecodeRowCallback(png_struct * png_ptr,png_byte * new_row,png_uint_32 row_num,int pass)286 void DecodeRowCallback(png_struct* png_ptr,
287 png_byte* new_row,
288 png_uint_32 row_num,
289 int pass) {
290 PngDecoderState* state =
291 static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
292
293 if (static_cast<int>(row_num) > state->height) {
294 NOTREACHED();
295 return;
296 }
297
298 uint8_t* base = nullptr;
299 base = &state->output->front();
300
301 uint8_t* dest = &base[state->width * state->output_channels * row_num];
302 if (state->row_converter)
303 state->row_converter(new_row, state->width, dest, &state->is_opaque);
304 else
305 memcpy(dest, new_row, state->width * state->output_channels);
306 }
307
DecodeEndCallback(png_struct * png_ptr,png_info * info)308 void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
309 PngDecoderState* state =
310 static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
311
312 // Mark the image as complete, this will tell the Decode function that we
313 // have successfully found the end of the data.
314 state->done = true;
315 }
316
317 // Automatically destroys the given read structs on destruction to make
318 // cleanup and error handling code cleaner.
319 class PngReadStructDestroyer {
320 public:
PngReadStructDestroyer(png_struct ** ps,png_info ** pi)321 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {}
~PngReadStructDestroyer()322 ~PngReadStructDestroyer() { png_destroy_read_struct(ps_, pi_, nullptr); }
323
324 private:
325 png_struct** ps_;
326 png_info** pi_;
327 };
328
BuildPNGStruct(pdfium::span<const uint8_t> input,png_struct ** png_ptr,png_info ** info_ptr)329 bool BuildPNGStruct(pdfium::span<const uint8_t> input,
330 png_struct** png_ptr,
331 png_info** info_ptr) {
332 if (input.size() < 8)
333 return false; // Input data too small to be a png
334
335 // Have libpng check the signature, it likes the first 8 bytes.
336 if (png_sig_cmp(const_cast<uint8_t*>(input.data()), 0, 8) != 0)
337 return false;
338
339 *png_ptr =
340 png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
341 if (!*png_ptr)
342 return false;
343
344 *info_ptr = png_create_info_struct(*png_ptr);
345 if (!*info_ptr) {
346 png_destroy_read_struct(png_ptr, nullptr, nullptr);
347 return false;
348 }
349
350 return true;
351 }
352
Decode(pdfium::span<const uint8_t> input,ColorFormat format,int * w,int * h)353 std::vector<uint8_t> Decode(pdfium::span<const uint8_t> input,
354 ColorFormat format,
355 int* w,
356 int* h) {
357 std::vector<uint8_t> output;
358 png_struct* png_ptr = nullptr;
359 png_info* info_ptr = nullptr;
360 if (!BuildPNGStruct(input, &png_ptr, &info_ptr))
361 return output;
362
363 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr);
364 if (setjmp(png_jmpbuf(png_ptr))) {
365 // The destroyer will ensure that the structures are cleaned up in this
366 // case, even though we may get here as a jump from random parts of the
367 // PNG library called below.
368 return output;
369 }
370
371 PngDecoderState state(format, &output);
372
373 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
374 &DecodeRowCallback, &DecodeEndCallback);
375 png_process_data(png_ptr, info_ptr, const_cast<uint8_t*>(input.data()),
376 input.size());
377
378 if (!state.done) {
379 // Fed it all the data but the library didn't think we got all the data, so
380 // this file must be truncated.
381 output.clear();
382 return output;
383 }
384
385 *w = state.width;
386 *h = state.height;
387 return output;
388 }
389
390 // Encoder
391 //
392 // This section of the code is based on nsPNGEncoder.cpp in Mozilla
393 // (Copyright 2005 Google Inc.)
394
395 // Passed around as the io_ptr in the png structs so our callbacks know where
396 // to write data.
397 struct PngEncoderState {
PngEncoderStateimage_diff_png::__anonc84d1df30111::PngEncoderState398 explicit PngEncoderState(std::vector<uint8_t>* o) : out(o) {}
399 std::vector<uint8_t>* out;
400 };
401
402 // Called by libpng to flush its internal buffer to ours.
EncoderWriteCallback(png_structp png,png_bytep data,png_size_t size)403 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
404 PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
405 size_t old_size = state->out->size();
406 state->out->resize(old_size + size);
407 memcpy(&(*state->out)[old_size], data, size);
408 }
409
FakeFlushCallback(png_structp png)410 void FakeFlushCallback(png_structp png) {
411 // We don't need to perform any flushing since we aren't doing real IO, but
412 // we're required to provide this function by libpng.
413 }
414
ConvertBGRAtoRGB(const uint8_t * bgra,int pixel_width,uint8_t * rgb,bool * is_opaque)415 void ConvertBGRAtoRGB(const uint8_t* bgra,
416 int pixel_width,
417 uint8_t* rgb,
418 bool* is_opaque) {
419 for (int x = 0; x < pixel_width; x++) {
420 const uint8_t* pixel_in = &bgra[x * 4];
421 uint8_t* pixel_out = &rgb[x * 3];
422 pixel_out[0] = pixel_in[2];
423 pixel_out[1] = pixel_in[1];
424 pixel_out[2] = pixel_in[0];
425 }
426 }
427
428 #ifdef PNG_TEXT_SUPPORTED
429
strdup(const char * str)430 inline char* strdup(const char* str) {
431 #if defined(OS_WIN)
432 return _strdup(str);
433 #else
434 return ::strdup(str);
435 #endif
436 }
437
438 class CommentWriter {
439 public:
CommentWriter(const std::vector<Comment> & comments)440 explicit CommentWriter(const std::vector<Comment>& comments)
441 : comments_(comments), png_text_(new png_text[comments.size()]) {
442 for (size_t i = 0; i < comments.size(); ++i)
443 AddComment(i, comments[i]);
444 }
445
~CommentWriter()446 ~CommentWriter() {
447 for (size_t i = 0; i < comments_.size(); ++i) {
448 free(png_text_[i].key);
449 free(png_text_[i].text);
450 }
451 delete[] png_text_;
452 }
453
HasComments()454 bool HasComments() { return !comments_.empty(); }
455
get_png_text()456 png_text* get_png_text() { return png_text_; }
457
size()458 int size() { return static_cast<int>(comments_.size()); }
459
460 private:
AddComment(size_t pos,const Comment & comment)461 void AddComment(size_t pos, const Comment& comment) {
462 png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE;
463 // A PNG comment's key can only be 79 characters long.
464 if (comment.key.length() > 79)
465 return;
466 png_text_[pos].key = strdup(comment.key.substr(0, 78).c_str());
467 png_text_[pos].text = strdup(comment.text.c_str());
468 png_text_[pos].text_length = comment.text.length();
469 #ifdef PNG_iTXt_SUPPORTED
470 png_text_[pos].itxt_length = 0;
471 png_text_[pos].lang = 0;
472 png_text_[pos].lang_key = 0;
473 #endif
474 }
475
476 const std::vector<Comment> comments_;
477 png_text* png_text_;
478 };
479 #endif // PNG_TEXT_SUPPORTED
480
481 // The type of functions usable for converting between pixel formats.
482 typedef void (*FormatConverter)(const uint8_t* in,
483 int w,
484 uint8_t* out,
485 bool* is_opaque);
486
487 // libpng uses a wacky setjmp-based API, which makes the compiler nervous.
488 // We constrain all of the calls we make to libpng where the setjmp() is in
489 // place to this function.
490 // Returns true on success.
DoLibpngWrite(png_struct * png_ptr,png_info * info_ptr,PngEncoderState * state,int width,int height,int row_byte_width,pdfium::span<const uint8_t> input,int compression_level,int png_output_color_type,int output_color_components,FormatConverter converter,const std::vector<Comment> & comments)491 bool DoLibpngWrite(png_struct* png_ptr,
492 png_info* info_ptr,
493 PngEncoderState* state,
494 int width,
495 int height,
496 int row_byte_width,
497 pdfium::span<const uint8_t> input,
498 int compression_level,
499 int png_output_color_type,
500 int output_color_components,
501 FormatConverter converter,
502 const std::vector<Comment>& comments) {
503 #ifdef PNG_TEXT_SUPPORTED
504 CommentWriter comment_writer(comments);
505 #endif
506 uint8_t* row_buffer = nullptr;
507
508 // Make sure to not declare any locals here -- locals in the presence
509 // of setjmp() in C++ code makes gcc complain.
510
511 if (setjmp(png_jmpbuf(png_ptr))) {
512 delete[] row_buffer;
513 return false;
514 }
515
516 png_set_compression_level(png_ptr, compression_level);
517
518 // Set our callback for libpng to give us the data.
519 png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback);
520
521 png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type,
522 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
523 PNG_FILTER_TYPE_DEFAULT);
524
525 #ifdef PNG_TEXT_SUPPORTED
526 if (comment_writer.HasComments()) {
527 png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(),
528 comment_writer.size());
529 }
530 #endif
531
532 png_write_info(png_ptr, info_ptr);
533
534 if (!converter) {
535 // No conversion needed, give the data directly to libpng.
536 for (int y = 0; y < height; y++) {
537 png_write_row(png_ptr, const_cast<uint8_t*>(&input[y * row_byte_width]));
538 }
539 } else {
540 // Needs conversion using a separate buffer.
541 row_buffer = new uint8_t[width * output_color_components];
542 for (int y = 0; y < height; y++) {
543 converter(&input[y * row_byte_width], width, row_buffer, nullptr);
544 png_write_row(png_ptr, row_buffer);
545 }
546 delete[] row_buffer;
547 }
548
549 png_write_end(png_ptr, info_ptr);
550 return true;
551 }
552
EncodeWithCompressionLevel(pdfium::span<const uint8_t> input,ColorFormat format,const int width,const int height,int row_byte_width,bool discard_transparency,const std::vector<Comment> & comments,int compression_level)553 std::vector<uint8_t> EncodeWithCompressionLevel(
554 pdfium::span<const uint8_t> input,
555 ColorFormat format,
556 const int width,
557 const int height,
558 int row_byte_width,
559 bool discard_transparency,
560 const std::vector<Comment>& comments,
561 int compression_level) {
562 std::vector<uint8_t> output;
563
564 // Run to convert an input row into the output row format, nullptr means no
565 // conversion is necessary.
566 FormatConverter converter = nullptr;
567
568 int input_color_components;
569 int output_color_components;
570 int png_output_color_type;
571 switch (format) {
572 case FORMAT_BGR:
573 converter = ConvertBGRtoRGB;
574 FALLTHROUGH;
575
576 case FORMAT_RGB:
577 input_color_components = 3;
578 output_color_components = 3;
579 png_output_color_type = PNG_COLOR_TYPE_RGB;
580 break;
581
582 case FORMAT_RGBA:
583 input_color_components = 4;
584 if (discard_transparency) {
585 output_color_components = 3;
586 png_output_color_type = PNG_COLOR_TYPE_RGB;
587 converter = ConvertRGBAtoRGB;
588 } else {
589 output_color_components = 4;
590 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
591 converter = nullptr;
592 }
593 break;
594
595 case FORMAT_BGRA:
596 input_color_components = 4;
597 if (discard_transparency) {
598 output_color_components = 3;
599 png_output_color_type = PNG_COLOR_TYPE_RGB;
600 converter = ConvertBGRAtoRGB;
601 } else {
602 output_color_components = 4;
603 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
604 converter = ConvertBetweenBGRAandRGBA;
605 }
606 break;
607
608 case FORMAT_GRAY:
609 input_color_components = 1;
610 output_color_components = 1;
611 png_output_color_type = PNG_COLOR_TYPE_GRAY;
612 break;
613
614 default:
615 NOTREACHED();
616 return output;
617 }
618
619 // Row stride should be at least as long as the length of the data.
620 if (row_byte_width < input_color_components * width)
621 return output;
622
623 png_struct* png_ptr =
624 png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
625 if (!png_ptr)
626 return output;
627 png_info* info_ptr = png_create_info_struct(png_ptr);
628 if (!info_ptr) {
629 png_destroy_write_struct(&png_ptr, nullptr);
630 return output;
631 }
632
633 PngEncoderState state(&output);
634 bool success =
635 DoLibpngWrite(png_ptr, info_ptr, &state, width, height, row_byte_width,
636 input, compression_level, png_output_color_type,
637 output_color_components, converter, comments);
638 png_destroy_write_struct(&png_ptr, &info_ptr);
639
640 if (!success)
641 output.clear();
642 return output;
643 }
644
Encode(pdfium::span<const uint8_t> input,ColorFormat format,const int width,const int height,int row_byte_width,bool discard_transparency,const std::vector<Comment> & comments)645 std::vector<uint8_t> Encode(pdfium::span<const uint8_t> input,
646 ColorFormat format,
647 const int width,
648 const int height,
649 int row_byte_width,
650 bool discard_transparency,
651 const std::vector<Comment>& comments) {
652 return EncodeWithCompressionLevel(input, format, width, height,
653 row_byte_width, discard_transparency,
654 comments, Z_DEFAULT_COMPRESSION);
655 }
656
657 } // namespace
658
DecodePNG(pdfium::span<const uint8_t> input,bool reverse_byte_order,int * width,int * height)659 std::vector<uint8_t> DecodePNG(pdfium::span<const uint8_t> input,
660 bool reverse_byte_order,
661 int* width,
662 int* height) {
663 ColorFormat format = reverse_byte_order ? FORMAT_BGRA : FORMAT_RGBA;
664 return Decode(input, format, width, height);
665 }
666
EncodeBGRPNG(pdfium::span<const uint8_t> input,int width,int height,int row_byte_width)667 std::vector<uint8_t> EncodeBGRPNG(pdfium::span<const uint8_t> input,
668 int width,
669 int height,
670 int row_byte_width) {
671 return Encode(input, FORMAT_BGR, width, height, row_byte_width, false,
672 std::vector<Comment>());
673 }
674
EncodeRGBAPNG(pdfium::span<const uint8_t> input,int width,int height,int row_byte_width)675 std::vector<uint8_t> EncodeRGBAPNG(pdfium::span<const uint8_t> input,
676 int width,
677 int height,
678 int row_byte_width) {
679 return Encode(input, FORMAT_RGBA, width, height, row_byte_width, false,
680 std::vector<Comment>());
681 }
682
EncodeBGRAPNG(pdfium::span<const uint8_t> input,int width,int height,int row_byte_width,bool discard_transparency)683 std::vector<uint8_t> EncodeBGRAPNG(pdfium::span<const uint8_t> input,
684 int width,
685 int height,
686 int row_byte_width,
687 bool discard_transparency) {
688 return Encode(input, FORMAT_BGRA, width, height, row_byte_width,
689 discard_transparency, std::vector<Comment>());
690 }
691
EncodeGrayPNG(pdfium::span<const uint8_t> input,int width,int height,int row_byte_width)692 std::vector<uint8_t> EncodeGrayPNG(pdfium::span<const uint8_t> input,
693 int width,
694 int height,
695 int row_byte_width) {
696 return Encode(input, FORMAT_GRAY, width, height, row_byte_width, false,
697 std::vector<Comment>());
698 }
699
700 } // namespace image_diff_png
701