Home | History | Annotate | Download | only in compile
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "compile/Png.h"
     18 
     19 #include <png.h>
     20 #include <zlib.h>
     21 
     22 #include <algorithm>
     23 #include <unordered_map>
     24 #include <unordered_set>
     25 
     26 #include "android-base/errors.h"
     27 #include "android-base/logging.h"
     28 #include "android-base/macros.h"
     29 
     30 #include "trace/TraceBuffer.h"
     31 
     32 namespace aapt {
     33 
     34 // Custom deleter that destroys libpng read and info structs.
     35 class PngReadStructDeleter {
     36  public:
     37   PngReadStructDeleter(png_structp read_ptr, png_infop info_ptr)
     38       : read_ptr_(read_ptr), info_ptr_(info_ptr) {}
     39 
     40   ~PngReadStructDeleter() {
     41     png_destroy_read_struct(&read_ptr_, &info_ptr_, nullptr);
     42   }
     43 
     44  private:
     45   png_structp read_ptr_;
     46   png_infop info_ptr_;
     47 
     48   DISALLOW_COPY_AND_ASSIGN(PngReadStructDeleter);
     49 };
     50 
     51 // Custom deleter that destroys libpng write and info structs.
     52 class PngWriteStructDeleter {
     53  public:
     54   PngWriteStructDeleter(png_structp write_ptr, png_infop info_ptr)
     55       : write_ptr_(write_ptr), info_ptr_(info_ptr) {}
     56 
     57   ~PngWriteStructDeleter() {
     58     png_destroy_write_struct(&write_ptr_, &info_ptr_);
     59   }
     60 
     61  private:
     62   png_structp write_ptr_;
     63   png_infop info_ptr_;
     64 
     65   DISALLOW_COPY_AND_ASSIGN(PngWriteStructDeleter);
     66 };
     67 
     68 // Custom warning logging method that uses IDiagnostics.
     69 static void LogWarning(png_structp png_ptr, png_const_charp warning_msg) {
     70   IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
     71   diag->Warn(DiagMessage() << warning_msg);
     72 }
     73 
     74 // Custom error logging method that uses IDiagnostics.
     75 static void LogError(png_structp png_ptr, png_const_charp error_msg) {
     76   IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
     77   diag->Error(DiagMessage() << error_msg);
     78 
     79   // Causes libpng to longjmp to the spot where setjmp was set. This is how libpng does
     80   // error handling. If this custom error handler method were to return, libpng would, by
     81   // default, print the error message to stdout and call the same png_longjmp method.
     82   png_longjmp(png_ptr, 1);
     83 }
     84 
     85 static void ReadDataFromStream(png_structp png_ptr, png_bytep buffer, png_size_t len) {
     86   io::InputStream* in = (io::InputStream*)png_get_io_ptr(png_ptr);
     87 
     88   const void* in_buffer;
     89   size_t in_len;
     90   if (!in->Next(&in_buffer, &in_len)) {
     91     if (in->HadError()) {
     92       std::stringstream error_msg_builder;
     93       error_msg_builder << "failed reading from input";
     94       if (!in->GetError().empty()) {
     95         error_msg_builder << ": " << in->GetError();
     96       }
     97       std::string err = error_msg_builder.str();
     98       png_error(png_ptr, err.c_str());
     99     }
    100     return;
    101   }
    102 
    103   const size_t bytes_read = std::min(in_len, len);
    104   memcpy(buffer, in_buffer, bytes_read);
    105   if (bytes_read != in_len) {
    106     in->BackUp(in_len - bytes_read);
    107   }
    108 }
    109 
    110 static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t len) {
    111   io::OutputStream* out = (io::OutputStream*)png_get_io_ptr(png_ptr);
    112 
    113   void* out_buffer;
    114   size_t out_len;
    115   while (len > 0) {
    116     if (!out->Next(&out_buffer, &out_len)) {
    117       if (out->HadError()) {
    118         std::stringstream err_msg_builder;
    119         err_msg_builder << "failed writing to output";
    120         if (!out->GetError().empty()) {
    121           err_msg_builder << ": " << out->GetError();
    122         }
    123         std::string err = out->GetError();
    124         png_error(png_ptr, err.c_str());
    125       }
    126       return;
    127     }
    128 
    129     const size_t bytes_written = std::min(out_len, len);
    130     memcpy(out_buffer, buffer, bytes_written);
    131 
    132     // Advance the input buffer.
    133     buffer += bytes_written;
    134     len -= bytes_written;
    135 
    136     // Advance the output buffer.
    137     out_len -= bytes_written;
    138   }
    139 
    140   // If the entire output buffer wasn't used, backup.
    141   if (out_len > 0) {
    142     out->BackUp(out_len);
    143   }
    144 }
    145 
    146 std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in) {
    147   TRACE_CALL();
    148   // Create a diagnostics that has the source information encoded.
    149   SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
    150 
    151   // Read the first 8 bytes of the file looking for the PNG signature.
    152   // Bail early if it does not match.
    153   const png_byte* signature;
    154   size_t buffer_size;
    155   if (!in->Next((const void**)&signature, &buffer_size)) {
    156     if (in->HadError()) {
    157       source_diag.Error(DiagMessage() << "failed to read PNG signature: " << in->GetError());
    158     } else {
    159       source_diag.Error(DiagMessage() << "not enough data for PNG signature");
    160     }
    161     return {};
    162   }
    163 
    164   if (buffer_size < kPngSignatureSize || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
    165     source_diag.Error(DiagMessage() << "file signature does not match PNG signature");
    166     return {};
    167   }
    168 
    169   // Start at the beginning of the first chunk.
    170   in->BackUp(buffer_size - kPngSignatureSize);
    171 
    172   // Create and initialize the png_struct with the default error and warning handlers.
    173   // The header version is also passed in to ensure that this was built against the same
    174   // version of libpng.
    175   png_structp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    176   if (read_ptr == nullptr) {
    177     source_diag.Error(DiagMessage() << "failed to create libpng read png_struct");
    178     return {};
    179   }
    180 
    181   // Create and initialize the memory for image header and data.
    182   png_infop info_ptr = png_create_info_struct(read_ptr);
    183   if (info_ptr == nullptr) {
    184     source_diag.Error(DiagMessage() << "failed to create libpng read png_info");
    185     png_destroy_read_struct(&read_ptr, nullptr, nullptr);
    186     return {};
    187   }
    188 
    189   // Automatically release PNG resources at end of scope.
    190   PngReadStructDeleter png_read_deleter(read_ptr, info_ptr);
    191 
    192   // libpng uses longjmp to jump to an error handling routine.
    193   // setjmp will only return true if it was jumped to, aka there was
    194   // an error.
    195   if (setjmp(png_jmpbuf(read_ptr))) {
    196     return {};
    197   }
    198 
    199   // Handle warnings ourselves via IDiagnostics.
    200   png_set_error_fn(read_ptr, (png_voidp)&source_diag, LogError, LogWarning);
    201 
    202   // Set up the read functions which read from our custom data sources.
    203   png_set_read_fn(read_ptr, (png_voidp)in, ReadDataFromStream);
    204 
    205   // Skip the signature that we already read.
    206   png_set_sig_bytes(read_ptr, kPngSignatureSize);
    207 
    208   // Read the chunk headers.
    209   png_read_info(read_ptr, info_ptr);
    210 
    211   // Extract image meta-data from the various chunk headers.
    212   uint32_t width, height;
    213   int bit_depth, color_type, interlace_method, compression_method, filter_method;
    214   png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
    215                &interlace_method, &compression_method, &filter_method);
    216 
    217   // When the image is read, expand it so that it is in RGBA 8888 format
    218   // so that image handling is uniform.
    219 
    220   if (color_type == PNG_COLOR_TYPE_PALETTE) {
    221     png_set_palette_to_rgb(read_ptr);
    222   }
    223 
    224   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
    225     png_set_expand_gray_1_2_4_to_8(read_ptr);
    226   }
    227 
    228   if (png_get_valid(read_ptr, info_ptr, PNG_INFO_tRNS)) {
    229     png_set_tRNS_to_alpha(read_ptr);
    230   }
    231 
    232   if (bit_depth == 16) {
    233     png_set_strip_16(read_ptr);
    234   }
    235 
    236   if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
    237     png_set_add_alpha(read_ptr, 0xFF, PNG_FILLER_AFTER);
    238   }
    239 
    240   if (color_type == PNG_COLOR_TYPE_GRAY ||
    241       color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    242     png_set_gray_to_rgb(read_ptr);
    243   }
    244 
    245   if (interlace_method != PNG_INTERLACE_NONE) {
    246     png_set_interlace_handling(read_ptr);
    247   }
    248 
    249   // Once all the options for reading have been set, we need to flush
    250   // them to libpng.
    251   png_read_update_info(read_ptr, info_ptr);
    252 
    253   // 9-patch uses int32_t to index images, so we cap the image dimensions to
    254   // something
    255   // that can always be represented by 9-patch.
    256   if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) {
    257     source_diag.Error(DiagMessage()
    258                       << "PNG image dimensions are too large: " << width << "x" << height);
    259     return {};
    260   }
    261 
    262   std::unique_ptr<Image> output_image = util::make_unique<Image>();
    263   output_image->width = static_cast<int32_t>(width);
    264   output_image->height = static_cast<int32_t>(height);
    265 
    266   const size_t row_bytes = png_get_rowbytes(read_ptr, info_ptr);
    267   CHECK(row_bytes == 4 * width);  // RGBA
    268 
    269   // Allocate one large block to hold the image.
    270   output_image->data = std::unique_ptr<uint8_t[]>(new uint8_t[height * row_bytes]);
    271 
    272   // Create an array of rows that index into the data block.
    273   output_image->rows = std::unique_ptr<uint8_t* []>(new uint8_t*[height]);
    274   for (uint32_t h = 0; h < height; h++) {
    275     output_image->rows[h] = output_image->data.get() + (h * row_bytes);
    276   }
    277 
    278   // Actually read the image pixels.
    279   png_read_image(read_ptr, output_image->rows.get());
    280 
    281   // Finish reading. This will read any other chunks after the image data.
    282   png_read_end(read_ptr, info_ptr);
    283 
    284   return output_image;
    285 }
    286 
    287 // Experimentally chosen constant to be added to the overhead of using color type
    288 // PNG_COLOR_TYPE_PALETTE to account for the uncompressability of the palette chunk.
    289 // Without this, many small PNGs encoded with palettes are larger after compression than
    290 // the same PNGs encoded as RGBA.
    291 constexpr static const size_t kPaletteOverheadConstant = 1024u * 10u;
    292 
    293 // Pick a color type by which to encode the image, based on which color type will take
    294 // the least amount of disk space.
    295 //
    296 // 9-patch images traditionally have not been encoded with palettes.
    297 // The original rationale was to avoid dithering until after scaling,
    298 // but I don't think this would be an issue with palettes. Either way,
    299 // our naive size estimation tends to be wrong for small images like 9-patches
    300 // and using palettes balloons the size of the resulting 9-patch.
    301 // In order to not regress in size, restrict 9-patch to not use palettes.
    302 
    303 // The options are:
    304 //
    305 // - RGB
    306 // - RGBA
    307 // - RGB + cheap alpha
    308 // - Color palette
    309 // - Color palette + cheap alpha
    310 // - Color palette + alpha palette
    311 // - Grayscale
    312 // - Grayscale + cheap alpha
    313 // - Grayscale + alpha
    314 //
    315 static int PickColorType(int32_t width, int32_t height, bool grayscale,
    316                          bool convertible_to_grayscale, bool has_nine_patch,
    317                          size_t color_palette_size, size_t alpha_palette_size) {
    318   const size_t palette_chunk_size = 16 + color_palette_size * 3;
    319   const size_t alpha_chunk_size = 16 + alpha_palette_size;
    320   const size_t color_alpha_data_chunk_size = 16 + 4 * width * height;
    321   const size_t color_data_chunk_size = 16 + 3 * width * height;
    322   const size_t grayscale_alpha_data_chunk_size = 16 + 2 * width * height;
    323   const size_t palette_data_chunk_size = 16 + width * height;
    324 
    325   if (grayscale) {
    326     if (alpha_palette_size == 0) {
    327       // This is the smallest the data can be.
    328       return PNG_COLOR_TYPE_GRAY;
    329     } else if (color_palette_size <= 256 && !has_nine_patch) {
    330       // This grayscale has alpha and can fit within a palette.
    331       // See if it is worth fitting into a palette.
    332       const size_t palette_threshold = palette_chunk_size + alpha_chunk_size +
    333                                        palette_data_chunk_size +
    334                                        kPaletteOverheadConstant;
    335       if (grayscale_alpha_data_chunk_size > palette_threshold) {
    336         return PNG_COLOR_TYPE_PALETTE;
    337       }
    338     }
    339     return PNG_COLOR_TYPE_GRAY_ALPHA;
    340   }
    341 
    342   if (color_palette_size <= 256 && !has_nine_patch) {
    343     // This image can fit inside a palette. Let's see if it is worth it.
    344     size_t total_size_with_palette =
    345         palette_data_chunk_size + palette_chunk_size;
    346     size_t total_size_without_palette = color_data_chunk_size;
    347     if (alpha_palette_size > 0) {
    348       total_size_with_palette += alpha_palette_size;
    349       total_size_without_palette = color_alpha_data_chunk_size;
    350     }
    351 
    352     if (total_size_without_palette >
    353         total_size_with_palette + kPaletteOverheadConstant) {
    354       return PNG_COLOR_TYPE_PALETTE;
    355     }
    356   }
    357 
    358   if (convertible_to_grayscale) {
    359     if (alpha_palette_size == 0) {
    360       return PNG_COLOR_TYPE_GRAY;
    361     } else {
    362       return PNG_COLOR_TYPE_GRAY_ALPHA;
    363     }
    364   }
    365 
    366   if (alpha_palette_size == 0) {
    367     return PNG_COLOR_TYPE_RGB;
    368   }
    369   return PNG_COLOR_TYPE_RGBA;
    370 }
    371 
    372 // Assigns indices to the color and alpha palettes, encodes them, and then invokes
    373 // png_set_PLTE/png_set_tRNS.
    374 // This must be done before writing image data.
    375 // Image data must be transformed to use the indices assigned within the palette.
    376 static void WritePalette(png_structp write_ptr, png_infop write_info_ptr,
    377                          std::unordered_map<uint32_t, int>* color_palette,
    378                          std::unordered_set<uint32_t>* alpha_palette) {
    379   CHECK(color_palette->size() <= 256);
    380   CHECK(alpha_palette->size() <= 256);
    381 
    382   // Populate the PNG palette struct and assign indices to the color palette.
    383 
    384   // Colors in the alpha palette should have smaller indices.
    385   // This will ensure that we can truncate the alpha palette if it is
    386   // smaller than the color palette.
    387   int index = 0;
    388   for (uint32_t color : *alpha_palette) {
    389     (*color_palette)[color] = index++;
    390   }
    391 
    392   // Assign the rest of the entries.
    393   for (auto& entry : *color_palette) {
    394     if (entry.second == -1) {
    395       entry.second = index++;
    396     }
    397   }
    398 
    399   // Create the PNG color palette struct.
    400   auto color_palette_bytes = std::unique_ptr<png_color[]>(new png_color[color_palette->size()]);
    401 
    402   std::unique_ptr<png_byte[]> alpha_palette_bytes;
    403   if (!alpha_palette->empty()) {
    404     alpha_palette_bytes = std::unique_ptr<png_byte[]>(new png_byte[alpha_palette->size()]);
    405   }
    406 
    407   for (const auto& entry : *color_palette) {
    408     const uint32_t color = entry.first;
    409     const int index = entry.second;
    410     CHECK(index >= 0);
    411     CHECK(static_cast<size_t>(index) < color_palette->size());
    412 
    413     png_colorp slot = color_palette_bytes.get() + index;
    414     slot->red = color >> 24;
    415     slot->green = color >> 16;
    416     slot->blue = color >> 8;
    417 
    418     const png_byte alpha = color & 0x000000ff;
    419     if (alpha != 0xff && alpha_palette_bytes) {
    420       CHECK(static_cast<size_t>(index) < alpha_palette->size());
    421       alpha_palette_bytes[index] = alpha;
    422     }
    423   }
    424 
    425   // The bytes get copied here, so it is safe to release color_palette_bytes at
    426   // the end of function
    427   // scope.
    428   png_set_PLTE(write_ptr, write_info_ptr, color_palette_bytes.get(), color_palette->size());
    429 
    430   if (alpha_palette_bytes) {
    431     png_set_tRNS(write_ptr, write_info_ptr, alpha_palette_bytes.get(), alpha_palette->size(),
    432                  nullptr);
    433   }
    434 }
    435 
    436 // Write the 9-patch custom PNG chunks to write_info_ptr. This must be done
    437 // before writing image data.
    438 static void WriteNinePatch(png_structp write_ptr, png_infop write_info_ptr,
    439                            const NinePatch* nine_patch) {
    440   // The order of the chunks is important.
    441   // 9-patch code in older platforms expects the 9-patch chunk to be last.
    442 
    443   png_unknown_chunk unknown_chunks[3];
    444   memset(unknown_chunks, 0, sizeof(unknown_chunks));
    445 
    446   size_t index = 0;
    447   size_t chunk_len = 0;
    448 
    449   std::unique_ptr<uint8_t[]> serialized_outline =
    450       nine_patch->SerializeRoundedRectOutline(&chunk_len);
    451   strcpy((char*)unknown_chunks[index].name, "npOl");
    452   unknown_chunks[index].size = chunk_len;
    453   unknown_chunks[index].data = (png_bytep)serialized_outline.get();
    454   unknown_chunks[index].location = PNG_HAVE_PLTE;
    455   index++;
    456 
    457   std::unique_ptr<uint8_t[]> serialized_layout_bounds;
    458   if (nine_patch->layout_bounds.nonZero()) {
    459     serialized_layout_bounds = nine_patch->SerializeLayoutBounds(&chunk_len);
    460     strcpy((char*)unknown_chunks[index].name, "npLb");
    461     unknown_chunks[index].size = chunk_len;
    462     unknown_chunks[index].data = (png_bytep)serialized_layout_bounds.get();
    463     unknown_chunks[index].location = PNG_HAVE_PLTE;
    464     index++;
    465   }
    466 
    467   std::unique_ptr<uint8_t[]> serialized_nine_patch = nine_patch->SerializeBase(&chunk_len);
    468   strcpy((char*)unknown_chunks[index].name, "npTc");
    469   unknown_chunks[index].size = chunk_len;
    470   unknown_chunks[index].data = (png_bytep)serialized_nine_patch.get();
    471   unknown_chunks[index].location = PNG_HAVE_PLTE;
    472   index++;
    473 
    474   // Handle all unknown chunks. We are manually setting the chunks here,
    475   // so we will only ever handle our custom chunks.
    476   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, nullptr, 0);
    477 
    478   // Set the actual chunks here. The data gets copied, so our buffers can
    479   // safely go out of scope.
    480   png_set_unknown_chunks(write_ptr, write_info_ptr, unknown_chunks, index);
    481 }
    482 
    483 bool WritePng(IAaptContext* context, const Image* image,
    484               const NinePatch* nine_patch, io::OutputStream* out,
    485               const PngOptions& options) {
    486   TRACE_CALL();
    487   // Create and initialize the write png_struct with the default error and
    488   // warning handlers.
    489   // The header version is also passed in to ensure that this was built against the same
    490   // version of libpng.
    491   png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    492   if (write_ptr == nullptr) {
    493     context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_struct");
    494     return false;
    495   }
    496 
    497   // Allocate memory to store image header data.
    498   png_infop write_info_ptr = png_create_info_struct(write_ptr);
    499   if (write_info_ptr == nullptr) {
    500     context->GetDiagnostics()->Error(DiagMessage() << "failed to create libpng write png_info");
    501     png_destroy_write_struct(&write_ptr, nullptr);
    502     return false;
    503   }
    504 
    505   // Automatically release PNG resources at end of scope.
    506   PngWriteStructDeleter png_write_deleter(write_ptr, write_info_ptr);
    507 
    508   // libpng uses longjmp to jump to error handling routines.
    509   // setjmp will return true only if it was jumped to, aka, there was an error.
    510   if (setjmp(png_jmpbuf(write_ptr))) {
    511     return false;
    512   }
    513 
    514   // Handle warnings with our IDiagnostics.
    515   png_set_error_fn(write_ptr, (png_voidp)context->GetDiagnostics(), LogError, LogWarning);
    516 
    517   // Set up the write functions which write to our custom data sources.
    518   png_set_write_fn(write_ptr, (png_voidp)out, WriteDataToStream, nullptr);
    519 
    520   // We want small files and can take the performance hit to achieve this goal.
    521   png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
    522 
    523   // Begin analysis of the image data.
    524   // Scan the entire image and determine if:
    525   // 1. Every pixel has R == G == B (grayscale)
    526   // 2. Every pixel has A == 255 (opaque)
    527   // 3. There are no more than 256 distinct RGBA colors (palette).
    528   std::unordered_map<uint32_t, int> color_palette;
    529   std::unordered_set<uint32_t> alpha_palette;
    530   bool needs_to_zero_rgb_channels_of_transparent_pixels = false;
    531   bool grayscale = true;
    532   int max_gray_deviation = 0;
    533 
    534   for (int32_t y = 0; y < image->height; y++) {
    535     const uint8_t* row = image->rows[y];
    536     for (int32_t x = 0; x < image->width; x++) {
    537       int red = *row++;
    538       int green = *row++;
    539       int blue = *row++;
    540       int alpha = *row++;
    541 
    542       if (alpha == 0) {
    543         // The color is completely transparent.
    544         // For purposes of palettes and grayscale optimization,
    545         // treat all channels as 0x00.
    546         needs_to_zero_rgb_channels_of_transparent_pixels =
    547             needs_to_zero_rgb_channels_of_transparent_pixels ||
    548             (red != 0 || green != 0 || blue != 0);
    549         red = green = blue = 0;
    550       }
    551 
    552       // Insert the color into the color palette.
    553       const uint32_t color = red << 24 | green << 16 | blue << 8 | alpha;
    554       color_palette[color] = -1;
    555 
    556       // If the pixel has non-opaque alpha, insert it into the
    557       // alpha palette.
    558       if (alpha != 0xff) {
    559         alpha_palette.insert(color);
    560       }
    561 
    562       // Check if the image is indeed grayscale.
    563       if (grayscale) {
    564         if (red != green || red != blue) {
    565           grayscale = false;
    566         }
    567       }
    568 
    569       // Calculate the gray scale deviation so that it can be compared
    570       // with the threshold.
    571       max_gray_deviation = std::max(std::abs(red - green), max_gray_deviation);
    572       max_gray_deviation = std::max(std::abs(green - blue), max_gray_deviation);
    573       max_gray_deviation = std::max(std::abs(blue - red), max_gray_deviation);
    574     }
    575   }
    576 
    577   if (context->IsVerbose()) {
    578     DiagMessage msg;
    579     msg << " paletteSize=" << color_palette.size()
    580         << " alphaPaletteSize=" << alpha_palette.size()
    581         << " maxGrayDeviation=" << max_gray_deviation
    582         << " grayScale=" << (grayscale ? "true" : "false");
    583     context->GetDiagnostics()->Note(msg);
    584   }
    585 
    586   const bool convertible_to_grayscale = max_gray_deviation <= options.grayscale_tolerance;
    587 
    588   const int new_color_type = PickColorType(
    589       image->width, image->height, grayscale, convertible_to_grayscale,
    590       nine_patch != nullptr, color_palette.size(), alpha_palette.size());
    591 
    592   if (context->IsVerbose()) {
    593     DiagMessage msg;
    594     msg << "encoding PNG ";
    595     if (nine_patch) {
    596       msg << "(with 9-patch) as ";
    597     }
    598     switch (new_color_type) {
    599       case PNG_COLOR_TYPE_GRAY:
    600         msg << "GRAY";
    601         break;
    602       case PNG_COLOR_TYPE_GRAY_ALPHA:
    603         msg << "GRAY + ALPHA";
    604         break;
    605       case PNG_COLOR_TYPE_RGB:
    606         msg << "RGB";
    607         break;
    608       case PNG_COLOR_TYPE_RGB_ALPHA:
    609         msg << "RGBA";
    610         break;
    611       case PNG_COLOR_TYPE_PALETTE:
    612         msg << "PALETTE";
    613         break;
    614       default:
    615         msg << "unknown type " << new_color_type;
    616         break;
    617     }
    618     context->GetDiagnostics()->Note(msg);
    619   }
    620 
    621   png_set_IHDR(write_ptr, write_info_ptr, image->width, image->height, 8,
    622                new_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
    623                PNG_FILTER_TYPE_DEFAULT);
    624 
    625   if (new_color_type & PNG_COLOR_MASK_PALETTE) {
    626     // Assigns indices to the palette, and writes the encoded palette to the
    627     // libpng writePtr.
    628     WritePalette(write_ptr, write_info_ptr, &color_palette, &alpha_palette);
    629     png_set_filter(write_ptr, 0, PNG_NO_FILTERS);
    630   } else {
    631     png_set_filter(write_ptr, 0, PNG_ALL_FILTERS);
    632   }
    633 
    634   if (nine_patch) {
    635     WriteNinePatch(write_ptr, write_info_ptr, nine_patch);
    636   }
    637 
    638   // Flush our updates to the header.
    639   png_write_info(write_ptr, write_info_ptr);
    640 
    641   // Write out each row of image data according to its encoding.
    642   if (new_color_type == PNG_COLOR_TYPE_PALETTE) {
    643     // 1 byte/pixel.
    644     auto out_row = std::unique_ptr<png_byte[]>(new png_byte[image->width]);
    645 
    646     for (int32_t y = 0; y < image->height; y++) {
    647       png_const_bytep in_row = image->rows[y];
    648       for (int32_t x = 0; x < image->width; x++) {
    649         int rr = *in_row++;
    650         int gg = *in_row++;
    651         int bb = *in_row++;
    652         int aa = *in_row++;
    653         if (aa == 0) {
    654           // Zero out color channels when transparent.
    655           rr = gg = bb = 0;
    656         }
    657 
    658         const uint32_t color = rr << 24 | gg << 16 | bb << 8 | aa;
    659         const int idx = color_palette[color];
    660         CHECK(idx != -1);
    661         out_row[x] = static_cast<png_byte>(idx);
    662       }
    663       png_write_row(write_ptr, out_row.get());
    664     }
    665   } else if (new_color_type == PNG_COLOR_TYPE_GRAY ||
    666              new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    667     const size_t bpp = new_color_type == PNG_COLOR_TYPE_GRAY ? 1 : 2;
    668     auto out_row =
    669         std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
    670 
    671     for (int32_t y = 0; y < image->height; y++) {
    672       png_const_bytep in_row = image->rows[y];
    673       for (int32_t x = 0; x < image->width; x++) {
    674         int rr = in_row[x * 4];
    675         int gg = in_row[x * 4 + 1];
    676         int bb = in_row[x * 4 + 2];
    677         int aa = in_row[x * 4 + 3];
    678         if (aa == 0) {
    679           // Zero out the gray channel when transparent.
    680           rr = gg = bb = 0;
    681         }
    682 
    683         if (grayscale) {
    684           // The image was already grayscale, red == green == blue.
    685           out_row[x * bpp] = in_row[x * 4];
    686         } else {
    687           // The image is convertible to grayscale, use linear-luminance of
    688           // sRGB colorspace:
    689           // https://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale
    690           out_row[x * bpp] =
    691               (png_byte)(rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
    692         }
    693 
    694         if (bpp == 2) {
    695           // Write out alpha if we have it.
    696           out_row[x * bpp + 1] = aa;
    697         }
    698       }
    699       png_write_row(write_ptr, out_row.get());
    700     }
    701   } else if (new_color_type == PNG_COLOR_TYPE_RGB || new_color_type == PNG_COLOR_TYPE_RGBA) {
    702     const size_t bpp = new_color_type == PNG_COLOR_TYPE_RGB ? 3 : 4;
    703     if (needs_to_zero_rgb_channels_of_transparent_pixels) {
    704       // The source RGBA data can't be used as-is, because we need to zero out
    705       // the RGB values of transparent pixels.
    706       auto out_row = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
    707 
    708       for (int32_t y = 0; y < image->height; y++) {
    709         png_const_bytep in_row = image->rows[y];
    710         for (int32_t x = 0; x < image->width; x++) {
    711           int rr = *in_row++;
    712           int gg = *in_row++;
    713           int bb = *in_row++;
    714           int aa = *in_row++;
    715           if (aa == 0) {
    716             // Zero out the RGB channels when transparent.
    717             rr = gg = bb = 0;
    718           }
    719           out_row[x * bpp] = rr;
    720           out_row[x * bpp + 1] = gg;
    721           out_row[x * bpp + 2] = bb;
    722           if (bpp == 4) {
    723             out_row[x * bpp + 3] = aa;
    724           }
    725         }
    726         png_write_row(write_ptr, out_row.get());
    727       }
    728     } else {
    729       // The source image can be used as-is, just tell libpng whether or not to
    730       // ignore the alpha channel.
    731       if (new_color_type == PNG_COLOR_TYPE_RGB) {
    732         // Delete the extraneous alpha values that we appended to our buffer
    733         // when reading the original values.
    734         png_set_filler(write_ptr, 0, PNG_FILLER_AFTER);
    735       }
    736       png_write_image(write_ptr, image->rows.get());
    737     }
    738   } else {
    739     LOG(FATAL) << "unreachable";
    740   }
    741 
    742   png_write_end(write_ptr, write_info_ptr);
    743   return true;
    744 }
    745 
    746 }  // namespace aapt
    747