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);
GetPalette() const21   uint32_t* GetPalette() const { return m_pPalette; }
GetColorLut() const22   uint32_t* GetColorLut() const { return m_cLut; }
GetAmountLut() const23   uint32_t* GetAmountLut() const { return m_aLut; }
Getlut() const24   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 };
_Partition(uint32_t * alut,uint32_t * clut,int l,int r)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 
_Qsort(uint32_t * alut,uint32_t * clut,int l,int r)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 
_ColorDecode(uint32_t pal_v,uint8_t & r,uint8_t & g,uint8_t & b)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 
_Obtain_Pal(uint32_t * aLut,uint32_t * cLut,uint32_t * dest_pal,uint32_t lut)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 
CFX_Palette()90 CFX_Palette::CFX_Palette() {
91   m_pPalette = nullptr;
92   m_cLut = nullptr;
93   m_aLut = nullptr;
94   m_lut = 0;
95 }
96 
~CFX_Palette()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 
BuildPalette(const CFX_DIBSource * pBitmap)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 
ConvertBuffer_1bppMask2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_8bppMask2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_1bppPlt2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_8bppPlt2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_RgbOrCmyk2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_IndexCopy(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_Plt2PltRgb8(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top,uint32_t * dst_plt)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 
ConvertBuffer_Rgb2PltRgb8(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top,uint32_t * dst_plt)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 
ConvertBuffer_1bppMask2Rgb(FXDIB_Format dst_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_8bppMask2Rgb(FXDIB_Format dst_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dst_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dst_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_24bppRgb2Rgb24(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_32bppRgb2Rgb24(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_Rgb2Rgb32(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer_32bppCmyk2Rgb32(uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top)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 
ConvertBuffer(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const CFX_DIBSource * pSrcBitmap,int src_left,int src_top,std::unique_ptr<uint32_t,FxFreeDeleter> * p_pal)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 
CloneConvert(FXDIB_Format dest_format) const786 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 
ConvertFormat(FXDIB_Format dest_format)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