Home | History | Annotate | Download | only in dib
      1 // Copyright 2014 PDFium 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include <memory>
      8 #include <utility>
      9 
     10 #include "core/fxcodec/fx_codec.h"
     11 #include "core/fxcrt/cfx_maybe_owned.h"
     12 #include "core/fxge/fx_dib.h"
     13 #include "third_party/base/ptr_util.h"
     14 
     15 class CFX_Palette {
     16  public:
     17   CFX_Palette();
     18   ~CFX_Palette();
     19 
     20   bool BuildPalette(const CFX_DIBSource* pBitmap);
     21   uint32_t* GetPalette() const { return m_pPalette; }
     22   uint32_t* GetColorLut() const { return m_cLut; }
     23   uint32_t* GetAmountLut() const { return m_aLut; }
     24   int32_t Getlut() const { return m_lut; }
     25 
     26  protected:
     27   uint32_t* m_pPalette;
     28   uint32_t* m_cLut;
     29   uint32_t* m_aLut;
     30   int m_lut;
     31 };
     32 int _Partition(uint32_t* alut, uint32_t* clut, int l, int r) {
     33   uint32_t p_a = alut[l];
     34   uint32_t p_c = clut[l];
     35   while (l < r) {
     36     while (l < r && alut[r] >= p_a) {
     37       r--;
     38     }
     39     if (l < r) {
     40       alut[l] = alut[r];
     41       clut[l++] = clut[r];
     42     }
     43     while (l < r && alut[l] <= p_a) {
     44       l++;
     45     }
     46     if (l < r) {
     47       alut[r] = alut[l];
     48       clut[r--] = clut[l];
     49     }
     50   }
     51   alut[l] = p_a;
     52   clut[l] = p_c;
     53   return l;
     54 }
     55 
     56 void _Qsort(uint32_t* alut, uint32_t* clut, int l, int r) {
     57   if (l < r) {
     58     int pI = _Partition(alut, clut, l, r);
     59     _Qsort(alut, clut, l, pI - 1);
     60     _Qsort(alut, clut, pI + 1, r);
     61   }
     62 }
     63 
     64 void _ColorDecode(uint32_t pal_v, uint8_t& r, uint8_t& g, uint8_t& b) {
     65   r = (uint8_t)((pal_v & 0xf00) >> 4);
     66   g = (uint8_t)(pal_v & 0x0f0);
     67   b = (uint8_t)((pal_v & 0x00f) << 4);
     68 }
     69 
     70 void _Obtain_Pal(uint32_t* aLut,
     71                  uint32_t* cLut,
     72                  uint32_t* dest_pal,
     73                  uint32_t lut) {
     74   uint32_t lut_1 = lut - 1;
     75   for (int row = 0; row < 256; row++) {
     76     int lut_offset = lut_1 - row;
     77     if (lut_offset < 0) {
     78       lut_offset += 256;
     79     }
     80     uint32_t color = cLut[lut_offset];
     81     uint8_t r;
     82     uint8_t g;
     83     uint8_t b;
     84     _ColorDecode(color, r, g, b);
     85     dest_pal[row] = ((uint32_t)r << 16) | ((uint32_t)g << 8) | b | 0xff000000;
     86     aLut[lut_offset] = row;
     87   }
     88 }
     89 
     90 CFX_Palette::CFX_Palette() {
     91   m_pPalette = nullptr;
     92   m_cLut = nullptr;
     93   m_aLut = nullptr;
     94   m_lut = 0;
     95 }
     96 
     97 CFX_Palette::~CFX_Palette() {
     98   FX_Free(m_pPalette);
     99   FX_Free(m_cLut);
    100   FX_Free(m_aLut);
    101   m_lut = 0;
    102 }
    103 
    104 bool CFX_Palette::BuildPalette(const CFX_DIBSource* pBitmap) {
    105   if (!pBitmap) {
    106     return false;
    107   }
    108   FX_Free(m_pPalette);
    109   m_pPalette = FX_Alloc(uint32_t, 256);
    110   int bpp = pBitmap->GetBPP() / 8;
    111   int width = pBitmap->GetWidth();
    112   int height = pBitmap->GetHeight();
    113   FX_Free(m_cLut);
    114   m_cLut = nullptr;
    115   FX_Free(m_aLut);
    116   m_aLut = nullptr;
    117   m_cLut = FX_Alloc(uint32_t, 4096);
    118   m_aLut = FX_Alloc(uint32_t, 4096);
    119   int row, col;
    120   m_lut = 0;
    121   for (row = 0; row < height; row++) {
    122     uint8_t* scan_line = (uint8_t*)pBitmap->GetScanline(row);
    123     for (col = 0; col < width; col++) {
    124       uint8_t* src_port = scan_line + col * bpp;
    125       uint32_t b = src_port[0] & 0xf0;
    126       uint32_t g = src_port[1] & 0xf0;
    127       uint32_t r = src_port[2] & 0xf0;
    128       uint32_t index = (r << 4) + g + (b >> 4);
    129       m_aLut[index]++;
    130     }
    131   }
    132   for (row = 0; row < 4096; row++) {
    133     if (m_aLut[row] != 0) {
    134       m_aLut[m_lut] = m_aLut[row];
    135       m_cLut[m_lut] = row;
    136       m_lut++;
    137     }
    138   }
    139   _Qsort(m_aLut, m_cLut, 0, m_lut - 1);
    140   _Obtain_Pal(m_aLut, m_cLut, m_pPalette, m_lut);
    141   return true;
    142 }
    143 
    144 bool ConvertBuffer_1bppMask2Gray(uint8_t* dest_buf,
    145                                  int dest_pitch,
    146                                  int width,
    147                                  int height,
    148                                  const CFX_DIBSource* pSrcBitmap,
    149                                  int src_left,
    150                                  int src_top) {
    151   uint8_t set_gray, reset_gray;
    152   set_gray = 0xff;
    153   reset_gray = 0x00;
    154   for (int row = 0; row < height; row++) {
    155     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    156     FXSYS_memset(dest_scan, reset_gray, width);
    157     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    158     for (int col = src_left; col < src_left + width; col++) {
    159       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    160         *dest_scan = set_gray;
    161       }
    162       dest_scan++;
    163     }
    164   }
    165   return true;
    166 }
    167 
    168 bool ConvertBuffer_8bppMask2Gray(uint8_t* dest_buf,
    169                                  int dest_pitch,
    170                                  int width,
    171                                  int height,
    172                                  const CFX_DIBSource* pSrcBitmap,
    173                                  int src_left,
    174                                  int src_top) {
    175   for (int row = 0; row < height; row++) {
    176     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    177     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    178     FXSYS_memcpy(dest_scan, src_scan, width);
    179   }
    180   return true;
    181 }
    182 
    183 bool ConvertBuffer_1bppPlt2Gray(uint8_t* dest_buf,
    184                                 int dest_pitch,
    185                                 int width,
    186                                 int height,
    187                                 const CFX_DIBSource* pSrcBitmap,
    188                                 int src_left,
    189                                 int src_top) {
    190   uint32_t* src_plt = pSrcBitmap->GetPalette();
    191   uint8_t gray[2];
    192   uint8_t reset_r;
    193   uint8_t reset_g;
    194   uint8_t reset_b;
    195   uint8_t set_r;
    196   uint8_t set_g;
    197   uint8_t set_b;
    198   if (pSrcBitmap->IsCmykImage()) {
    199     AdobeCMYK_to_sRGB1(FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
    200                        FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]),
    201                        reset_r, reset_g, reset_b);
    202     AdobeCMYK_to_sRGB1(FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
    203                        FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]),
    204                        set_r, set_g, set_b);
    205   } else {
    206     reset_r = FXARGB_R(src_plt[0]);
    207     reset_g = FXARGB_G(src_plt[0]);
    208     reset_b = FXARGB_B(src_plt[0]);
    209     set_r = FXARGB_R(src_plt[1]);
    210     set_g = FXARGB_G(src_plt[1]);
    211     set_b = FXARGB_B(src_plt[1]);
    212   }
    213   gray[0] = FXRGB2GRAY(reset_r, reset_g, reset_b);
    214   gray[1] = FXRGB2GRAY(set_r, set_g, set_b);
    215 
    216   for (int row = 0; row < height; row++) {
    217     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    218     FXSYS_memset(dest_scan, gray[0], width);
    219     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    220     for (int col = src_left; col < src_left + width; col++) {
    221       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    222         *dest_scan = gray[1];
    223       }
    224       dest_scan++;
    225     }
    226   }
    227   return true;
    228 }
    229 
    230 bool ConvertBuffer_8bppPlt2Gray(uint8_t* dest_buf,
    231                                 int dest_pitch,
    232                                 int width,
    233                                 int height,
    234                                 const CFX_DIBSource* pSrcBitmap,
    235                                 int src_left,
    236                                 int src_top) {
    237   uint32_t* src_plt = pSrcBitmap->GetPalette();
    238   uint8_t gray[256];
    239   if (pSrcBitmap->IsCmykImage()) {
    240     uint8_t r;
    241     uint8_t g;
    242     uint8_t b;
    243     for (size_t i = 0; i < FX_ArraySize(gray); i++) {
    244       AdobeCMYK_to_sRGB1(
    245           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    246           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), r, g, b);
    247       gray[i] = FXRGB2GRAY(r, g, b);
    248     }
    249   } else {
    250     for (size_t i = 0; i < FX_ArraySize(gray); i++) {
    251       gray[i] = FXRGB2GRAY(FXARGB_R(src_plt[i]), FXARGB_G(src_plt[i]),
    252                            FXARGB_B(src_plt[i]));
    253     }
    254   }
    255 
    256   for (int row = 0; row < height; row++) {
    257     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    258     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    259     for (int col = 0; col < width; col++) {
    260       *dest_scan++ = gray[*src_scan++];
    261     }
    262   }
    263   return true;
    264 }
    265 
    266 bool ConvertBuffer_RgbOrCmyk2Gray(uint8_t* dest_buf,
    267                                   int dest_pitch,
    268                                   int width,
    269                                   int height,
    270                                   const CFX_DIBSource* pSrcBitmap,
    271                                   int src_left,
    272                                   int src_top) {
    273   int Bpp = pSrcBitmap->GetBPP() / 8;
    274   if (pSrcBitmap->IsCmykImage()) {
    275     for (int row = 0; row < height; row++) {
    276       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    277       const uint8_t* src_scan =
    278           pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    279       for (int col = 0; col < width; col++) {
    280         uint8_t r, g, b;
    281         AdobeCMYK_to_sRGB1(FXSYS_GetCValue((uint32_t)src_scan[0]),
    282                            FXSYS_GetMValue((uint32_t)src_scan[1]),
    283                            FXSYS_GetYValue((uint32_t)src_scan[2]),
    284                            FXSYS_GetKValue((uint32_t)src_scan[3]), r, g, b);
    285         *dest_scan++ = FXRGB2GRAY(r, g, b);
    286         src_scan += 4;
    287       }
    288     }
    289   } else {
    290     for (int row = 0; row < height; row++) {
    291       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    292       const uint8_t* src_scan =
    293           pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
    294       for (int col = 0; col < width; col++) {
    295         *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
    296         src_scan += Bpp;
    297       }
    298     }
    299   }
    300   return true;
    301 }
    302 
    303 void ConvertBuffer_IndexCopy(uint8_t* dest_buf,
    304                              int dest_pitch,
    305                              int width,
    306                              int height,
    307                              const CFX_DIBSource* pSrcBitmap,
    308                              int src_left,
    309                              int src_top) {
    310   if (pSrcBitmap->GetBPP() == 1) {
    311     for (int row = 0; row < height; row++) {
    312       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    313       FXSYS_memset(dest_scan, 0, width);
    314       const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    315       for (int col = src_left; col < src_left + width; col++) {
    316         if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    317           *dest_scan = 1;
    318         }
    319         dest_scan++;
    320       }
    321     }
    322   } else {
    323     for (int row = 0; row < height; row++) {
    324       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    325       const uint8_t* src_scan =
    326           pSrcBitmap->GetScanline(src_top + row) + src_left;
    327       FXSYS_memcpy(dest_scan, src_scan, width);
    328     }
    329   }
    330 }
    331 
    332 bool ConvertBuffer_Plt2PltRgb8(uint8_t* dest_buf,
    333                                int dest_pitch,
    334                                int width,
    335                                int height,
    336                                const CFX_DIBSource* pSrcBitmap,
    337                                int src_left,
    338                                int src_top,
    339                                uint32_t* dst_plt) {
    340   ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
    341                           src_left, src_top);
    342   uint32_t* src_plt = pSrcBitmap->GetPalette();
    343   int plt_size = pSrcBitmap->GetPaletteSize();
    344   if (pSrcBitmap->IsCmykImage()) {
    345     for (int i = 0; i < plt_size; i++) {
    346       uint8_t r;
    347       uint8_t g;
    348       uint8_t b;
    349       AdobeCMYK_to_sRGB1(
    350           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    351           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), r, g, b);
    352       dst_plt[i] = FXARGB_MAKE(0xff, r, g, b);
    353     }
    354   } else {
    355     FXSYS_memcpy(dst_plt, src_plt, plt_size * 4);
    356   }
    357   return true;
    358 }
    359 
    360 bool ConvertBuffer_Rgb2PltRgb8(uint8_t* dest_buf,
    361                                int dest_pitch,
    362                                int width,
    363                                int height,
    364                                const CFX_DIBSource* pSrcBitmap,
    365                                int src_left,
    366                                int src_top,
    367                                uint32_t* dst_plt) {
    368   int bpp = pSrcBitmap->GetBPP() / 8;
    369   CFX_Palette palette;
    370   palette.BuildPalette(pSrcBitmap);
    371   uint32_t* cLut = palette.GetColorLut();
    372   uint32_t* aLut = palette.GetAmountLut();
    373   if (!cLut || !aLut) {
    374     return false;
    375   }
    376   int lut = palette.Getlut();
    377   uint32_t* pPalette = palette.GetPalette();
    378   if (lut > 256) {
    379     int err, min_err;
    380     int lut_256 = lut - 256;
    381     for (int row = 0; row < lut_256; row++) {
    382       min_err = 1000000;
    383       uint8_t r, g, b;
    384       _ColorDecode(cLut[row], r, g, b);
    385       int clrindex = 0;
    386       for (int col = 0; col < 256; col++) {
    387         uint32_t p_color = *(pPalette + col);
    388         int d_r = r - (uint8_t)(p_color >> 16);
    389         int d_g = g - (uint8_t)(p_color >> 8);
    390         int d_b = b - (uint8_t)(p_color);
    391         err = d_r * d_r + d_g * d_g + d_b * d_b;
    392         if (err < min_err) {
    393           min_err = err;
    394           clrindex = col;
    395         }
    396       }
    397       aLut[row] = clrindex;
    398     }
    399   }
    400   int32_t lut_1 = lut - 1;
    401   for (int row = 0; row < height; row++) {
    402     uint8_t* src_scan =
    403         (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left;
    404     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    405     for (int col = 0; col < width; col++) {
    406       uint8_t* src_port = src_scan + col * bpp;
    407       int r = src_port[2] & 0xf0;
    408       int g = src_port[1] & 0xf0;
    409       int b = src_port[0] & 0xf0;
    410       uint32_t clrindex = (r << 4) + g + (b >> 4);
    411       for (int i = lut_1; i >= 0; i--)
    412         if (clrindex == cLut[i]) {
    413           *(dest_scan + col) = (uint8_t)(aLut[i]);
    414           break;
    415         }
    416     }
    417   }
    418   FXSYS_memcpy(dst_plt, pPalette, sizeof(uint32_t) * 256);
    419   return true;
    420 }
    421 
    422 bool ConvertBuffer_1bppMask2Rgb(FXDIB_Format dst_format,
    423                                 uint8_t* dest_buf,
    424                                 int dest_pitch,
    425                                 int width,
    426                                 int height,
    427                                 const CFX_DIBSource* pSrcBitmap,
    428                                 int src_left,
    429                                 int src_top) {
    430   int comps = (dst_format & 0xff) / 8;
    431   uint8_t set_gray, reset_gray;
    432   set_gray = 0xff;
    433   reset_gray = 0x00;
    434   for (int row = 0; row < height; row++) {
    435     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    436     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    437     for (int col = src_left; col < src_left + width; col++) {
    438       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    439         dest_scan[0] = set_gray;
    440         dest_scan[1] = set_gray;
    441         dest_scan[2] = set_gray;
    442       } else {
    443         dest_scan[0] = reset_gray;
    444         dest_scan[1] = reset_gray;
    445         dest_scan[2] = reset_gray;
    446       }
    447       dest_scan += comps;
    448     }
    449   }
    450   return true;
    451 }
    452 
    453 bool ConvertBuffer_8bppMask2Rgb(FXDIB_Format dst_format,
    454                                 uint8_t* dest_buf,
    455                                 int dest_pitch,
    456                                 int width,
    457                                 int height,
    458                                 const CFX_DIBSource* pSrcBitmap,
    459                                 int src_left,
    460                                 int src_top) {
    461   int comps = (dst_format & 0xff) / 8;
    462   for (int row = 0; row < height; row++) {
    463     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    464     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    465     uint8_t src_pixel;
    466     for (int col = 0; col < width; col++) {
    467       src_pixel = *src_scan++;
    468       *dest_scan++ = src_pixel;
    469       *dest_scan++ = src_pixel;
    470       *dest_scan = src_pixel;
    471       dest_scan += comps - 2;
    472     }
    473   }
    474   return true;
    475 }
    476 
    477 bool ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dst_format,
    478                                uint8_t* dest_buf,
    479                                int dest_pitch,
    480                                int width,
    481                                int height,
    482                                const CFX_DIBSource* pSrcBitmap,
    483                                int src_left,
    484                                int src_top) {
    485   int comps = (dst_format & 0xff) / 8;
    486   uint32_t* src_plt = pSrcBitmap->GetPalette();
    487   uint32_t plt[2];
    488   uint8_t* bgr_ptr = (uint8_t*)plt;
    489   if (pSrcBitmap->IsCmykImage()) {
    490     plt[0] = FXCMYK_TODIB(src_plt[0]);
    491     plt[1] = FXCMYK_TODIB(src_plt[1]);
    492   } else {
    493     bgr_ptr[0] = FXARGB_B(src_plt[0]);
    494     bgr_ptr[1] = FXARGB_G(src_plt[0]);
    495     bgr_ptr[2] = FXARGB_R(src_plt[0]);
    496     bgr_ptr[3] = FXARGB_B(src_plt[1]);
    497     bgr_ptr[4] = FXARGB_G(src_plt[1]);
    498     bgr_ptr[5] = FXARGB_R(src_plt[1]);
    499   }
    500 
    501   if (pSrcBitmap->IsCmykImage()) {
    502     AdobeCMYK_to_sRGB1(FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
    503                        FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]),
    504                        bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]);
    505     AdobeCMYK_to_sRGB1(FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
    506                        FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]),
    507                        bgr_ptr[5], bgr_ptr[4], bgr_ptr[3]);
    508   }
    509 
    510   for (int row = 0; row < height; row++) {
    511     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    512     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    513     for (int col = src_left; col < src_left + width; col++) {
    514       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    515         *dest_scan++ = bgr_ptr[3];
    516         *dest_scan++ = bgr_ptr[4];
    517         *dest_scan = bgr_ptr[5];
    518       } else {
    519         *dest_scan++ = bgr_ptr[0];
    520         *dest_scan++ = bgr_ptr[1];
    521         *dest_scan = bgr_ptr[2];
    522       }
    523       dest_scan += comps - 2;
    524     }
    525   }
    526   return true;
    527 }
    528 
    529 bool ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dst_format,
    530                                uint8_t* dest_buf,
    531                                int dest_pitch,
    532                                int width,
    533                                int height,
    534                                const CFX_DIBSource* pSrcBitmap,
    535                                int src_left,
    536                                int src_top) {
    537   int comps = (dst_format & 0xff) / 8;
    538   uint32_t* src_plt = pSrcBitmap->GetPalette();
    539   uint32_t plt[256];
    540   uint8_t* bgr_ptr = (uint8_t*)plt;
    541   if (!pSrcBitmap->IsCmykImage()) {
    542     for (int i = 0; i < 256; i++) {
    543       *bgr_ptr++ = FXARGB_B(src_plt[i]);
    544       *bgr_ptr++ = FXARGB_G(src_plt[i]);
    545       *bgr_ptr++ = FXARGB_R(src_plt[i]);
    546     }
    547     bgr_ptr = (uint8_t*)plt;
    548   }
    549 
    550   if (pSrcBitmap->IsCmykImage()) {
    551     for (int i = 0; i < 256; i++) {
    552       AdobeCMYK_to_sRGB1(
    553           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    554           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), bgr_ptr[2],
    555           bgr_ptr[1], bgr_ptr[0]);
    556       bgr_ptr += 3;
    557     }
    558     bgr_ptr = (uint8_t*)plt;
    559   }
    560 
    561   for (int row = 0; row < height; row++) {
    562     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    563     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    564     for (int col = 0; col < width; col++) {
    565       uint8_t* src_pixel = bgr_ptr + 3 * (*src_scan++);
    566       *dest_scan++ = *src_pixel++;
    567       *dest_scan++ = *src_pixel++;
    568       *dest_scan = *src_pixel++;
    569       dest_scan += comps - 2;
    570     }
    571   }
    572   return true;
    573 }
    574 
    575 bool ConvertBuffer_24bppRgb2Rgb24(uint8_t* dest_buf,
    576                                   int dest_pitch,
    577                                   int width,
    578                                   int height,
    579                                   const CFX_DIBSource* pSrcBitmap,
    580                                   int src_left,
    581                                   int src_top) {
    582   for (int row = 0; row < height; row++) {
    583     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    584     const uint8_t* src_scan =
    585         pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
    586     FXSYS_memcpy(dest_scan, src_scan, width * 3);
    587   }
    588   return true;
    589 }
    590 
    591 bool ConvertBuffer_32bppRgb2Rgb24(uint8_t* dest_buf,
    592                                   int dest_pitch,
    593                                   int width,
    594                                   int height,
    595                                   const CFX_DIBSource* pSrcBitmap,
    596                                   int src_left,
    597                                   int src_top) {
    598   for (int row = 0; row < height; row++) {
    599     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    600     const uint8_t* src_scan =
    601         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    602     for (int col = 0; col < width; col++) {
    603       *dest_scan++ = *src_scan++;
    604       *dest_scan++ = *src_scan++;
    605       *dest_scan++ = *src_scan++;
    606       src_scan++;
    607     }
    608   }
    609   return true;
    610 }
    611 
    612 bool ConvertBuffer_Rgb2Rgb32(uint8_t* dest_buf,
    613                              int dest_pitch,
    614                              int width,
    615                              int height,
    616                              const CFX_DIBSource* pSrcBitmap,
    617                              int src_left,
    618                              int src_top) {
    619   int comps = pSrcBitmap->GetBPP() / 8;
    620   for (int row = 0; row < height; row++) {
    621     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    622     const uint8_t* src_scan =
    623         pSrcBitmap->GetScanline(src_top + row) + src_left * comps;
    624     for (int col = 0; col < width; col++) {
    625       *dest_scan++ = *src_scan++;
    626       *dest_scan++ = *src_scan++;
    627       *dest_scan++ = *src_scan++;
    628       dest_scan++;
    629       src_scan += comps - 3;
    630     }
    631   }
    632   return true;
    633 }
    634 
    635 bool ConvertBuffer_32bppCmyk2Rgb32(uint8_t* dest_buf,
    636                                    int dest_pitch,
    637                                    int width,
    638                                    int height,
    639                                    const CFX_DIBSource* pSrcBitmap,
    640                                    int src_left,
    641                                    int src_top) {
    642   for (int row = 0; row < height; row++) {
    643     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    644     const uint8_t* src_scan =
    645         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    646     for (int col = 0; col < width; col++) {
    647       AdobeCMYK_to_sRGB1(src_scan[0], src_scan[1], src_scan[2], src_scan[3],
    648                          dest_scan[2], dest_scan[1], dest_scan[0]);
    649       dest_scan += 4;
    650       src_scan += 4;
    651     }
    652   }
    653   return true;
    654 }
    655 
    656 bool ConvertBuffer(FXDIB_Format dest_format,
    657                    uint8_t* dest_buf,
    658                    int dest_pitch,
    659                    int width,
    660                    int height,
    661                    const CFX_DIBSource* pSrcBitmap,
    662                    int src_left,
    663                    int src_top,
    664                    std::unique_ptr<uint32_t, FxFreeDeleter>* p_pal) {
    665   FXDIB_Format src_format = pSrcBitmap->GetFormat();
    666   switch (dest_format) {
    667     case FXDIB_Invalid:
    668     case FXDIB_1bppCmyk:
    669     case FXDIB_1bppMask:
    670     case FXDIB_1bppRgb:
    671       ASSERT(false);
    672       return false;
    673     case FXDIB_8bppMask: {
    674       if ((src_format & 0xff) == 1) {
    675         if (pSrcBitmap->GetPalette()) {
    676           return ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
    677                                             pSrcBitmap, src_left, src_top);
    678         }
    679         return ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
    680                                            pSrcBitmap, src_left, src_top);
    681       }
    682       if ((src_format & 0xff) == 8) {
    683         if (pSrcBitmap->GetPalette()) {
    684           return ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
    685                                             pSrcBitmap, src_left, src_top);
    686         }
    687         return ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
    688                                            pSrcBitmap, src_left, src_top);
    689       }
    690       if ((src_format & 0xff) >= 24) {
    691         return ConvertBuffer_RgbOrCmyk2Gray(dest_buf, dest_pitch, width, height,
    692                                             pSrcBitmap, src_left, src_top);
    693       }
    694       return false;
    695     }
    696     case FXDIB_8bppRgb:
    697     case FXDIB_8bppRgba: {
    698       if ((src_format & 0xff) == 8 && !pSrcBitmap->GetPalette()) {
    699         return ConvertBuffer(FXDIB_8bppMask, dest_buf, dest_pitch, width,
    700                              height, pSrcBitmap, src_left, src_top, p_pal);
    701       }
    702       p_pal->reset(FX_Alloc(uint32_t, 256));
    703       if (((src_format & 0xff) == 1 || (src_format & 0xff) == 8) &&
    704           pSrcBitmap->GetPalette()) {
    705         return ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
    706                                          pSrcBitmap, src_left, src_top,
    707                                          p_pal->get());
    708       }
    709       if ((src_format & 0xff) >= 24) {
    710         return ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
    711                                          pSrcBitmap, src_left, src_top,
    712                                          p_pal->get());
    713       }
    714       return false;
    715     }
    716     case FXDIB_Rgb:
    717     case FXDIB_Rgba: {
    718       if ((src_format & 0xff) == 1) {
    719         if (pSrcBitmap->GetPalette()) {
    720           return ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch,
    721                                            width, height, pSrcBitmap, src_left,
    722                                            src_top);
    723         }
    724         return ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch,
    725                                           width, height, pSrcBitmap, src_left,
    726                                           src_top);
    727       }
    728       if ((src_format & 0xff) == 8) {
    729         if (pSrcBitmap->GetPalette()) {
    730           return ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch,
    731                                            width, height, pSrcBitmap, src_left,
    732                                            src_top);
    733         }
    734         return ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch,
    735                                           width, height, pSrcBitmap, src_left,
    736                                           src_top);
    737       }
    738       if ((src_format & 0xff) == 24) {
    739         return ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
    740                                             pSrcBitmap, src_left, src_top);
    741       }
    742       if ((src_format & 0xff) == 32) {
    743         return ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
    744                                             pSrcBitmap, src_left, src_top);
    745       }
    746       return false;
    747     }
    748     case FXDIB_Argb:
    749     case FXDIB_Rgb32: {
    750       if ((src_format & 0xff) == 1) {
    751         if (pSrcBitmap->GetPalette()) {
    752           return ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch,
    753                                            width, height, pSrcBitmap, src_left,
    754                                            src_top);
    755         }
    756         return ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch,
    757                                           width, height, pSrcBitmap, src_left,
    758                                           src_top);
    759       }
    760       if ((src_format & 0xff) == 8) {
    761         if (pSrcBitmap->GetPalette()) {
    762           return ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch,
    763                                            width, height, pSrcBitmap, src_left,
    764                                            src_top);
    765         }
    766         return ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch,
    767                                           width, height, pSrcBitmap, src_left,
    768                                           src_top);
    769       }
    770       if ((src_format & 0xff) >= 24) {
    771         if (src_format & 0x0400) {
    772           return ConvertBuffer_32bppCmyk2Rgb32(dest_buf, dest_pitch, width,
    773                                                height, pSrcBitmap, src_left,
    774                                                src_top);
    775         }
    776         return ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height,
    777                                        pSrcBitmap, src_left, src_top);
    778       }
    779       return false;
    780     }
    781     default:
    782       return false;
    783   }
    784 }
    785 
    786 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::CloneConvert(
    787     FXDIB_Format dest_format) const {
    788   if (dest_format == GetFormat())
    789     return Clone(nullptr);
    790 
    791   std::unique_ptr<CFX_DIBitmap> pClone = pdfium::MakeUnique<CFX_DIBitmap>();
    792   if (!pClone->Create(m_Width, m_Height, dest_format))
    793     return nullptr;
    794 
    795   CFX_MaybeOwned<CFX_DIBitmap> pSrcAlpha;
    796   if (HasAlpha()) {
    797     if (GetFormat() == FXDIB_Argb)
    798       pSrcAlpha = CloneAlphaMask();
    799     else
    800       pSrcAlpha = m_pAlphaMask;
    801 
    802     if (!pSrcAlpha)
    803       return nullptr;
    804   }
    805   bool ret = true;
    806   if (dest_format & 0x0200) {
    807     if (dest_format == FXDIB_Argb) {
    808       ret = pSrcAlpha
    809                 ? pClone->LoadChannel(FXDIB_Alpha, pSrcAlpha.Get(), FXDIB_Alpha)
    810                 : pClone->LoadChannel(FXDIB_Alpha, 0xff);
    811     } else {
    812       ret = pClone->SetAlphaMask(pSrcAlpha.Get());
    813     }
    814   }
    815   if (!ret)
    816     return nullptr;
    817 
    818   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
    819   if (!ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(),
    820                      m_Width, m_Height, this, 0, 0, &pal_8bpp)) {
    821     return nullptr;
    822   }
    823   if (pal_8bpp)
    824     pClone->SetPalette(pal_8bpp.get());
    825 
    826   return pClone;
    827 }
    828 
    829 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
    830   FXDIB_Format src_format = GetFormat();
    831   if (dest_format == src_format)
    832     return true;
    833 
    834   if (dest_format == FXDIB_8bppMask && src_format == FXDIB_8bppRgb &&
    835       !m_pPalette) {
    836     m_AlphaFlag = 1;
    837     return true;
    838   }
    839   if (dest_format == FXDIB_Argb && src_format == FXDIB_Rgb32) {
    840     m_AlphaFlag = 2;
    841     for (int row = 0; row < m_Height; row++) {
    842       uint8_t* scanline = m_pBuffer + row * m_Pitch + 3;
    843       for (int col = 0; col < m_Width; col++) {
    844         *scanline = 0xff;
    845         scanline += 4;
    846       }
    847     }
    848     return true;
    849   }
    850   int dest_bpp = dest_format & 0xff;
    851   int dest_pitch = (dest_bpp * m_Width + 31) / 32 * 4;
    852   uint8_t* dest_buf = FX_TryAlloc(uint8_t, dest_pitch * m_Height + 4);
    853   if (!dest_buf) {
    854     return false;
    855   }
    856   CFX_DIBitmap* pAlphaMask = nullptr;
    857   if (dest_format == FXDIB_Argb) {
    858     FXSYS_memset(dest_buf, 0xff, dest_pitch * m_Height + 4);
    859     if (m_pAlphaMask) {
    860       for (int row = 0; row < m_Height; row++) {
    861         uint8_t* pDstScanline = dest_buf + row * dest_pitch + 3;
    862         const uint8_t* pSrcScanline = m_pAlphaMask->GetScanline(row);
    863         for (int col = 0; col < m_Width; col++) {
    864           *pDstScanline = *pSrcScanline++;
    865           pDstScanline += 4;
    866         }
    867       }
    868     }
    869   } else if (dest_format & 0x0200) {
    870     if (src_format == FXDIB_Argb) {
    871       pAlphaMask = CloneAlphaMask().release();
    872       if (!pAlphaMask) {
    873         FX_Free(dest_buf);
    874         return false;
    875       }
    876     } else {
    877       if (!m_pAlphaMask) {
    878         if (!BuildAlphaMask()) {
    879           FX_Free(dest_buf);
    880           return false;
    881         }
    882         pAlphaMask = m_pAlphaMask;
    883         m_pAlphaMask = nullptr;
    884       } else {
    885         pAlphaMask = m_pAlphaMask;
    886       }
    887     }
    888   }
    889   bool ret = false;
    890   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
    891   ret = ConvertBuffer(dest_format, dest_buf, dest_pitch, m_Width, m_Height,
    892                       this, 0, 0, &pal_8bpp);
    893   if (!ret) {
    894     if (pAlphaMask != m_pAlphaMask)
    895       delete pAlphaMask;
    896     FX_Free(dest_buf);
    897     return false;
    898   }
    899   if (m_pAlphaMask && pAlphaMask != m_pAlphaMask)
    900     delete m_pAlphaMask;
    901   m_pAlphaMask = pAlphaMask;
    902   m_pPalette = std::move(pal_8bpp);
    903   if (!m_bExtBuf)
    904     FX_Free(m_pBuffer);
    905   m_bExtBuf = false;
    906   m_pBuffer = dest_buf;
    907   m_bpp = (uint8_t)dest_format;
    908   m_AlphaFlag = (uint8_t)(dest_format >> 8);
    909   m_Pitch = dest_pitch;
    910   return true;
    911 }
    912