cfx_dibsource.cpp revision d904c1ec7e8d1d86ed56f0dd252435d12cd345ae
1// Copyright 2017 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 "core/fxge/dib/cfx_dibsource.h"
8
9#include <algorithm>
10#include <memory>
11#include <utility>
12#include <vector>
13
14#include "core/fxcodec/fx_codec.h"
15#include "core/fxge/cfx_cliprgn.h"
16#include "core/fxge/dib/cfx_bitmapstorer.h"
17#include "core/fxge/dib/cfx_dibitmap.h"
18#include "core/fxge/dib/cfx_imagestretcher.h"
19#include "core/fxge/dib/cfx_imagetransformer.h"
20#include "third_party/base/logging.h"
21#include "third_party/base/ptr_util.h"
22
23namespace {
24
25class CFX_Palette {
26 public:
27  explicit CFX_Palette(const RetainPtr<CFX_DIBSource>& pBitmap);
28  ~CFX_Palette();
29
30  const uint32_t* GetPalette() { return m_Palette.data(); }
31  const std::pair<uint32_t, uint32_t>* GetLuts() const { return m_Luts.data(); }
32  int32_t GetLutCount() const { return m_lut; }
33  void SetAmountLut(int row, uint32_t value) { m_Luts[row].first = value; }
34
35 private:
36  std::vector<uint32_t> m_Palette;
37  // (Amount, Color) pairs
38  std::vector<std::pair<uint32_t, uint32_t>> m_Luts;
39  int m_lut;
40};
41
42void ColorDecode(uint32_t pal_v, uint8_t* r, uint8_t* g, uint8_t* b) {
43  *r = static_cast<uint8_t>((pal_v & 0xf00) >> 4);
44  *g = static_cast<uint8_t>(pal_v & 0x0f0);
45  *b = static_cast<uint8_t>((pal_v & 0x00f) << 4);
46}
47
48void Obtain_Pal(std::pair<uint32_t, uint32_t>* luts,
49                uint32_t* dest_pal,
50                uint32_t lut) {
51  uint32_t lut_1 = lut - 1;
52  for (int row = 0; row < 256; ++row) {
53    int lut_offset = lut_1 - row;
54    if (lut_offset < 0)
55      lut_offset += 256;
56    uint32_t color = luts[lut_offset].second;
57    uint8_t r;
58    uint8_t g;
59    uint8_t b;
60    ColorDecode(color, &r, &g, &b);
61    dest_pal[row] = (static_cast<uint32_t>(r) << 16) |
62                    (static_cast<uint32_t>(g) << 8) | b | 0xff000000;
63    luts[lut_offset].first = row;
64  }
65}
66
67CFX_Palette::CFX_Palette(const RetainPtr<CFX_DIBSource>& pBitmap)
68    : m_Palette(256), m_Luts(4096), m_lut(0) {
69  int bpp = pBitmap->GetBPP() / 8;
70  int width = pBitmap->GetWidth();
71  int height = pBitmap->GetHeight();
72  for (int row = 0; row < height; ++row) {
73    const uint8_t* scan_line = pBitmap->GetScanline(row);
74    for (int col = 0; col < width; ++col) {
75      const uint8_t* src_port = scan_line + col * bpp;
76      uint32_t b = src_port[0] & 0xf0;
77      uint32_t g = src_port[1] & 0xf0;
78      uint32_t r = src_port[2] & 0xf0;
79      uint32_t index = (r << 4) + g + (b >> 4);
80      ++m_Luts[index].first;
81    }
82  }
83  // Move non-zeros to the front and count them
84  for (int row = 0; row < 4096; ++row) {
85    if (m_Luts[row].first != 0) {
86      m_Luts[m_lut].first = m_Luts[row].first;
87      m_Luts[m_lut].second = row;
88      ++m_lut;
89    }
90  }
91  std::sort(m_Luts.begin(), m_Luts.begin() + m_lut,
92            [](const std::pair<uint32_t, uint32_t>& arg1,
93               const std::pair<uint32_t, uint32_t>& arg2) {
94              return arg1.first < arg2.first;
95            });
96  Obtain_Pal(m_Luts.data(), m_Palette.data(), m_lut);
97}
98
99CFX_Palette::~CFX_Palette() {}
100
101void ConvertBuffer_1bppMask2Gray(uint8_t* dest_buf,
102                                 int dest_pitch,
103                                 int width,
104                                 int height,
105                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
106                                 int src_left,
107                                 int src_top) {
108  uint8_t set_gray, reset_gray;
109  set_gray = 0xff;
110  reset_gray = 0x00;
111  for (int row = 0; row < height; ++row) {
112    uint8_t* dest_scan = dest_buf + row * dest_pitch;
113    memset(dest_scan, reset_gray, width);
114    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
115    for (int col = src_left; col < src_left + width; ++col) {
116      if (src_scan[col / 8] & (1 << (7 - col % 8)))
117        *dest_scan = set_gray;
118      ++dest_scan;
119    }
120  }
121}
122
123void ConvertBuffer_8bppMask2Gray(uint8_t* dest_buf,
124                                 int dest_pitch,
125                                 int width,
126                                 int height,
127                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
128                                 int src_left,
129                                 int src_top) {
130  for (int row = 0; row < height; ++row) {
131    uint8_t* dest_scan = dest_buf + row * dest_pitch;
132    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
133    memcpy(dest_scan, src_scan, width);
134  }
135}
136
137void ConvertBuffer_1bppPlt2Gray(uint8_t* dest_buf,
138                                int dest_pitch,
139                                int width,
140                                int height,
141                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
142                                int src_left,
143                                int src_top) {
144  uint32_t* src_plt = pSrcBitmap->GetPalette();
145  uint8_t gray[2];
146  uint8_t reset_r;
147  uint8_t reset_g;
148  uint8_t reset_b;
149  uint8_t set_r;
150  uint8_t set_g;
151  uint8_t set_b;
152  if (pSrcBitmap->IsCmykImage()) {
153    std::tie(reset_r, reset_g, reset_b) = AdobeCMYK_to_sRGB1(
154        FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
155        FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
156    std::tie(set_r, set_g, set_b) = AdobeCMYK_to_sRGB1(
157        FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
158        FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
159  } else {
160    reset_r = FXARGB_R(src_plt[0]);
161    reset_g = FXARGB_G(src_plt[0]);
162    reset_b = FXARGB_B(src_plt[0]);
163    set_r = FXARGB_R(src_plt[1]);
164    set_g = FXARGB_G(src_plt[1]);
165    set_b = FXARGB_B(src_plt[1]);
166  }
167  gray[0] = FXRGB2GRAY(reset_r, reset_g, reset_b);
168  gray[1] = FXRGB2GRAY(set_r, set_g, set_b);
169
170  for (int row = 0; row < height; ++row) {
171    uint8_t* dest_scan = dest_buf + row * dest_pitch;
172    memset(dest_scan, gray[0], width);
173    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
174    for (int col = src_left; col < src_left + width; ++col) {
175      if (src_scan[col / 8] & (1 << (7 - col % 8)))
176        *dest_scan = gray[1];
177      ++dest_scan;
178    }
179  }
180}
181
182void ConvertBuffer_8bppPlt2Gray(uint8_t* dest_buf,
183                                int dest_pitch,
184                                int width,
185                                int height,
186                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
187                                int src_left,
188                                int src_top) {
189  uint32_t* src_plt = pSrcBitmap->GetPalette();
190  uint8_t gray[256];
191  if (pSrcBitmap->IsCmykImage()) {
192    uint8_t r;
193    uint8_t g;
194    uint8_t b;
195    for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
196      std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
197          FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
198          FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
199      gray[i] = FXRGB2GRAY(r, g, b);
200    }
201  } else {
202    for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
203      gray[i] = FXRGB2GRAY(FXARGB_R(src_plt[i]), FXARGB_G(src_plt[i]),
204                           FXARGB_B(src_plt[i]));
205    }
206  }
207
208  for (int row = 0; row < height; ++row) {
209    uint8_t* dest_scan = dest_buf + row * dest_pitch;
210    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
211    for (int col = 0; col < width; ++col)
212      *dest_scan++ = gray[*src_scan++];
213  }
214}
215
216void ConvertBuffer_RgbOrCmyk2Gray(uint8_t* dest_buf,
217                                  int dest_pitch,
218                                  int width,
219                                  int height,
220                                  const RetainPtr<CFX_DIBSource>& pSrcBitmap,
221                                  int src_left,
222                                  int src_top) {
223  int Bpp = pSrcBitmap->GetBPP() / 8;
224  if (pSrcBitmap->IsCmykImage()) {
225    for (int row = 0; row < height; ++row) {
226      uint8_t* dest_scan = dest_buf + row * dest_pitch;
227      const uint8_t* src_scan =
228          pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
229      for (int col = 0; col < width; ++col) {
230        uint8_t r;
231        uint8_t g;
232        uint8_t b;
233        std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
234            FXSYS_GetCValue(static_cast<uint32_t>(src_scan[0])),
235            FXSYS_GetMValue(static_cast<uint32_t>(src_scan[1])),
236            FXSYS_GetYValue(static_cast<uint32_t>(src_scan[2])),
237            FXSYS_GetKValue(static_cast<uint32_t>(src_scan[3])));
238        *dest_scan++ = FXRGB2GRAY(r, g, b);
239        src_scan += 4;
240      }
241    }
242  } else {
243    for (int row = 0; row < height; ++row) {
244      uint8_t* dest_scan = dest_buf + row * dest_pitch;
245      const uint8_t* src_scan =
246          pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
247      for (int col = 0; col < width; ++col) {
248        *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
249        src_scan += Bpp;
250      }
251    }
252  }
253}
254
255void ConvertBuffer_IndexCopy(uint8_t* dest_buf,
256                             int dest_pitch,
257                             int width,
258                             int height,
259                             const RetainPtr<CFX_DIBSource>& pSrcBitmap,
260                             int src_left,
261                             int src_top) {
262  if (pSrcBitmap->GetBPP() == 1) {
263    for (int row = 0; row < height; ++row) {
264      uint8_t* dest_scan = dest_buf + row * dest_pitch;
265      // Set all destination pixels to be white initially.
266      memset(dest_scan, 255, width);
267      const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
268      for (int col = src_left; col < src_left + width; ++col) {
269        // If the source bit is set, then set the destination pixel to be black.
270        if (src_scan[col / 8] & (1 << (7 - col % 8)))
271          *dest_scan = 0;
272
273        ++dest_scan;
274      }
275    }
276  } else {
277    for (int row = 0; row < height; ++row) {
278      uint8_t* dest_scan = dest_buf + row * dest_pitch;
279      const uint8_t* src_scan =
280          pSrcBitmap->GetScanline(src_top + row) + src_left;
281      memcpy(dest_scan, src_scan, width);
282    }
283  }
284}
285
286void ConvertBuffer_Plt2PltRgb8(uint8_t* dest_buf,
287                               int dest_pitch,
288                               int width,
289                               int height,
290                               const RetainPtr<CFX_DIBSource>& pSrcBitmap,
291                               int src_left,
292                               int src_top,
293                               uint32_t* dst_plt) {
294  ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
295                          src_left, src_top);
296  uint32_t* src_plt = pSrcBitmap->GetPalette();
297  int plt_size = pSrcBitmap->GetPaletteSize();
298  if (pSrcBitmap->IsCmykImage()) {
299    for (int i = 0; i < plt_size; ++i) {
300      uint8_t r;
301      uint8_t g;
302      uint8_t b;
303      std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
304          FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
305          FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
306      dst_plt[i] = FXARGB_MAKE(0xff, r, g, b);
307    }
308  } else {
309    memcpy(dst_plt, src_plt, plt_size * 4);
310  }
311}
312
313void ConvertBuffer_Rgb2PltRgb8(uint8_t* dest_buf,
314                               int dest_pitch,
315                               int width,
316                               int height,
317                               const RetainPtr<CFX_DIBSource>& pSrcBitmap,
318                               int src_left,
319                               int src_top,
320                               uint32_t* dst_plt) {
321  int bpp = pSrcBitmap->GetBPP() / 8;
322  CFX_Palette palette(pSrcBitmap);
323  const std::pair<uint32_t, uint32_t>* Luts = palette.GetLuts();
324  int lut = palette.GetLutCount();
325  const uint32_t* pal = palette.GetPalette();
326  if (lut > 256) {
327    int err;
328    int min_err;
329    int lut_256 = lut - 256;
330    for (int row = 0; row < lut_256; ++row) {
331      min_err = 1000000;
332      uint8_t r;
333      uint8_t g;
334      uint8_t b;
335      ColorDecode(Luts[row].second, &r, &g, &b);
336      uint32_t clrindex = 0;
337      for (int col = 0; col < 256; ++col) {
338        uint32_t p_color = pal[col];
339        int d_r = r - static_cast<uint8_t>(p_color >> 16);
340        int d_g = g - static_cast<uint8_t>(p_color >> 8);
341        int d_b = b - static_cast<uint8_t>(p_color);
342        err = d_r * d_r + d_g * d_g + d_b * d_b;
343        if (err < min_err) {
344          min_err = err;
345          clrindex = col;
346        }
347      }
348      palette.SetAmountLut(row, clrindex);
349    }
350  }
351  int32_t lut_1 = lut - 1;
352  for (int row = 0; row < height; ++row) {
353    uint8_t* src_scan =
354        const_cast<uint8_t*>(pSrcBitmap->GetScanline(src_top + row)) + src_left;
355    uint8_t* dest_scan = dest_buf + row * dest_pitch;
356    for (int col = 0; col < width; ++col) {
357      uint8_t* src_port = src_scan + col * bpp;
358      int r = src_port[2] & 0xf0;
359      int g = src_port[1] & 0xf0;
360      int b = src_port[0] & 0xf0;
361      uint32_t clrindex = (r << 4) + g + (b >> 4);
362      for (int i = lut_1; i >= 0; --i)
363        if (clrindex == Luts[i].second) {
364          *(dest_scan + col) = static_cast<uint8_t>(Luts[i].first);
365          break;
366        }
367    }
368  }
369  memcpy(dst_plt, pal, sizeof(uint32_t) * 256);
370}
371
372void ConvertBuffer_1bppMask2Rgb(FXDIB_Format dst_format,
373                                uint8_t* dest_buf,
374                                int dest_pitch,
375                                int width,
376                                int height,
377                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
378                                int src_left,
379                                int src_top) {
380  int comps = (dst_format & 0xff) / 8;
381  uint8_t set_gray, reset_gray;
382  set_gray = 0xff;
383  reset_gray = 0x00;
384  for (int row = 0; row < height; ++row) {
385    uint8_t* dest_scan = dest_buf + row * dest_pitch;
386    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
387    for (int col = src_left; col < src_left + width; ++col) {
388      if (src_scan[col / 8] & (1 << (7 - col % 8))) {
389        dest_scan[0] = set_gray;
390        dest_scan[1] = set_gray;
391        dest_scan[2] = set_gray;
392      } else {
393        dest_scan[0] = reset_gray;
394        dest_scan[1] = reset_gray;
395        dest_scan[2] = reset_gray;
396      }
397      dest_scan += comps;
398    }
399  }
400}
401
402void ConvertBuffer_8bppMask2Rgb(FXDIB_Format dst_format,
403                                uint8_t* dest_buf,
404                                int dest_pitch,
405                                int width,
406                                int height,
407                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
408                                int src_left,
409                                int src_top) {
410  int comps = (dst_format & 0xff) / 8;
411  for (int row = 0; row < height; ++row) {
412    uint8_t* dest_scan = dest_buf + row * dest_pitch;
413    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
414    uint8_t src_pixel;
415    for (int col = 0; col < width; ++col) {
416      src_pixel = *src_scan++;
417      *dest_scan++ = src_pixel;
418      *dest_scan++ = src_pixel;
419      *dest_scan = src_pixel;
420      dest_scan += comps - 2;
421    }
422  }
423}
424
425void ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dst_format,
426                               uint8_t* dest_buf,
427                               int dest_pitch,
428                               int width,
429                               int height,
430                               const RetainPtr<CFX_DIBSource>& pSrcBitmap,
431                               int src_left,
432                               int src_top) {
433  int comps = (dst_format & 0xff) / 8;
434  uint32_t* src_plt = pSrcBitmap->GetPalette();
435  uint32_t plt[2];
436  uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
437  if (pSrcBitmap->IsCmykImage()) {
438    plt[0] = FXCMYK_TODIB(src_plt[0]);
439    plt[1] = FXCMYK_TODIB(src_plt[1]);
440  } else {
441    bgr_ptr[0] = FXARGB_B(src_plt[0]);
442    bgr_ptr[1] = FXARGB_G(src_plt[0]);
443    bgr_ptr[2] = FXARGB_R(src_plt[0]);
444    bgr_ptr[3] = FXARGB_B(src_plt[1]);
445    bgr_ptr[4] = FXARGB_G(src_plt[1]);
446    bgr_ptr[5] = FXARGB_R(src_plt[1]);
447  }
448
449  if (pSrcBitmap->IsCmykImage()) {
450    std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
451        FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
452        FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
453    std::tie(bgr_ptr[5], bgr_ptr[4], bgr_ptr[3]) = AdobeCMYK_to_sRGB1(
454        FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
455        FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
456  }
457
458  for (int row = 0; row < height; ++row) {
459    uint8_t* dest_scan = dest_buf + row * dest_pitch;
460    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
461    for (int col = src_left; col < src_left + width; ++col) {
462      if (src_scan[col / 8] & (1 << (7 - col % 8))) {
463        *dest_scan++ = bgr_ptr[3];
464        *dest_scan++ = bgr_ptr[4];
465        *dest_scan = bgr_ptr[5];
466      } else {
467        *dest_scan++ = bgr_ptr[0];
468        *dest_scan++ = bgr_ptr[1];
469        *dest_scan = bgr_ptr[2];
470      }
471      dest_scan += comps - 2;
472    }
473  }
474}
475
476void ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dst_format,
477                               uint8_t* dest_buf,
478                               int dest_pitch,
479                               int width,
480                               int height,
481                               const RetainPtr<CFX_DIBSource>& pSrcBitmap,
482                               int src_left,
483                               int src_top) {
484  int comps = (dst_format & 0xff) / 8;
485  uint32_t* src_plt = pSrcBitmap->GetPalette();
486  uint32_t plt[256];
487  uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
488  if (!pSrcBitmap->IsCmykImage()) {
489    for (int i = 0; i < 256; ++i) {
490      *bgr_ptr++ = FXARGB_B(src_plt[i]);
491      *bgr_ptr++ = FXARGB_G(src_plt[i]);
492      *bgr_ptr++ = FXARGB_R(src_plt[i]);
493    }
494    bgr_ptr = reinterpret_cast<uint8_t*>(plt);
495  }
496
497  if (pSrcBitmap->IsCmykImage()) {
498    for (int i = 0; i < 256; ++i) {
499      std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
500          FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
501          FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
502      bgr_ptr += 3;
503    }
504    bgr_ptr = reinterpret_cast<uint8_t*>(plt);
505  }
506
507  for (int row = 0; row < height; ++row) {
508    uint8_t* dest_scan = dest_buf + row * dest_pitch;
509    const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
510    for (int col = 0; col < width; ++col) {
511      uint8_t* src_pixel = bgr_ptr + 3 * (*src_scan++);
512      *dest_scan++ = *src_pixel++;
513      *dest_scan++ = *src_pixel++;
514      *dest_scan = *src_pixel++;
515      dest_scan += comps - 2;
516    }
517  }
518}
519
520void ConvertBuffer_24bppRgb2Rgb24(uint8_t* dest_buf,
521                                  int dest_pitch,
522                                  int width,
523                                  int height,
524                                  const RetainPtr<CFX_DIBSource>& pSrcBitmap,
525                                  int src_left,
526                                  int src_top) {
527  for (int row = 0; row < height; ++row) {
528    uint8_t* dest_scan = dest_buf + row * dest_pitch;
529    const uint8_t* src_scan =
530        pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
531    memcpy(dest_scan, src_scan, width * 3);
532  }
533}
534
535void ConvertBuffer_32bppRgb2Rgb24(uint8_t* dest_buf,
536                                  int dest_pitch,
537                                  int width,
538                                  int height,
539                                  const RetainPtr<CFX_DIBSource>& pSrcBitmap,
540                                  int src_left,
541                                  int src_top) {
542  for (int row = 0; row < height; ++row) {
543    uint8_t* dest_scan = dest_buf + row * dest_pitch;
544    const uint8_t* src_scan =
545        pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
546    for (int col = 0; col < width; ++col) {
547      *dest_scan++ = *src_scan++;
548      *dest_scan++ = *src_scan++;
549      *dest_scan++ = *src_scan++;
550      ++src_scan;
551    }
552  }
553}
554
555void ConvertBuffer_Rgb2Rgb32(uint8_t* dest_buf,
556                             int dest_pitch,
557                             int width,
558                             int height,
559                             const RetainPtr<CFX_DIBSource>& pSrcBitmap,
560                             int src_left,
561                             int src_top) {
562  int comps = pSrcBitmap->GetBPP() / 8;
563  for (int row = 0; row < height; ++row) {
564    uint8_t* dest_scan = dest_buf + row * dest_pitch;
565    const uint8_t* src_scan =
566        pSrcBitmap->GetScanline(src_top + row) + src_left * comps;
567    for (int col = 0; col < width; ++col) {
568      *dest_scan++ = *src_scan++;
569      *dest_scan++ = *src_scan++;
570      *dest_scan++ = *src_scan++;
571      ++dest_scan;
572      src_scan += comps - 3;
573    }
574  }
575}
576
577void ConvertBuffer_32bppCmyk2Rgb32(uint8_t* dest_buf,
578                                   int dest_pitch,
579                                   int width,
580                                   int height,
581                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
582                                   int src_left,
583                                   int src_top) {
584  for (int row = 0; row < height; ++row) {
585    uint8_t* dest_scan = dest_buf + row * dest_pitch;
586    const uint8_t* src_scan =
587        pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
588    for (int col = 0; col < width; ++col) {
589      std::tie(dest_scan[2], dest_scan[1], dest_scan[0]) = AdobeCMYK_to_sRGB1(
590          src_scan[0], src_scan[1], src_scan[2], src_scan[3]);
591      dest_scan += 4;
592      src_scan += 4;
593    }
594  }
595}
596
597}  // namespace
598
599CFX_DIBSource::CFX_DIBSource()
600    : m_Width(0), m_Height(0), m_bpp(0), m_AlphaFlag(0), m_Pitch(0) {}
601
602CFX_DIBSource::~CFX_DIBSource() {}
603
604uint8_t* CFX_DIBSource::GetBuffer() const {
605  return nullptr;
606}
607
608bool CFX_DIBSource::SkipToScanline(int line, IFX_PauseIndicator* pPause) const {
609  return false;
610}
611
612RetainPtr<CFX_DIBitmap> CFX_DIBSource::Clone(const FX_RECT* pClip) const {
613  FX_RECT rect(0, 0, m_Width, m_Height);
614  if (pClip) {
615    rect.Intersect(*pClip);
616    if (rect.IsEmpty())
617      return nullptr;
618  }
619  auto pNewBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
620  if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat()))
621    return nullptr;
622
623  pNewBitmap->SetPalette(m_pPalette.get());
624  pNewBitmap->SetAlphaMask(m_pAlphaMask, pClip);
625  if (GetBPP() == 1 && rect.left % 8 != 0) {
626    int left_shift = rect.left % 32;
627    int right_shift = 32 - left_shift;
628    int dword_count = pNewBitmap->m_Pitch / 4;
629    for (int row = rect.top; row < rect.bottom; ++row) {
630      uint32_t* src_scan = (uint32_t*)GetScanline(row) + rect.left / 32;
631      uint32_t* dest_scan = (uint32_t*)pNewBitmap->GetScanline(row - rect.top);
632      for (int i = 0; i < dword_count; ++i) {
633        dest_scan[i] =
634            (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
635      }
636    }
637  } else {
638    int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8;
639    if (m_Pitch < static_cast<uint32_t>(copy_len))
640      copy_len = m_Pitch;
641
642    for (int row = rect.top; row < rect.bottom; ++row) {
643      const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8;
644      uint8_t* dest_scan = (uint8_t*)pNewBitmap->GetScanline(row - rect.top);
645      memcpy(dest_scan, src_scan, copy_len);
646    }
647  }
648  return pNewBitmap;
649}
650
651void CFX_DIBSource::BuildPalette() {
652  if (m_pPalette)
653    return;
654
655  if (GetBPP() == 1) {
656    m_pPalette.reset(FX_Alloc(uint32_t, 2));
657    if (IsCmykImage()) {
658      m_pPalette.get()[0] = 0xff;
659      m_pPalette.get()[1] = 0;
660    } else {
661      m_pPalette.get()[0] = 0xff000000;
662      m_pPalette.get()[1] = 0xffffffff;
663    }
664  } else if (GetBPP() == 8) {
665    m_pPalette.reset(FX_Alloc(uint32_t, 256));
666    if (IsCmykImage()) {
667      for (int i = 0; i < 256; ++i)
668        m_pPalette.get()[i] = 0xff - i;
669    } else {
670      for (int i = 0; i < 256; ++i)
671        m_pPalette.get()[i] = 0xff000000 | (i * 0x10101);
672    }
673  }
674}
675
676bool CFX_DIBSource::BuildAlphaMask() {
677  if (m_pAlphaMask)
678    return true;
679
680  m_pAlphaMask = pdfium::MakeRetain<CFX_DIBitmap>();
681  if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
682    m_pAlphaMask = nullptr;
683    return false;
684  }
685  memset(m_pAlphaMask->GetBuffer(), 0xff,
686         m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
687  return true;
688}
689
690uint32_t CFX_DIBSource::GetPaletteArgb(int index) const {
691  ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
692  if (m_pPalette)
693    return m_pPalette.get()[index];
694
695  if (IsCmykImage()) {
696    if (GetBPP() == 1)
697      return index ? 0 : 0xff;
698
699    return 0xff - index;
700  }
701  if (GetBPP() == 1)
702    return index ? 0xffffffff : 0xff000000;
703
704  return index * 0x10101 | 0xff000000;
705}
706
707void CFX_DIBSource::SetPaletteArgb(int index, uint32_t color) {
708  ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
709  if (!m_pPalette) {
710    BuildPalette();
711  }
712  m_pPalette.get()[index] = color;
713}
714
715int CFX_DIBSource::FindPalette(uint32_t color) const {
716  ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
717  if (!m_pPalette) {
718    if (IsCmykImage()) {
719      if (GetBPP() == 1)
720        return (static_cast<uint8_t>(color) == 0xff) ? 0 : 1;
721
722      return 0xff - static_cast<uint8_t>(color);
723    }
724    if (GetBPP() == 1)
725      return (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
726
727    return static_cast<uint8_t>(color);
728  }
729  int palsize = (1 << GetBPP());
730  for (int i = 0; i < palsize; ++i) {
731    if (m_pPalette.get()[i] == color)
732      return i;
733  }
734  return -1;
735}
736
737void CFX_DIBSource::GetOverlapRect(int& dest_left,
738                                   int& dest_top,
739                                   int& width,
740                                   int& height,
741                                   int src_width,
742                                   int src_height,
743                                   int& src_left,
744                                   int& src_top,
745                                   const CFX_ClipRgn* pClipRgn) {
746  if (width == 0 || height == 0)
747    return;
748
749  ASSERT(width > 0 && height > 0);
750  if (dest_left > m_Width || dest_top > m_Height) {
751    width = 0;
752    height = 0;
753    return;
754  }
755  int x_offset = dest_left - src_left;
756  int y_offset = dest_top - src_top;
757  FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height);
758  FX_RECT src_bound(0, 0, src_width, src_height);
759  src_rect.Intersect(src_bound);
760  FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset,
761                    src_rect.right + x_offset, src_rect.bottom + y_offset);
762  FX_RECT dest_bound(0, 0, m_Width, m_Height);
763  dest_rect.Intersect(dest_bound);
764  if (pClipRgn)
765    dest_rect.Intersect(pClipRgn->GetBox());
766  dest_left = dest_rect.left;
767  dest_top = dest_rect.top;
768  src_left = dest_left - x_offset;
769  src_top = dest_top - y_offset;
770  width = dest_rect.right - dest_rect.left;
771  height = dest_rect.bottom - dest_rect.top;
772}
773
774void CFX_DIBSource::SetPalette(const uint32_t* pSrc) {
775  static const uint32_t kPaletteSize = 256;
776  if (!pSrc || GetBPP() > 8) {
777    m_pPalette.reset();
778    return;
779  }
780  uint32_t pal_size = 1 << GetBPP();
781  if (!m_pPalette)
782    m_pPalette.reset(FX_Alloc(uint32_t, pal_size));
783  pal_size = std::min(pal_size, kPaletteSize);
784  memcpy(m_pPalette.get(), pSrc, pal_size * sizeof(uint32_t));
785}
786
787void CFX_DIBSource::GetPalette(uint32_t* pal, int alpha) const {
788  ASSERT(GetBPP() <= 8 && !IsCmykImage());
789  if (GetBPP() == 1) {
790    pal[0] = ((m_pPalette ? m_pPalette.get()[0] : 0xff000000) & 0xffffff) |
791             (alpha << 24);
792    pal[1] = ((m_pPalette ? m_pPalette.get()[1] : 0xffffffff) & 0xffffff) |
793             (alpha << 24);
794    return;
795  }
796  if (m_pPalette) {
797    for (int i = 0; i < 256; ++i)
798      pal[i] = (m_pPalette.get()[i] & 0x00ffffff) | (alpha << 24);
799  } else {
800    for (int i = 0; i < 256; ++i)
801      pal[i] = (i * 0x10101) | (alpha << 24);
802  }
803}
804
805RetainPtr<CFX_DIBitmap> CFX_DIBSource::CloneAlphaMask() const {
806  ASSERT(GetFormat() == FXDIB_Argb);
807  FX_RECT rect(0, 0, m_Width, m_Height);
808  auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
809  if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask))
810    return nullptr;
811
812  for (int row = rect.top; row < rect.bottom; ++row) {
813    const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3;
814    uint8_t* dest_scan =
815        const_cast<uint8_t*>(pMask->GetScanline(row - rect.top));
816    for (int col = rect.left; col < rect.right; ++col) {
817      *dest_scan++ = *src_scan;
818      src_scan += 4;
819    }
820  }
821  return pMask;
822}
823
824bool CFX_DIBSource::SetAlphaMask(const RetainPtr<CFX_DIBSource>& pAlphaMask,
825                                 const FX_RECT* pClip) {
826  if (!HasAlpha() || GetFormat() == FXDIB_Argb)
827    return false;
828
829  if (!pAlphaMask) {
830    m_pAlphaMask->Clear(0xff000000);
831    return true;
832  }
833  FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height);
834  if (pClip) {
835    rect.Intersect(*pClip);
836    if (rect.IsEmpty() || rect.Width() != m_Width ||
837        rect.Height() != m_Height) {
838      return false;
839    }
840  } else {
841    if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height)
842      return false;
843  }
844  for (int row = 0; row < m_Height; ++row) {
845    memcpy(const_cast<uint8_t*>(m_pAlphaMask->GetScanline(row)),
846           pAlphaMask->GetScanline(row + rect.top) + rect.left,
847           m_pAlphaMask->m_Pitch);
848  }
849  return true;
850}
851
852RetainPtr<CFX_DIBitmap> CFX_DIBSource::FlipImage(bool bXFlip,
853                                                 bool bYFlip) const {
854  auto pFlipped = pdfium::MakeRetain<CFX_DIBitmap>();
855  if (!pFlipped->Create(m_Width, m_Height, GetFormat()))
856    return nullptr;
857
858  pFlipped->SetPalette(m_pPalette.get());
859  uint8_t* pDestBuffer = pFlipped->GetBuffer();
860  int Bpp = m_bpp / 8;
861  for (int row = 0; row < m_Height; ++row) {
862    const uint8_t* src_scan = GetScanline(row);
863    uint8_t* dest_scan =
864        pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
865    if (!bXFlip) {
866      memcpy(dest_scan, src_scan, m_Pitch);
867      continue;
868    }
869    if (m_bpp == 1) {
870      memset(dest_scan, 0, m_Pitch);
871      for (int col = 0; col < m_Width; ++col)
872        if (src_scan[col / 8] & (1 << (7 - col % 8))) {
873          int dest_col = m_Width - col - 1;
874          dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
875        }
876    } else {
877      dest_scan += (m_Width - 1) * Bpp;
878      if (Bpp == 1) {
879        for (int col = 0; col < m_Width; ++col) {
880          *dest_scan = *src_scan;
881          --dest_scan;
882          ++src_scan;
883        }
884      } else if (Bpp == 3) {
885        for (int col = 0; col < m_Width; ++col) {
886          dest_scan[0] = src_scan[0];
887          dest_scan[1] = src_scan[1];
888          dest_scan[2] = src_scan[2];
889          dest_scan -= 3;
890          src_scan += 3;
891        }
892      } else {
893        ASSERT(Bpp == 4);
894        for (int col = 0; col < m_Width; ++col) {
895          *(uint32_t*)dest_scan = *(uint32_t*)src_scan;
896          dest_scan -= 4;
897          src_scan += 4;
898        }
899      }
900    }
901  }
902  if (m_pAlphaMask) {
903    pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
904    uint32_t dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
905    for (int row = 0; row < m_Height; ++row) {
906      const uint8_t* src_scan = m_pAlphaMask->GetScanline(row);
907      uint8_t* dest_scan =
908          pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
909      if (!bXFlip) {
910        memcpy(dest_scan, src_scan, dest_pitch);
911        continue;
912      }
913      dest_scan += (m_Width - 1);
914      for (int col = 0; col < m_Width; ++col) {
915        *dest_scan = *src_scan;
916        --dest_scan;
917        ++src_scan;
918      }
919    }
920  }
921  return pFlipped;
922}
923
924RetainPtr<CFX_DIBitmap> CFX_DIBSource::CloneConvert(FXDIB_Format dest_format) {
925  if (dest_format == GetFormat())
926    return Clone(nullptr);
927
928  auto pClone = pdfium::MakeRetain<CFX_DIBitmap>();
929  if (!pClone->Create(m_Width, m_Height, dest_format))
930    return nullptr;
931
932  RetainPtr<CFX_DIBitmap> pSrcAlpha;
933  if (HasAlpha()) {
934    if (GetFormat() == FXDIB_Argb)
935      pSrcAlpha = CloneAlphaMask();
936    else
937      pSrcAlpha = m_pAlphaMask;
938
939    if (!pSrcAlpha)
940      return nullptr;
941  }
942  bool ret = true;
943  if (dest_format & 0x0200) {
944    if (dest_format == FXDIB_Argb) {
945      ret = pSrcAlpha ? pClone->LoadChannel(FXDIB_Alpha, pSrcAlpha, FXDIB_Alpha)
946                      : pClone->LoadChannel(FXDIB_Alpha, 0xff);
947    } else {
948      ret = pClone->SetAlphaMask(pSrcAlpha, nullptr);
949    }
950  }
951  if (!ret)
952    return nullptr;
953
954  RetainPtr<CFX_DIBSource> holder(this);
955  std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
956  if (!ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(),
957                     m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
958    return nullptr;
959  }
960  if (pal_8bpp)
961    pClone->SetPalette(pal_8bpp.get());
962
963  return pClone;
964}
965
966RetainPtr<CFX_DIBitmap> CFX_DIBSource::SwapXY(bool bXFlip, bool bYFlip) const {
967  FX_RECT dest_clip(0, 0, m_Height, m_Width);
968  if (dest_clip.IsEmpty())
969    return nullptr;
970
971  auto pTransBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
972  int result_height = dest_clip.Height();
973  int result_width = dest_clip.Width();
974  if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
975    return nullptr;
976
977  pTransBitmap->SetPalette(m_pPalette.get());
978  int dest_pitch = pTransBitmap->GetPitch();
979  uint8_t* dest_buf = pTransBitmap->GetBuffer();
980  int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
981  int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
982  int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
983  int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
984  if (GetBPP() == 1) {
985    memset(dest_buf, 0xff, dest_pitch * result_height);
986    for (int row = row_start; row < row_end; ++row) {
987      const uint8_t* src_scan = GetScanline(row);
988      int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
989                     dest_clip.left;
990      uint8_t* dest_scan = dest_buf;
991      if (bYFlip)
992        dest_scan += (result_height - 1) * dest_pitch;
993      int dest_step = bYFlip ? -dest_pitch : dest_pitch;
994      for (int col = col_start; col < col_end; ++col) {
995        if (!(src_scan[col / 8] & (1 << (7 - col % 8))))
996          dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
997        dest_scan += dest_step;
998      }
999    }
1000  } else {
1001    int nBytes = GetBPP() / 8;
1002    int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1003    if (nBytes == 3)
1004      dest_step -= 2;
1005    for (int row = row_start; row < row_end; ++row) {
1006      int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1007                     dest_clip.left;
1008      uint8_t* dest_scan = dest_buf + dest_col * nBytes;
1009      if (bYFlip)
1010        dest_scan += (result_height - 1) * dest_pitch;
1011      if (nBytes == 4) {
1012        uint32_t* src_scan = (uint32_t*)GetScanline(row) + col_start;
1013        for (int col = col_start; col < col_end; ++col) {
1014          *(uint32_t*)dest_scan = *src_scan++;
1015          dest_scan += dest_step;
1016        }
1017      } else {
1018        const uint8_t* src_scan = GetScanline(row) + col_start * nBytes;
1019        if (nBytes == 1) {
1020          for (int col = col_start; col < col_end; ++col) {
1021            *dest_scan = *src_scan++;
1022            dest_scan += dest_step;
1023          }
1024        } else {
1025          for (int col = col_start; col < col_end; ++col) {
1026            *dest_scan++ = *src_scan++;
1027            *dest_scan++ = *src_scan++;
1028            *dest_scan = *src_scan++;
1029            dest_scan += dest_step;
1030          }
1031        }
1032      }
1033    }
1034  }
1035  if (m_pAlphaMask) {
1036    dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch();
1037    dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer();
1038    int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1039    for (int row = row_start; row < row_end; ++row) {
1040      int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1041                     dest_clip.left;
1042      uint8_t* dest_scan = dest_buf + dest_col;
1043      if (bYFlip)
1044        dest_scan += (result_height - 1) * dest_pitch;
1045      const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start;
1046      for (int col = col_start; col < col_end; ++col) {
1047        *dest_scan = *src_scan++;
1048        dest_scan += dest_step;
1049      }
1050    }
1051  }
1052  return pTransBitmap;
1053}
1054
1055RetainPtr<CFX_DIBitmap> CFX_DIBSource::TransformTo(
1056    const CFX_Matrix* pDestMatrix,
1057    int* result_left,
1058    int* result_top) {
1059  RetainPtr<CFX_DIBSource> holder(this);
1060  CFX_ImageTransformer transformer(holder, pDestMatrix, 0, nullptr);
1061  transformer.Continue(nullptr);
1062  *result_left = transformer.result().left;
1063  *result_top = transformer.result().top;
1064  return transformer.DetachBitmap();
1065}
1066
1067RetainPtr<CFX_DIBitmap> CFX_DIBSource::StretchTo(int dest_width,
1068                                                 int dest_height,
1069                                                 uint32_t flags,
1070                                                 const FX_RECT* pClip) {
1071  RetainPtr<CFX_DIBSource> holder(this);
1072  FX_RECT clip_rect(0, 0, abs(dest_width), abs(dest_height));
1073  if (pClip)
1074    clip_rect.Intersect(*pClip);
1075
1076  if (clip_rect.IsEmpty())
1077    return nullptr;
1078
1079  if (dest_width == m_Width && dest_height == m_Height)
1080    return Clone(&clip_rect);
1081
1082  CFX_BitmapStorer storer;
1083  CFX_ImageStretcher stretcher(&storer, holder, dest_width, dest_height,
1084                               clip_rect, flags);
1085  if (stretcher.Start())
1086    stretcher.Continue(nullptr);
1087
1088  return storer.Detach();
1089}
1090
1091// static
1092bool CFX_DIBSource::ConvertBuffer(
1093    FXDIB_Format dest_format,
1094    uint8_t* dest_buf,
1095    int dest_pitch,
1096    int width,
1097    int height,
1098    const RetainPtr<CFX_DIBSource>& pSrcBitmap,
1099    int src_left,
1100    int src_top,
1101    std::unique_ptr<uint32_t, FxFreeDeleter>* p_pal) {
1102  FXDIB_Format src_format = pSrcBitmap->GetFormat();
1103  switch (dest_format) {
1104    case FXDIB_Invalid:
1105    case FXDIB_1bppCmyk:
1106    case FXDIB_1bppMask:
1107    case FXDIB_1bppRgb:
1108      NOTREACHED();
1109      return false;
1110    case FXDIB_8bppMask: {
1111      if ((src_format & 0xff) == 1) {
1112        if (pSrcBitmap->GetPalette()) {
1113          ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
1114                                     pSrcBitmap, src_left, src_top);
1115          return true;
1116        }
1117        ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
1118                                    pSrcBitmap, src_left, src_top);
1119        return true;
1120      }
1121      if ((src_format & 0xff) == 8) {
1122        if (pSrcBitmap->GetPalette()) {
1123          ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
1124                                     pSrcBitmap, src_left, src_top);
1125          return true;
1126        }
1127        ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
1128                                    pSrcBitmap, src_left, src_top);
1129        return true;
1130      }
1131      if ((src_format & 0xff) >= 24) {
1132        ConvertBuffer_RgbOrCmyk2Gray(dest_buf, dest_pitch, width, height,
1133                                     pSrcBitmap, src_left, src_top);
1134        return true;
1135      }
1136      return false;
1137    }
1138    case FXDIB_8bppRgb:
1139    case FXDIB_8bppRgba: {
1140      if ((src_format & 0xff) == 8 && !pSrcBitmap->GetPalette()) {
1141        return ConvertBuffer(FXDIB_8bppMask, dest_buf, dest_pitch, width,
1142                             height, pSrcBitmap, src_left, src_top, p_pal);
1143      }
1144      p_pal->reset(FX_Alloc(uint32_t, 256));
1145      if (((src_format & 0xff) == 1 || (src_format & 0xff) == 8) &&
1146          pSrcBitmap->GetPalette()) {
1147        ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
1148                                  pSrcBitmap, src_left, src_top, p_pal->get());
1149        return true;
1150      }
1151      if ((src_format & 0xff) >= 24) {
1152        ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
1153                                  pSrcBitmap, src_left, src_top, p_pal->get());
1154        return true;
1155      }
1156      return false;
1157    }
1158    case FXDIB_Rgb:
1159    case FXDIB_Rgba: {
1160      if ((src_format & 0xff) == 1) {
1161        if (pSrcBitmap->GetPalette()) {
1162          ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
1163                                    height, pSrcBitmap, src_left, src_top);
1164          return true;
1165        }
1166        ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
1167                                   height, pSrcBitmap, src_left, src_top);
1168        return true;
1169      }
1170      if ((src_format & 0xff) == 8) {
1171        if (pSrcBitmap->GetPalette()) {
1172          ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
1173                                    height, pSrcBitmap, src_left, src_top);
1174          return true;
1175        }
1176        ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
1177                                   height, pSrcBitmap, src_left, src_top);
1178        return true;
1179      }
1180      if ((src_format & 0xff) == 24) {
1181        ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
1182                                     pSrcBitmap, src_left, src_top);
1183        return true;
1184      }
1185      if ((src_format & 0xff) == 32) {
1186        ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
1187                                     pSrcBitmap, src_left, src_top);
1188        return true;
1189      }
1190      return false;
1191    }
1192    case FXDIB_Argb:
1193    case FXDIB_Rgb32: {
1194      if ((src_format & 0xff) == 1) {
1195        if (pSrcBitmap->GetPalette()) {
1196          ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
1197                                    height, pSrcBitmap, src_left, src_top);
1198          return true;
1199        }
1200        ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
1201                                   height, pSrcBitmap, src_left, src_top);
1202        return true;
1203      }
1204      if ((src_format & 0xff) == 8) {
1205        if (pSrcBitmap->GetPalette()) {
1206          ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
1207                                    height, pSrcBitmap, src_left, src_top);
1208          return true;
1209        }
1210        ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
1211                                   height, pSrcBitmap, src_left, src_top);
1212        return true;
1213      }
1214      if ((src_format & 0xff) >= 24) {
1215        if (src_format & 0x0400) {
1216          ConvertBuffer_32bppCmyk2Rgb32(dest_buf, dest_pitch, width, height,
1217                                        pSrcBitmap, src_left, src_top);
1218          return true;
1219        }
1220        ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, pSrcBitmap,
1221                                src_left, src_top);
1222        return true;
1223      }
1224      return false;
1225    }
1226    default:
1227      return false;
1228  }
1229}
1230