aa7fe6c608e1ea4adec39427238de58b7944150c
[pdfium.git] / core / src / fxge / dib / fx_dib_main.cpp
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 "../../../include/fxge/fx_dib.h"
8 #include "../../../include/fxge/fx_ge.h"
9 #include "../../../include/fxcodec/fx_codec.h"
10 #include "dib_int.h"
11 #include <limits.h>
12 FX_BOOL ConvertBuffer(FXDIB_Format dest_format, uint8_t* dest_buf, int dest_pitch, int width, int height,
13                       const CFX_DIBSource* pSrcBitmap, int src_left, int src_top, FX_DWORD*& pal, void* pIccTransform);
14 void CmykDecode(FX_DWORD cmyk, int& c, int& m, int& y, int& k)
15 {
16     c = FXSYS_GetCValue(cmyk);
17     m = FXSYS_GetMValue(cmyk);
18     y = FXSYS_GetYValue(cmyk);
19     k = FXSYS_GetKValue(cmyk);
20 }
21 void ArgbDecode(FX_DWORD argb, int& a, int& r, int& g, int& b)
22 {
23     a = FXARGB_A(argb);
24     r = FXARGB_R(argb);
25     g = FXARGB_G(argb);
26     b = FXARGB_B(argb);
27 }
28 void ArgbDecode(FX_DWORD argb, int& a, FX_COLORREF& rgb)
29 {
30     a = FXARGB_A(argb);
31     rgb = FXSYS_RGB(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
32 }
33 FX_DWORD ArgbEncode(int a, FX_COLORREF rgb)
34 {
35     return FXARGB_MAKE(a, FXSYS_GetRValue(rgb), FXSYS_GetGValue(rgb), FXSYS_GetBValue(rgb));
36 }
37 CFX_DIBSource::CFX_DIBSource()
38 {
39     m_bpp = 0;
40     m_AlphaFlag = 0;
41     m_Width = m_Height = 0;
42     m_Pitch = 0;
43     m_pPalette = NULL;
44     m_pAlphaMask = NULL;
45 }
46 CFX_DIBSource::~CFX_DIBSource()
47 {
48     if (m_pPalette) {
49         FX_Free(m_pPalette);
50     }
51     if (m_pAlphaMask) {
52         delete m_pAlphaMask;
53     }
54 }
55 CFX_DIBitmap::CFX_DIBitmap()
56 {
57     m_bExtBuf = FALSE;
58     m_pBuffer = NULL;
59     m_pPalette = NULL;
60 }
61 #define _MAX_OOM_LIMIT_ 12000000
62 FX_BOOL CFX_DIBitmap::Create(int width, int height, FXDIB_Format format, uint8_t* pBuffer, int pitch)
63 {
64     m_pBuffer = NULL;
65     m_bpp = (uint8_t)format;
66     m_AlphaFlag = (uint8_t)(format >> 8);
67     m_Width = m_Height = m_Pitch = 0;
68     if (width <= 0 || height <= 0 || pitch < 0) {
69         return FALSE;
70     }
71     if ((INT_MAX - 31) / width < (format & 0xff)) {
72         return FALSE;
73     }
74     if (!pitch) {
75         pitch = (width * (format & 0xff) + 31) / 32 * 4;
76     }
77     if ((1 << 30) / pitch < height) {
78         return FALSE;
79     }
80     if (pBuffer) {
81         m_pBuffer = pBuffer;
82         m_bExtBuf = TRUE;
83     } else {
84         int size = pitch * height + 4;
85         int oomlimit = _MAX_OOM_LIMIT_;
86         if (oomlimit >= 0 && size >= oomlimit) {
87             m_pBuffer = FX_TryAlloc(uint8_t, size);
88             if (m_pBuffer == NULL) {
89                 return FALSE;
90             }
91         } else {
92             m_pBuffer = FX_Alloc(uint8_t, size);
93         }
94     }
95     m_Width = width;
96     m_Height = height;
97     m_Pitch = pitch;
98     if (HasAlpha() && format != FXDIB_Argb) {
99         FX_BOOL ret = TRUE;
100         ret = BuildAlphaMask();
101         if (!ret) {
102             if (!m_bExtBuf && m_pBuffer) {
103                 FX_Free(m_pBuffer);
104                 m_pBuffer = NULL;
105                 m_Width = m_Height = m_Pitch = 0;
106                 return FALSE;
107             }
108         }
109     }
110     return TRUE;
111 }
112 FX_BOOL CFX_DIBitmap::Copy(const CFX_DIBSource* pSrc)
113 {
114     if (m_pBuffer) {
115         return FALSE;
116     }
117     if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat())) {
118         return FALSE;
119     }
120     CopyPalette(pSrc->GetPalette());
121     CopyAlphaMask(pSrc->m_pAlphaMask);
122     for (int row = 0; row < pSrc->GetHeight(); row ++) {
123         FXSYS_memcpy(m_pBuffer + row * m_Pitch, pSrc->GetScanline(row), m_Pitch);
124     }
125     return TRUE;
126 }
127 CFX_DIBitmap::~CFX_DIBitmap()
128 {
129     if (m_pBuffer && !m_bExtBuf) {
130         FX_Free(m_pBuffer);
131     }
132     m_pBuffer = NULL;
133 }
134 void CFX_DIBitmap::TakeOver(CFX_DIBitmap* pSrcBitmap)
135 {
136     if (m_pBuffer && !m_bExtBuf) {
137         FX_Free(m_pBuffer);
138     }
139     if (m_pPalette) {
140         FX_Free(m_pPalette);
141     }
142     if (m_pAlphaMask) {
143         delete m_pAlphaMask;
144     }
145     m_pBuffer = pSrcBitmap->m_pBuffer;
146     m_pPalette = pSrcBitmap->m_pPalette;
147     m_pAlphaMask = pSrcBitmap->m_pAlphaMask;
148     pSrcBitmap->m_pBuffer = NULL;
149     pSrcBitmap->m_pPalette = NULL;
150     pSrcBitmap->m_pAlphaMask = NULL;
151     m_bpp = pSrcBitmap->m_bpp;
152     m_bExtBuf = pSrcBitmap->m_bExtBuf;
153     m_AlphaFlag = pSrcBitmap->m_AlphaFlag;
154     m_Width = pSrcBitmap->m_Width;
155     m_Height = pSrcBitmap->m_Height;
156     m_Pitch = pSrcBitmap->m_Pitch;
157 }
158 CFX_DIBitmap* CFX_DIBSource::Clone(const FX_RECT* pClip) const
159 {
160     FX_RECT rect(0, 0, m_Width, m_Height);
161     if (pClip) {
162         rect.Intersect(*pClip);
163         if (rect.IsEmpty()) {
164             return NULL;
165         }
166     }
167     CFX_DIBitmap* pNewBitmap = new CFX_DIBitmap;
168     if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat())) {
169         delete pNewBitmap;
170         return NULL;
171     }
172     pNewBitmap->CopyPalette(m_pPalette);
173     pNewBitmap->CopyAlphaMask(m_pAlphaMask, pClip);
174     if (GetBPP() == 1 && rect.left % 8 != 0) {
175         int left_shift = rect.left % 32;
176         int right_shift = 32 - left_shift;
177         int dword_count = pNewBitmap->m_Pitch / 4;
178         for (int row = rect.top; row < rect.bottom; row ++) {
179             FX_DWORD* src_scan = (FX_DWORD*)GetScanline(row) + rect.left / 32;
180             FX_DWORD* dest_scan = (FX_DWORD*)pNewBitmap->GetScanline(row - rect.top);
181             for (int i = 0; i < dword_count; i ++) {
182                 dest_scan[i] = (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
183             }
184         }
185     } else {
186         int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8;
187         if (m_Pitch < (FX_DWORD)copy_len) {
188             copy_len = m_Pitch;
189         }
190         for (int row = rect.top; row < rect.bottom; row ++) {
191             const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8;
192             uint8_t* dest_scan = (uint8_t*)pNewBitmap->GetScanline(row - rect.top);
193             FXSYS_memcpy(dest_scan, src_scan, copy_len);
194         }
195     }
196     return pNewBitmap;
197 }
198 void CFX_DIBSource::BuildPalette()
199 {
200     if (m_pPalette) {
201         return;
202     }
203     if (GetBPP() == 1) {
204         m_pPalette = FX_Alloc(FX_DWORD, 2);
205         if(IsCmykImage()) {
206             m_pPalette[0] = 0xff;
207             m_pPalette[1] = 0;
208         } else {
209             m_pPalette[0] = 0xff000000;
210             m_pPalette[1] = 0xffffffff;
211         }
212     } else if (GetBPP() == 8) {
213         m_pPalette = FX_Alloc(FX_DWORD, 256);
214         if(IsCmykImage()) {
215             for (int i = 0; i < 256; i ++) {
216                 m_pPalette[i] = 0xff - i;
217             }
218         } else {
219             for (int i = 0; i < 256; i ++) {
220                 m_pPalette[i] = 0xff000000 | (i * 0x10101);
221             }
222         }
223     }
224 }
225 FX_BOOL CFX_DIBSource::BuildAlphaMask()
226 {
227     if (m_pAlphaMask) {
228         return TRUE;
229     }
230     m_pAlphaMask = new CFX_DIBitmap;
231     if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
232         delete m_pAlphaMask;
233         m_pAlphaMask = NULL;
234         return FALSE;
235     }
236     FXSYS_memset(m_pAlphaMask->GetBuffer(), 0xff, m_pAlphaMask->GetHeight()*m_pAlphaMask->GetPitch());
237     return TRUE;
238 }
239 FX_DWORD CFX_DIBSource::GetPaletteEntry(int index) const
240 {
241     ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
242     if (m_pPalette) {
243         return m_pPalette[index];
244     }
245     if (IsCmykImage()) {
246         if (GetBPP() == 1) {
247             return index ? 0 : 0xff;
248         }
249         return 0xff - index;
250     }
251     if (GetBPP() == 1) {
252         return index ? 0xffffffff : 0xff000000;
253     }
254     return index * 0x10101 | 0xff000000;
255 }
256 void CFX_DIBSource::SetPaletteEntry(int index, FX_DWORD color)
257 {
258     ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
259     if (m_pPalette == NULL) {
260         BuildPalette();
261     }
262     m_pPalette[index] = color;
263 }
264 int CFX_DIBSource::FindPalette(FX_DWORD color) const
265 {
266     ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
267     if (m_pPalette == NULL) {
268         if (IsCmykImage()) {
269             if (GetBPP() == 1) {
270                 return ((uint8_t)color == 0xff) ? 0 : 1;
271             }
272             return 0xff - (uint8_t)color;
273         }
274         if (GetBPP() == 1) {
275             return ((uint8_t)color == 0xff) ? 1 : 0;
276         }
277         return (uint8_t)color;
278     }
279     int palsize = (1 << GetBPP());
280     for (int i = 0; i < palsize; i ++)
281         if (m_pPalette[i] == color) {
282             return i;
283         }
284     return -1;
285 }
286 void CFX_DIBitmap::Clear(FX_DWORD color)
287 {
288     if (m_pBuffer == NULL) {
289         return;
290     }
291     switch (GetFormat()) {
292         case FXDIB_1bppMask:
293             FXSYS_memset(m_pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
294             break;
295         case FXDIB_1bppRgb: {
296                 int index = FindPalette(color);
297                 FXSYS_memset(m_pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
298                 break;
299             }
300         case FXDIB_8bppMask:
301             FXSYS_memset(m_pBuffer, color >> 24, m_Pitch * m_Height);
302             break;
303         case FXDIB_8bppRgb: {
304                 int index = FindPalette(color);
305                 FXSYS_memset(m_pBuffer, index, m_Pitch * m_Height);
306                 break;
307             }
308         case FXDIB_Rgb:
309         case FXDIB_Rgba: {
310                 int a, r, g, b;
311                 ArgbDecode(color, a, r, g, b);
312                 if (r == g && g == b) {
313                     FXSYS_memset(m_pBuffer, r, m_Pitch * m_Height);
314                 } else {
315                     int byte_pos = 0;
316                     for (int col = 0; col < m_Width; col ++) {
317                         m_pBuffer[byte_pos++] = b;
318                         m_pBuffer[byte_pos++] = g;
319                         m_pBuffer[byte_pos++] = r;
320                     }
321                     for (int row = 1; row < m_Height; row ++) {
322                         FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch);
323                     }
324                 }
325                 break;
326             }
327         case FXDIB_Rgb32:
328         case FXDIB_Argb: {
329                 color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
330                 for (int i = 0; i < m_Width; i ++) {
331                     ((FX_DWORD*)m_pBuffer)[i] = color;
332                 }
333                 for (int row = 1; row < m_Height; row ++) {
334                     FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch);
335                 }
336                 break;
337             }
338         default:
339             break;
340     }
341 }
342 void CFX_DIBSource::GetOverlapRect(int& dest_left, int& dest_top, int& width, int& height,
343                                    int src_width, int src_height, int& src_left, int& src_top,
344                                    const CFX_ClipRgn* pClipRgn)
345 {
346     if (width == 0 || height == 0) {
347         return;
348     }
349     ASSERT(width > 0 && height > 0);
350     if (dest_left > m_Width || dest_top > m_Height) {
351         width = 0;
352         height = 0;
353         return;
354     }
355     int x_offset = dest_left - src_left;
356     int y_offset = dest_top - src_top;
357     FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height);
358     FX_RECT src_bound(0, 0, src_width, src_height);
359     src_rect.Intersect(src_bound);
360     FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset,
361                       src_rect.right + x_offset, src_rect.bottom + y_offset);
362     FX_RECT dest_bound(0, 0, m_Width, m_Height);
363     dest_rect.Intersect(dest_bound);
364     if (pClipRgn) {
365         dest_rect.Intersect(pClipRgn->GetBox());
366     }
367     dest_left = dest_rect.left;
368     dest_top = dest_rect.top;
369     src_left = dest_left - x_offset;
370     src_top = dest_top - y_offset;
371     width = dest_rect.right - dest_rect.left;
372     height = dest_rect.bottom - dest_rect.top;
373 }
374 FX_BOOL CFX_DIBitmap::TransferBitmap(int dest_left, int dest_top, int width, int height,
375                                      const CFX_DIBSource* pSrcBitmap, int src_left, int src_top, void* pIccTransform)
376 {
377     if (m_pBuffer == NULL) {
378         return FALSE;
379     }
380     GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left, src_top, NULL);
381     if (width == 0 || height == 0) {
382         return TRUE;
383     }
384     FXDIB_Format dest_format = GetFormat();
385     FXDIB_Format src_format = pSrcBitmap->GetFormat();
386     if (dest_format == src_format && pIccTransform == NULL) {
387         if (GetBPP() == 1) {
388             for (int row = 0; row < height; row ++) {
389                 uint8_t* dest_scan = m_pBuffer + (dest_top + row) * m_Pitch;
390                 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
391                 for (int col = 0; col < width; col ++) {
392                     if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
393                         dest_scan[(dest_left + col) / 8] |= 1 << (7 - (dest_left + col) % 8);
394                     } else {
395                         dest_scan[(dest_left + col) / 8] &= ~(1 << (7 - (dest_left + col) % 8));
396                     }
397                 }
398             }
399         } else {
400             int Bpp = GetBPP() / 8;
401             for (int row = 0; row < height; row ++) {
402                 uint8_t* dest_scan = m_pBuffer + (dest_top + row) * m_Pitch + dest_left * Bpp;
403                 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
404                 FXSYS_memcpy(dest_scan, src_scan, width * Bpp);
405             }
406         }
407     } else {
408         if (m_pPalette) {
409             return FALSE;
410         }
411         if (m_bpp == 8) {
412             dest_format = FXDIB_8bppMask;
413         }
414         uint8_t* dest_buf = m_pBuffer + dest_top * m_Pitch + dest_left * GetBPP() / 8;
415         FX_DWORD* d_plt = NULL;
416         if(!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height, pSrcBitmap, src_left, src_top, d_plt, pIccTransform)) {
417             return FALSE;
418         }
419     }
420     return TRUE;
421 }
422 FX_BOOL CFX_DIBitmap::TransferMask(int dest_left, int dest_top, int width, int height,
423                                    const CFX_DIBSource* pMask, FX_DWORD color, int src_left, int src_top, int alpha_flag, void* pIccTransform)
424 {
425     if (m_pBuffer == NULL) {
426         return FALSE;
427     }
428     ASSERT(HasAlpha() && (m_bpp >= 24));
429     ASSERT(pMask->IsAlphaMask());
430     if (!HasAlpha() || !pMask->IsAlphaMask() || m_bpp < 24) {
431         return FALSE;
432     }
433     GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(), pMask->GetHeight(), src_left, src_top, NULL);
434     if (width == 0 || height == 0) {
435         return TRUE;
436     }
437     int src_bpp = pMask->GetBPP();
438     int alpha;
439     FX_DWORD dst_color;
440     if (alpha_flag >> 8) {
441         alpha = alpha_flag & 0xff;
442         dst_color = FXCMYK_TODIB(color);
443     } else {
444         alpha = FXARGB_A(color);
445         dst_color = FXARGB_TODIB(color);
446     }
447     uint8_t* color_p = (uint8_t*)&dst_color;
448     if (pIccTransform && CFX_GEModule::Get()->GetCodecModule() && CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
449         ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
450         pIccModule->TranslateScanline(pIccTransform, color_p, color_p, 1);
451     } else {
452         if (alpha_flag >> 8 && !IsCmykImage())
453             AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), FXSYS_GetYValue(color), FXSYS_GetKValue(color),
454                                color_p[2], color_p[1], color_p[0]);
455         else if (!(alpha_flag >> 8) && IsCmykImage()) {
456             return FALSE;
457         }
458     }
459     if(!IsCmykImage()) {
460         color_p[3] = (uint8_t)alpha;
461     }
462     if (GetFormat() == FXDIB_Argb) {
463         for (int row = 0; row < height; row ++) {
464             FX_DWORD* dest_pos = (FX_DWORD*)(m_pBuffer + (dest_top + row) * m_Pitch + dest_left * 4);
465             const uint8_t* src_scan = pMask->GetScanline(src_top + row);
466             if (src_bpp == 1) {
467                 for (int col = 0; col < width; col ++) {
468                     int src_bitpos = src_left + col;
469                     if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) {
470                         *dest_pos = dst_color;
471                     } else {
472                         *dest_pos = 0;
473                     }
474                     dest_pos ++;
475                 }
476             } else {
477                 src_scan += src_left;
478                 dst_color = FXARGB_TODIB(dst_color);
479                 dst_color &= 0xffffff;
480                 for (int col = 0; col < width; col ++) {
481                     FXARGB_SETDIB(dest_pos++, dst_color | ((alpha * (*src_scan++) / 255) << 24));
482                 }
483             }
484         }
485     } else {
486         int comps = m_bpp / 8;
487         for (int row = 0; row < height; row ++) {
488             uint8_t* dest_color_pos = m_pBuffer + (dest_top + row) * m_Pitch + dest_left * comps;
489             uint8_t* dest_alpha_pos = (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left;
490             const uint8_t* src_scan = pMask->GetScanline(src_top + row);
491             if (src_bpp == 1) {
492                 for (int col = 0; col < width; col ++) {
493                     int src_bitpos = src_left + col;
494                     if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) {
495                         FXSYS_memcpy(dest_color_pos, color_p, comps);
496                         *dest_alpha_pos = 0xff;
497                     } else {
498                         FXSYS_memset(dest_color_pos, 0, comps);
499                         *dest_alpha_pos = 0;
500                     }
501                     dest_color_pos += comps;
502                     dest_alpha_pos ++;
503                 }
504             } else {
505                 src_scan += src_left;
506                 for (int col = 0; col < width; col ++) {
507                     FXSYS_memcpy(dest_color_pos, color_p, comps);
508                     dest_color_pos += comps;
509                     *dest_alpha_pos++ = (alpha * (*src_scan++) / 255);
510                 }
511             }
512         }
513     }
514     return TRUE;
515 }
516 void CFX_DIBSource::CopyPalette(const FX_DWORD* pSrc, FX_DWORD size)
517 {
518     if (pSrc == NULL || GetBPP() > 8) {
519         if (m_pPalette) {
520             FX_Free(m_pPalette);
521         }
522         m_pPalette = NULL;
523     } else {
524         FX_DWORD pal_size = 1 << GetBPP();
525         if (m_pPalette == NULL) {
526             m_pPalette = FX_Alloc(FX_DWORD, pal_size);
527         }
528         if (pal_size > size) {
529             pal_size = size;
530         }
531         FXSYS_memcpy(m_pPalette, pSrc, pal_size * sizeof(FX_DWORD));
532     }
533 }
534 void CFX_DIBSource::GetPalette(FX_DWORD* pal, int alpha) const
535 {
536     ASSERT(GetBPP() <= 8 && !IsCmykImage());
537     if (GetBPP() == 1) {
538         pal[0] = ((m_pPalette ? m_pPalette[0] : 0xff000000) & 0xffffff) | (alpha << 24);
539         pal[1] = ((m_pPalette ? m_pPalette[1] : 0xffffffff) & 0xffffff) | (alpha << 24);
540         return;
541     }
542     if (m_pPalette) {
543         for (int i = 0; i < 256; i ++) {
544             pal[i] = (m_pPalette[i] & 0x00ffffff) | (alpha << 24);
545         }
546     } else {
547         for (int i = 0; i < 256; i ++) {
548             pal[i] = (i * 0x10101) | (alpha << 24);
549         }
550     }
551 }
552 CFX_DIBitmap* CFX_DIBSource::GetAlphaMask(const FX_RECT* pClip) const
553 {
554     ASSERT(GetFormat() == FXDIB_Argb);
555     FX_RECT rect(0, 0, m_Width, m_Height);
556     if (pClip) {
557         rect.Intersect(*pClip);
558         if (rect.IsEmpty()) {
559             return NULL;
560         }
561     }
562     CFX_DIBitmap* pMask = new CFX_DIBitmap;
563     if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask)) {
564         delete pMask;
565         return NULL;
566     }
567     for (int row = rect.top; row < rect.bottom; row ++) {
568         const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3;
569         uint8_t* dest_scan = (uint8_t*)pMask->GetScanline(row - rect.top);
570         for (int col = rect.left; col < rect.right; col ++) {
571             *dest_scan ++ = *src_scan;
572             src_scan += 4;
573         }
574     }
575     return pMask;
576 }
577 FX_BOOL CFX_DIBSource::CopyAlphaMask(const CFX_DIBSource* pAlphaMask, const FX_RECT* pClip)
578 {
579     if (!HasAlpha() || GetFormat() == FXDIB_Argb) {
580         return FALSE;
581     }
582     if (pAlphaMask) {
583         FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height);
584         if (pClip) {
585             rect.Intersect(*pClip);
586             if (rect.IsEmpty() || rect.Width() != m_Width || rect.Height() != m_Height) {
587                 return FALSE;
588             }
589         } else {
590             if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height) {
591                 return FALSE;
592             }
593         }
594         for (int row = 0; row < m_Height; row ++)
595             FXSYS_memcpy((void*)m_pAlphaMask->GetScanline(row),
596                            pAlphaMask->GetScanline(row + rect.top) + rect.left, m_pAlphaMask->m_Pitch);
597     } else {
598         m_pAlphaMask->Clear(0xff000000);
599     }
600     return TRUE;
601 }
602 const int g_ChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3};
603 FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, const CFX_DIBSource* pSrcBitmap, FXDIB_Channel srcChannel)
604 {
605     if (m_pBuffer == NULL) {
606         return FALSE;
607     }
608     CFX_DIBSource* pSrcClone = (CFX_DIBSource*)pSrcBitmap;
609     CFX_DIBitmap* pDst = this;
610     int destOffset, srcOffset;
611     if (srcChannel == FXDIB_Alpha) {
612         if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask()) {
613             return FALSE;
614         }
615         if (pSrcBitmap->GetBPP() == 1) {
616             pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask);
617             if (pSrcClone == NULL) {
618                 return FALSE;
619             }
620         }
621         if(pSrcBitmap->GetFormat() == FXDIB_Argb) {
622             srcOffset = 3;
623         } else {
624             srcOffset = 0;
625         }
626     } else {
627         if (pSrcBitmap->IsAlphaMask()) {
628             return FALSE;
629         }
630         if (pSrcBitmap->GetBPP() < 24) {
631             if (pSrcBitmap->IsCmykImage()) {
632                 pSrcClone = pSrcBitmap->CloneConvert((FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x20));
633             } else {
634                 pSrcClone = pSrcBitmap->CloneConvert((FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x18));
635             }
636             if (pSrcClone == NULL) {
637                 return FALSE;
638             }
639         }
640         srcOffset = g_ChannelOffset[srcChannel];
641     }
642     if (destChannel == FXDIB_Alpha) {
643         if (IsAlphaMask()) {
644             if(!ConvertFormat(FXDIB_8bppMask)) {
645                 if (pSrcClone != pSrcBitmap) {
646                     delete pSrcClone;
647                 }
648                 return FALSE;
649             }
650             destOffset = 0;
651         } else {
652             destOffset = 0;
653             if(!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
654                 if (pSrcClone != pSrcBitmap) {
655                     delete pSrcClone;
656                 }
657                 return FALSE;
658             }
659             if (GetFormat() == FXDIB_Argb) {
660                 destOffset = 3;
661             }
662         }
663     } else {
664         if (IsAlphaMask()) {
665             if (pSrcClone != pSrcBitmap) {
666                 delete pSrcClone;
667             }
668             return FALSE;
669         }
670         if (GetBPP() < 24) {
671             if (HasAlpha()) {
672                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
673                     if (pSrcClone != pSrcBitmap) {
674                         delete pSrcClone;
675                     }
676                     return FALSE;
677                 }
678             } else
679 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
680                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
681 #else
682                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
683 #endif
684                     if (pSrcClone != pSrcBitmap) {
685                         delete pSrcClone;
686                     }
687                     return FALSE;
688                 }
689         }
690         destOffset = g_ChannelOffset[destChannel];
691     }
692     if (srcChannel == FXDIB_Alpha && pSrcClone->m_pAlphaMask) {
693         CFX_DIBitmap* pAlphaMask = pSrcClone->m_pAlphaMask;
694         if (pSrcClone->GetWidth() != m_Width || pSrcClone->GetHeight() != m_Height) {
695             if (pAlphaMask) {
696                 pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height);
697                 if (pAlphaMask == NULL) {
698                     if (pSrcClone != pSrcBitmap) {
699                         delete pSrcClone;
700                     }
701                     return FALSE;
702                 }
703             }
704         }
705         if (pSrcClone != pSrcBitmap) {
706             pSrcClone->m_pAlphaMask = NULL;
707             delete pSrcClone;
708         }
709         pSrcClone = pAlphaMask;
710         srcOffset = 0;
711     } else if (pSrcClone->GetWidth() != m_Width || pSrcClone->GetHeight() != m_Height) {
712         CFX_DIBitmap* pSrcMatched = pSrcClone->StretchTo(m_Width, m_Height);
713         if (pSrcClone != pSrcBitmap) {
714             delete pSrcClone;
715         }
716         if (pSrcMatched == NULL) {
717             return FALSE;
718         }
719         pSrcClone = pSrcMatched;
720     }
721     if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
722         pDst = m_pAlphaMask;
723         destOffset = 0;
724     }
725     int srcBytes = pSrcClone->GetBPP() / 8;
726     int destBytes = pDst->GetBPP() / 8;
727     for (int row = 0; row < m_Height; row ++) {
728         uint8_t* dest_pos = (uint8_t*)pDst->GetScanline(row) + destOffset;
729         const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset;
730         for (int col = 0; col < m_Width; col ++) {
731             *dest_pos = *src_pos;
732             dest_pos += destBytes;
733             src_pos += srcBytes;
734         }
735     }
736     if (pSrcClone != pSrcBitmap && pSrcClone != pSrcBitmap->m_pAlphaMask) {
737         delete pSrcClone;
738     }
739     return TRUE;
740 }
741 FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value)
742 {
743     if (m_pBuffer == NULL) {
744         return FALSE;
745     }
746     int destOffset;
747     if (destChannel == FXDIB_Alpha) {
748         if (IsAlphaMask()) {
749             if(!ConvertFormat(FXDIB_8bppMask)) {
750                 return FALSE;
751             }
752             destOffset = 0;
753         } else {
754             destOffset = 0;
755             if(!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
756                 return FALSE;
757             }
758             if (GetFormat() == FXDIB_Argb) {
759                 destOffset = 3;
760             }
761         }
762     } else {
763         if (IsAlphaMask()) {
764             return FALSE;
765         }
766         if (GetBPP() < 24) {
767             if (HasAlpha()) {
768                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
769                     return FALSE;
770                 }
771             } else
772 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
773                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
774                     return FALSE;
775                 }
776 #else
777                 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
778                     return FALSE;
779                 }
780 #endif
781         }
782         destOffset = g_ChannelOffset[destChannel];
783     }
784     int Bpp = GetBPP() / 8;
785     if (Bpp == 1) {
786         FXSYS_memset(m_pBuffer, value, m_Height * m_Pitch);
787         return TRUE;
788     }
789     if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
790         FXSYS_memset(m_pAlphaMask->GetBuffer(), value, m_pAlphaMask->GetHeight()*m_pAlphaMask->GetPitch());
791         return TRUE;
792     }
793     for (int row = 0; row < m_Height; row ++) {
794         uint8_t* scan_line = m_pBuffer + row * m_Pitch + destOffset;
795         for (int col = 0; col < m_Width; col ++) {
796             *scan_line = value;
797             scan_line += Bpp;
798         }
799     }
800     return TRUE;
801 }
802 FX_BOOL CFX_DIBitmap::MultiplyAlpha(const CFX_DIBSource* pSrcBitmap)
803 {
804     if (m_pBuffer == NULL) {
805         return FALSE;
806     }
807     ASSERT(pSrcBitmap->IsAlphaMask());
808     if (!pSrcBitmap->IsAlphaMask()) {
809         return FALSE;
810     }
811     if (!IsAlphaMask() && !HasAlpha()) {
812         return LoadChannel(FXDIB_Alpha, pSrcBitmap, FXDIB_Alpha);
813     }
814     CFX_DIBitmap* pSrcClone = (CFX_DIBitmap*)pSrcBitmap;
815     if (pSrcBitmap->GetWidth() != m_Width || pSrcBitmap->GetHeight() != m_Height) {
816         pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height);
817         ASSERT(pSrcClone != NULL);
818         if (pSrcClone == NULL) {
819             return FALSE;
820         }
821     }
822     if (IsAlphaMask()) {
823         if(!ConvertFormat(FXDIB_8bppMask)) {
824             if (pSrcClone != pSrcBitmap) {
825                 delete pSrcClone;
826             }
827             return FALSE;
828         }
829         for (int row = 0; row < m_Height; row ++) {
830             uint8_t* dest_scan = m_pBuffer + m_Pitch * row;
831             uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row;
832             if (pSrcClone->GetBPP() == 1) {
833                 for (int col = 0; col < m_Width; col ++) {
834                     if (!((1 << (7 - col % 8)) & src_scan[col / 8])) {
835                         dest_scan[col] = 0;
836                     }
837                 }
838             } else {
839                 for (int col = 0; col < m_Width; col ++) {
840                     *dest_scan = (*dest_scan) * src_scan[col] / 255;
841                     dest_scan ++;
842                 }
843             }
844         }
845     } else {
846         if(GetFormat() == FXDIB_Argb) {
847             if (pSrcClone->GetBPP() == 1) {
848                 if (pSrcClone != pSrcBitmap) {
849                     delete pSrcClone;
850                 }
851                 return FALSE;
852             }
853             for (int row = 0; row < m_Height; row ++) {
854                 uint8_t* dest_scan = m_pBuffer + m_Pitch * row + 3;
855                 uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row;
856                 for (int col = 0; col < m_Width; col ++) {
857                     *dest_scan = (*dest_scan) * src_scan[col] / 255;
858                     dest_scan += 4;
859                 }
860             }
861         } else {
862             m_pAlphaMask->MultiplyAlpha(pSrcClone);
863         }
864     }
865     if (pSrcClone != pSrcBitmap) {
866         delete pSrcClone;
867     }
868     return TRUE;
869 }
870 FX_BOOL CFX_DIBitmap::GetGrayData(void* pIccTransform)
871 {
872     if (m_pBuffer == NULL) {
873         return FALSE;
874     }
875     switch (GetFormat()) {
876         case FXDIB_1bppRgb: {
877                 if (m_pPalette == NULL) {
878                     return FALSE;
879                 }
880                 uint8_t gray[2];
881                 for (int i = 0; i < 2; i ++) {
882                     int r = (uint8_t)(m_pPalette[i] >> 16);
883                     int g = (uint8_t)(m_pPalette[i] >> 8);
884                     int b = (uint8_t)m_pPalette[i];
885                     gray[i] = (uint8_t)FXRGB2GRAY(r, g, b);
886                 }
887                 CFX_DIBitmap* pMask = new CFX_DIBitmap;
888                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
889                     delete pMask;
890                     return FALSE;
891                 }
892                 FXSYS_memset(pMask->GetBuffer(), gray[0], pMask->GetPitch() * m_Height);
893                 for (int row = 0; row < m_Height; row ++) {
894                     uint8_t* src_pos = m_pBuffer + row * m_Pitch;
895                     uint8_t* dest_pos = (uint8_t*)pMask->GetScanline(row);
896                     for (int col = 0; col < m_Width; col ++) {
897                         if (src_pos[col / 8] & (1 << (7 - col % 8))) {
898                             *dest_pos = gray[1];
899                         }
900                         dest_pos ++;
901                     }
902                 }
903                 TakeOver(pMask);
904                 delete pMask;
905                 break;
906             }
907         case FXDIB_8bppRgb: {
908                 if (m_pPalette == NULL) {
909                     return FALSE;
910                 }
911                 uint8_t gray[256];
912                 for (int i = 0; i < 256; i ++) {
913                     int r = (uint8_t)(m_pPalette[i] >> 16);
914                     int g = (uint8_t)(m_pPalette[i] >> 8);
915                     int b = (uint8_t)m_pPalette[i];
916                     gray[i] = (uint8_t)FXRGB2GRAY(r, g, b);
917                 }
918                 CFX_DIBitmap* pMask = new CFX_DIBitmap;
919                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
920                     delete pMask;
921                     return FALSE;
922                 }
923                 for (int row = 0; row < m_Height; row ++) {
924                     uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
925                     uint8_t* src_pos = m_pBuffer + row * m_Pitch;
926                     for (int col = 0; col < m_Width; col ++) {
927                         *dest_pos ++ = gray[*src_pos ++];
928                     }
929                 }
930                 TakeOver(pMask);
931                 delete pMask;
932                 break;
933             }
934         case FXDIB_Rgb: {
935                 CFX_DIBitmap* pMask = new CFX_DIBitmap;
936                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
937                     delete pMask;
938                     return FALSE;
939                 }
940                 for (int row = 0; row < m_Height; row ++) {
941                     uint8_t* src_pos = m_pBuffer + row * m_Pitch;
942                     uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
943                     for (int col = 0; col < m_Width; col ++) {
944                         *dest_pos ++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
945                         src_pos += 3;
946                     }
947                 }
948                 TakeOver(pMask);
949                 delete pMask;
950                 break;
951             }
952         case FXDIB_Rgb32: {
953                 CFX_DIBitmap* pMask = new CFX_DIBitmap;
954                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
955                     delete pMask;
956                     return FALSE;
957                 }
958                 for (int row = 0; row < m_Height; row ++) {
959                     uint8_t* src_pos = m_pBuffer + row * m_Pitch;
960                     uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
961                     for (int col = 0; col < m_Width; col ++) {
962                         *dest_pos ++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
963                         src_pos += 4;
964                     }
965                 }
966                 TakeOver(pMask);
967                 delete pMask;
968                 break;
969             }
970         default:
971             return FALSE;
972     }
973     return TRUE;
974 }
975 FX_BOOL CFX_DIBitmap::MultiplyAlpha(int alpha)
976 {
977     if (m_pBuffer == NULL) {
978         return FALSE;
979     }
980     switch (GetFormat()) {
981         case FXDIB_1bppMask:
982             if (!ConvertFormat(FXDIB_8bppMask)) {
983                 return FALSE;
984             }
985             MultiplyAlpha(alpha);
986             break;
987         case FXDIB_8bppMask: {
988                 for (int row = 0; row < m_Height; row ++) {
989                     uint8_t* scan_line = m_pBuffer + row * m_Pitch;
990                     for (int col = 0; col < m_Width; col ++) {
991                         scan_line[col] = scan_line[col] * alpha / 255;
992                     }
993                 }
994                 break;
995             }
996         case FXDIB_Argb: {
997                 for (int row = 0; row < m_Height; row ++) {
998                     uint8_t* scan_line = m_pBuffer + row * m_Pitch + 3;
999                     for (int col = 0; col < m_Width; col ++) {
1000                         *scan_line = (*scan_line) * alpha / 255;
1001                         scan_line += 4;
1002                     }
1003                 }
1004                 break;
1005             }
1006         default:
1007             if (HasAlpha()) {
1008                 m_pAlphaMask->MultiplyAlpha(alpha);
1009             } else if (IsCmykImage()) {
1010                 if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
1011                     return FALSE;
1012                 }
1013                 m_pAlphaMask->MultiplyAlpha(alpha);
1014             } else {
1015                 if (!ConvertFormat(FXDIB_Argb)) {
1016                     return FALSE;
1017                 }
1018                 MultiplyAlpha(alpha);
1019             }
1020             break;
1021     }
1022     return TRUE;
1023 }
1024 FX_DWORD CFX_DIBitmap::GetPixel(int x, int y) const
1025 {
1026     if (m_pBuffer == NULL) {
1027         return 0;
1028     }
1029     uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1030     switch (GetFormat()) {
1031         case FXDIB_1bppMask: {
1032                 if ((*pos) & (1 << (7 - x % 8))) {
1033                     return 0xff000000;
1034                 }
1035                 return 0;
1036             }
1037         case FXDIB_1bppRgb: {
1038                 if ((*pos) & (1 << (7 - x % 8))) {
1039                     return m_pPalette ? m_pPalette[1] : 0xffffffff;
1040                 } else {
1041                     return m_pPalette ? m_pPalette[0] : 0xff000000;
1042                 }
1043                 break;
1044             }
1045         case FXDIB_8bppMask:
1046             return (*pos) << 24;
1047         case FXDIB_8bppRgb:
1048             return m_pPalette ? m_pPalette[*pos] : (0xff000000 | ((*pos) * 0x10101));
1049         case FXDIB_Rgb:
1050         case FXDIB_Rgba:
1051         case FXDIB_Rgb32:
1052             return FXARGB_GETDIB(pos) | 0xff000000;
1053         case FXDIB_Argb:
1054             return FXARGB_GETDIB(pos);
1055         default:
1056             break;
1057     }
1058     return 0;
1059 }
1060 void CFX_DIBitmap::SetPixel(int x, int y, FX_DWORD color)
1061 {
1062     if (m_pBuffer == NULL) {
1063         return;
1064     }
1065     if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) {
1066         return;
1067     }
1068     uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1069     switch (GetFormat()) {
1070         case FXDIB_1bppMask:
1071             if (color >> 24) {
1072                 *pos |= 1 << (7 - x % 8);
1073             } else {
1074                 *pos &= ~(1 << (7 - x % 8));
1075             }
1076             break;
1077         case FXDIB_1bppRgb:
1078             if (m_pPalette) {
1079                 if (color == m_pPalette[1]) {
1080                     *pos |= 1 << (7 - x % 8);
1081                 } else {
1082                     *pos &= ~(1 << (7 - x % 8));
1083                 }
1084             } else {
1085                 if (color == 0xffffffff) {
1086                     *pos |= 1 << (7 - x % 8);
1087                 } else {
1088                     *pos &= ~(1 << (7 - x % 8));
1089                 }
1090             }
1091             break;
1092         case FXDIB_8bppMask:
1093             *pos = (uint8_t)(color >> 24);
1094             break;
1095         case FXDIB_8bppRgb: {
1096                 if (m_pPalette) {
1097                     for (int i = 0; i < 256; i ++) {
1098                         if (m_pPalette[i] == color) {
1099                             *pos = (uint8_t)i;
1100                             return;
1101                         }
1102                     }
1103                     *pos = 0;
1104                 } else {
1105                     *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
1106                 }
1107                 break;
1108             }
1109         case FXDIB_Rgb:
1110         case FXDIB_Rgb32: {
1111                 int alpha = FXARGB_A(color);
1112                 pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
1113                 pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
1114                 pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
1115                 break;
1116             }
1117         case FXDIB_Rgba: {
1118                 pos[0] = FXARGB_B(color);
1119                 pos[1] = FXARGB_G(color);
1120                 pos[2] = FXARGB_R(color);
1121                 break;
1122             }
1123         case FXDIB_Argb:
1124             FXARGB_SETDIB(pos, color);
1125             break;
1126         default:
1127             break;
1128     }
1129 }
1130 void CFX_DIBitmap::DownSampleScanline(int line, uint8_t* dest_scan, int dest_bpp,
1131                                       int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const
1132 {
1133     if (m_pBuffer == NULL) {
1134         return;
1135     }
1136     int src_Bpp = m_bpp / 8;
1137     uint8_t* scanline = m_pBuffer + line * m_Pitch;
1138     if (src_Bpp == 0) {
1139         for (int i = 0; i < clip_width; i ++) {
1140             FX_DWORD dest_x = clip_left + i;
1141             FX_DWORD src_x = dest_x * m_Width / dest_width;
1142             if (bFlipX) {
1143                 src_x = m_Width - src_x - 1;
1144             }
1145             src_x %= m_Width;
1146             dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
1147         }
1148     } else if (src_Bpp == 1) {
1149         for (int i = 0; i < clip_width; i ++) {
1150             FX_DWORD dest_x = clip_left + i;
1151             FX_DWORD src_x = dest_x * m_Width / dest_width;
1152             if (bFlipX) {
1153                 src_x = m_Width - src_x - 1;
1154             }
1155             src_x %= m_Width;
1156             int dest_pos = i;
1157             if (m_pPalette) {
1158                 if (!IsCmykImage()) {
1159                     dest_pos *= 3;
1160                     FX_ARGB argb = m_pPalette[scanline[src_x]];
1161                     dest_scan[dest_pos] = FXARGB_B(argb);
1162                     dest_scan[dest_pos + 1] = FXARGB_G(argb);
1163                     dest_scan[dest_pos + 2] = FXARGB_R(argb);
1164                 } else {
1165                     dest_pos *= 4;
1166                     FX_CMYK cmyk = m_pPalette[scanline[src_x]];
1167                     dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
1168                     dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
1169                     dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
1170                     dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
1171                 }
1172             } else {
1173                 dest_scan[dest_pos] = scanline[src_x];
1174             }
1175         }
1176     } else {
1177         for (int i = 0; i < clip_width; i ++) {
1178             FX_DWORD dest_x = clip_left + i;
1179             FX_DWORD src_x = bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp : (dest_x * m_Width / dest_width) * src_Bpp;
1180             src_x %= m_Width * src_Bpp;
1181             int dest_pos = i * src_Bpp;
1182             for (int b = 0; b < src_Bpp; b ++) {
1183                 dest_scan[dest_pos + b] = scanline[src_x + b];
1184             }
1185         }
1186     }
1187 }
1188 FX_BOOL CFX_DIBitmap::ConvertColorScale(FX_DWORD forecolor, FX_DWORD backcolor)
1189 {
1190     ASSERT(!IsAlphaMask());
1191     if (m_pBuffer == NULL || IsAlphaMask()) {
1192         return FALSE;
1193     }
1194     int fc, fm, fy, fk, bc, bm, by, bk;
1195     int fr, fg, fb, br, bg, bb;
1196     FX_BOOL isCmykImage = IsCmykImage();
1197     if (isCmykImage) {
1198         fc = FXSYS_GetCValue(forecolor);
1199         fm = FXSYS_GetMValue(forecolor);
1200         fy = FXSYS_GetYValue(forecolor);
1201         fk = FXSYS_GetKValue(forecolor);
1202         bc = FXSYS_GetCValue(backcolor);
1203         bm = FXSYS_GetMValue(backcolor);
1204         by = FXSYS_GetYValue(backcolor);
1205         bk = FXSYS_GetKValue(backcolor);
1206     } else {
1207         fr = FXSYS_GetRValue(forecolor);
1208         fg = FXSYS_GetGValue(forecolor);
1209         fb = FXSYS_GetBValue(forecolor);
1210         br = FXSYS_GetRValue(backcolor);
1211         bg = FXSYS_GetGValue(backcolor);
1212         bb = FXSYS_GetBValue(backcolor);
1213     }
1214     if (m_bpp <= 8) {
1215         if (isCmykImage) {
1216             if (forecolor == 0xff && backcolor == 0 && m_pPalette == NULL) {
1217                 return TRUE;
1218             }
1219         } else if (forecolor == 0 && backcolor == 0xffffff && m_pPalette == NULL) {
1220             return TRUE;
1221         }
1222         if (m_pPalette == NULL) {
1223             BuildPalette();
1224         }
1225         int size = 1 << m_bpp;
1226         if (isCmykImage) {
1227             for (int i = 0; i < size; i ++) {
1228                 uint8_t b, g, r;
1229                 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette[i]), FXSYS_GetMValue(m_pPalette[i]), FXSYS_GetYValue(m_pPalette[i]), FXSYS_GetKValue(m_pPalette[i]),
1230                                    r, g, b);
1231                 int gray = 255 - FXRGB2GRAY(r, g, b);
1232                 m_pPalette[i] = CmykEncode(bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
1233                                            by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
1234             }
1235         } else
1236             for (int i = 0; i < size; i ++) {
1237                 int gray = FXRGB2GRAY(FXARGB_R(m_pPalette[i]), FXARGB_G(m_pPalette[i]), FXARGB_B(m_pPalette[i]));
1238                 m_pPalette[i] = FXARGB_MAKE(0xff, br + (fr - br) * gray / 255, bg + (fg - bg) * gray / 255,
1239                                             bb + (fb - bb) * gray / 255);
1240             }
1241         return TRUE;
1242     }
1243     if (isCmykImage) {
1244         if (forecolor == 0xff && backcolor == 0x00) {
1245             for (int row = 0; row < m_Height; row ++) {
1246                 uint8_t* scanline = m_pBuffer + row * m_Pitch;
1247                 for (int col = 0; col < m_Width; col ++) {
1248                     uint8_t b, g, r;
1249                     AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1250                                        r, g, b);
1251                     *scanline ++ = 0;
1252                     *scanline ++ = 0;
1253                     *scanline ++ = 0;
1254                     *scanline ++ = 255 - FXRGB2GRAY(r, g, b);
1255                 }
1256             }
1257             return TRUE;
1258         }
1259     } else if (forecolor == 0 && backcolor == 0xffffff) {
1260         for (int row = 0; row < m_Height; row ++) {
1261             uint8_t* scanline = m_pBuffer + row * m_Pitch;
1262             int gap = m_bpp / 8 - 2;
1263             for (int col = 0; col < m_Width; col ++) {
1264                 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1265                 *scanline ++ = gray;
1266                 *scanline ++ = gray;
1267                 *scanline    = gray;
1268                 scanline += gap;
1269             }
1270         }
1271         return TRUE;
1272     }
1273     if (isCmykImage) {
1274         for (int row = 0; row < m_Height; row ++) {
1275             uint8_t* scanline = m_pBuffer + row * m_Pitch;
1276             for (int col = 0; col < m_Width; col ++) {
1277                 uint8_t b, g, r;
1278                 AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1279                                    r, g, b);
1280                 int gray = 255 - FXRGB2GRAY(r, g, b);
1281                 *scanline ++ = bc + (fc - bc) * gray / 255;
1282                 *scanline ++ = bm + (fm - bm) * gray / 255;
1283                 *scanline ++ = by + (fy - by) * gray / 255;
1284                 *scanline ++ = bk + (fk - bk) * gray / 255;
1285             }
1286         }
1287     } else {
1288         for (int row = 0; row < m_Height; row ++) {
1289             uint8_t* scanline = m_pBuffer + row * m_Pitch;
1290             int gap = m_bpp / 8 - 2;
1291             for (int col = 0; col < m_Width; col ++) {
1292                 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1293                 *scanline ++ = bb + (fb - bb) * gray / 255;
1294                 *scanline ++ = bg + (fg - bg) * gray / 255;
1295                 *scanline    = br + (fr - br) * gray / 255;
1296                 scanline += gap;
1297             }
1298         }
1299     }
1300     return TRUE;
1301 }
1302 FX_BOOL CFX_DIBitmap::DitherFS(const FX_DWORD* pPalette, int pal_size, const FX_RECT* pRect)
1303 {
1304     if (m_pBuffer == NULL) {
1305         return FALSE;
1306     }
1307     if (m_bpp != 8 && m_pPalette != NULL && m_AlphaFlag != 0) {
1308         return FALSE;
1309     }
1310     if (m_Width < 4 && m_Height < 4) {
1311         return FALSE;
1312     }
1313     FX_RECT rect(0, 0, m_Width, m_Height);
1314     if (pRect) {
1315         rect.Intersect(*pRect);
1316     }
1317     uint8_t translate[256];
1318     for (int i = 0; i < 256; i ++) {
1319         int err2 = 65536;
1320         for (int j = 0; j < pal_size; j ++) {
1321             uint8_t entry = (uint8_t)pPalette[j];
1322             int err = (int)entry - i;
1323             if (err * err < err2) {
1324                 err2 = err * err;
1325                 translate[i] = entry;
1326             }
1327         }
1328     }
1329     for (int row = rect.top; row < rect.bottom; row ++) {
1330         uint8_t* scan = m_pBuffer + row * m_Pitch;
1331         uint8_t* next_scan = m_pBuffer + (row + 1) * m_Pitch;
1332         for (int col = rect.left; col < rect.right; col ++) {
1333             int src_pixel = scan[col];
1334             int dest_pixel = translate[src_pixel];
1335             scan[col] = (uint8_t)dest_pixel;
1336             int error = -dest_pixel + src_pixel;
1337             if (col < rect.right - 1) {
1338                 int src = scan[col + 1];
1339                 src += error * 7 / 16;
1340                 if (src > 255) {
1341                     scan[col + 1] = 255;
1342                 } else if (src < 0) {
1343                     scan[col + 1] = 0;
1344                 } else {
1345                     scan[col + 1] = src;
1346                 }
1347             }
1348             if (col < rect.right - 1 && row < rect.bottom - 1) {
1349                 int src = next_scan[col + 1];
1350                 src += error * 1 / 16;
1351                 if (src > 255) {
1352                     next_scan[col + 1] = 255;
1353                 } else if (src < 0) {
1354                     next_scan[col + 1] = 0;
1355                 } else {
1356                     next_scan[col + 1] = src;
1357                 }
1358             }
1359             if (row < rect.bottom - 1) {
1360                 int src = next_scan[col];
1361                 src += error * 5 / 16;
1362                 if (src > 255) {
1363                     next_scan[col] = 255;
1364                 } else if (src < 0) {
1365                     next_scan[col] = 0;
1366                 } else {
1367                     next_scan[col] = src;
1368                 }
1369             }
1370             if (col > rect.left && row < rect.bottom - 1) {
1371                 int src = next_scan[col - 1];
1372                 src += error * 3 / 16;
1373                 if (src > 255) {
1374                     next_scan[col - 1] = 255;
1375                 } else if (src < 0) {
1376                     next_scan[col - 1] = 0;
1377                 } else {
1378                     next_scan[col - 1] = src;
1379                 }
1380             }
1381         }
1382     }
1383     return TRUE;
1384 }
1385 CFX_DIBitmap* CFX_DIBSource::FlipImage(FX_BOOL bXFlip, FX_BOOL bYFlip) const
1386 {
1387     CFX_DIBitmap* pFlipped = new CFX_DIBitmap;
1388     if (!pFlipped->Create(m_Width, m_Height, GetFormat())) {
1389         delete pFlipped;
1390         return NULL;
1391     }
1392     pFlipped->CopyPalette(m_pPalette);
1393     uint8_t* pDestBuffer = pFlipped->GetBuffer();
1394     int Bpp = m_bpp / 8;
1395     for (int row = 0; row < m_Height; row ++) {
1396         const uint8_t* src_scan = GetScanline(row);
1397         uint8_t* dest_scan = pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
1398         if (!bXFlip) {
1399             FXSYS_memcpy(dest_scan, src_scan, m_Pitch);
1400             continue;
1401         }
1402         if (m_bpp == 1) {
1403             FXSYS_memset(dest_scan, 0, m_Pitch);
1404             for (int col = 0; col < m_Width; col ++)
1405                 if (src_scan[col / 8] & (1 << (7 - col % 8))) {
1406                     int dest_col = m_Width - col - 1;
1407                     dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
1408                 }
1409         } else {
1410             dest_scan += (m_Width - 1) * Bpp;
1411             if (Bpp == 1) {
1412                 for (int col = 0; col < m_Width; col ++) {
1413                     *dest_scan = *src_scan;
1414                     dest_scan --;
1415                     src_scan ++;
1416                 }
1417             } else if (Bpp == 3) {
1418                 for (int col = 0; col < m_Width; col ++) {
1419                     dest_scan[0] = src_scan[0];
1420                     dest_scan[1] = src_scan[1];
1421                     dest_scan[2] = src_scan[2];
1422                     dest_scan -= 3;
1423                     src_scan += 3;
1424                 }
1425             } else {
1426                 ASSERT(Bpp == 4);
1427                 for (int col = 0; col < m_Width; col ++) {
1428                     *(FX_DWORD*)dest_scan = *(FX_DWORD*)src_scan;
1429                     dest_scan -= 4;
1430                     src_scan += 4;
1431                 }
1432             }
1433         }
1434     }
1435     if (m_pAlphaMask) {
1436         pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
1437         FX_DWORD dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
1438         for (int row = 0; row < m_Height; row ++) {
1439             const uint8_t* src_scan = m_pAlphaMask->GetScanline(row);
1440             uint8_t* dest_scan = pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
1441             if (!bXFlip) {
1442                 FXSYS_memcpy(dest_scan, src_scan, dest_pitch);
1443                 continue;
1444             }
1445             dest_scan += (m_Width - 1);
1446             for (int col = 0; col < m_Width; col ++) {
1447                 *dest_scan = *src_scan;
1448                 dest_scan --;
1449                 src_scan ++;
1450             }
1451         }
1452     }
1453     return pFlipped;
1454 }
1455 CFX_DIBExtractor::CFX_DIBExtractor(const CFX_DIBSource* pSrc)
1456 {
1457     m_pBitmap = NULL;
1458     if (pSrc->GetBuffer() == NULL) {
1459         m_pBitmap = pSrc->Clone();
1460     } else {
1461         m_pBitmap = new CFX_DIBitmap;
1462         if (!m_pBitmap->Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat(), pSrc->GetBuffer())) {
1463             delete m_pBitmap;
1464             m_pBitmap = NULL;
1465             return;
1466         }
1467         m_pBitmap->CopyPalette(pSrc->GetPalette());
1468         m_pBitmap->CopyAlphaMask(pSrc->m_pAlphaMask);
1469     }
1470 }
1471 CFX_DIBExtractor::~CFX_DIBExtractor()
1472 {
1473     if (m_pBitmap) {
1474         delete m_pBitmap;
1475     }
1476 }
1477 CFX_FilteredDIB::CFX_FilteredDIB()
1478 {
1479     m_pScanline = NULL;
1480     m_pSrc = NULL;
1481 }
1482 CFX_FilteredDIB::~CFX_FilteredDIB()
1483 {
1484     if (m_pSrc && m_bAutoDropSrc) {
1485         delete m_pSrc;
1486     }
1487     if (m_pScanline) {
1488         FX_Free(m_pScanline);
1489     }
1490 }
1491 void CFX_FilteredDIB::LoadSrc(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc)
1492 {
1493     m_pSrc = pSrc;
1494     m_bAutoDropSrc = bAutoDropSrc;
1495     m_Width = pSrc->GetWidth();
1496     m_Height = pSrc->GetHeight();
1497     FXDIB_Format format = GetDestFormat();
1498     m_bpp = (uint8_t)format;
1499     m_AlphaFlag = (uint8_t)(format >> 8);
1500     m_Pitch = (m_Width * (format & 0xff) + 31) / 32 * 4;
1501     m_pPalette = GetDestPalette();
1502     m_pScanline = FX_Alloc(uint8_t, m_Pitch);
1503 }
1504 const uint8_t* CFX_FilteredDIB::GetScanline(int line) const
1505 {
1506     TranslateScanline(m_pScanline, m_pSrc->GetScanline(line));
1507     return m_pScanline;
1508 }
1509 void CFX_FilteredDIB::DownSampleScanline(int line, uint8_t* dest_scan, int dest_bpp,
1510         int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const
1511 {
1512     m_pSrc->DownSampleScanline(line, dest_scan, dest_bpp, dest_width, bFlipX, clip_left, clip_width);
1513     TranslateDownSamples(dest_scan, dest_scan, clip_width, dest_bpp);
1514 }
1515 CFX_ImageRenderer::CFX_ImageRenderer()
1516 {
1517     m_Status = 0;
1518     m_pTransformer = NULL;
1519     m_bRgbByteOrder = FALSE;
1520     m_BlendType = FXDIB_BLEND_NORMAL;
1521 }
1522 CFX_ImageRenderer::~CFX_ImageRenderer()
1523 {
1524     if (m_pTransformer) {
1525         delete m_pTransformer;
1526     }
1527 }
1528 extern FX_RECT _FXDIB_SwapClipBox(FX_RECT& clip, int width, int height, FX_BOOL bFlipX, FX_BOOL bFlipY);
1529 FX_BOOL CFX_ImageRenderer::Start(CFX_DIBitmap* pDevice, const CFX_ClipRgn* pClipRgn,
1530                                  const CFX_DIBSource* pSource, int bitmap_alpha,
1531                                  FX_DWORD mask_color, const CFX_AffineMatrix* pMatrix,
1532                                  FX_DWORD dib_flags, FX_BOOL bRgbByteOrder,
1533                                  int alpha_flag, void* pIccTransform, int blend_type)
1534 {
1535     m_Matrix = *pMatrix;
1536     CFX_FloatRect image_rect_f = m_Matrix.GetUnitRect();
1537     FX_RECT image_rect = image_rect_f.GetOutterRect();
1538     m_ClipBox = pClipRgn ? pClipRgn->GetBox() : FX_RECT(0, 0, pDevice->GetWidth(), pDevice->GetHeight());
1539     m_ClipBox.Intersect(image_rect);
1540     if (m_ClipBox.IsEmpty()) {
1541         return FALSE;
1542     }
1543     m_pDevice = pDevice;
1544     m_pClipRgn = pClipRgn;
1545     m_MaskColor = mask_color;
1546     m_BitmapAlpha = bitmap_alpha;
1547     m_Matrix = *pMatrix;
1548     m_Flags = dib_flags;
1549     m_AlphaFlag = alpha_flag;
1550     m_pIccTransform = pIccTransform;
1551     m_bRgbByteOrder = bRgbByteOrder;
1552     m_BlendType = blend_type;
1553     FX_BOOL ret = TRUE;
1554     if ((FXSYS_fabs(m_Matrix.b) >= 0.5f || m_Matrix.a == 0) ||
1555             (FXSYS_fabs(m_Matrix.c) >= 0.5f || m_Matrix.d == 0) ) {
1556         if (FXSYS_fabs(m_Matrix.a) < FXSYS_fabs(m_Matrix.b) / 20 && FXSYS_fabs(m_Matrix.d) < FXSYS_fabs(m_Matrix.c) / 20 &&
1557                 FXSYS_fabs(m_Matrix.a) < 0.5f && FXSYS_fabs(m_Matrix.d) < 0.5f) {
1558             int dest_width = image_rect.Width();
1559             int dest_height = image_rect.Height();
1560             FX_RECT bitmap_clip = m_ClipBox;
1561             bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1562             bitmap_clip = _FXDIB_SwapClipBox(bitmap_clip, dest_width, dest_height, m_Matrix.c > 0, m_Matrix.b < 0);
1563             m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox, TRUE,
1564                                m_Matrix.c > 0, m_Matrix.b < 0, m_bRgbByteOrder, alpha_flag, pIccTransform, m_BlendType);
1565             if (!m_Stretcher.Start(&m_Composer, pSource, dest_height, dest_width, bitmap_clip, dib_flags)) {
1566                 return FALSE;
1567             }
1568             m_Status = 1;
1569             return TRUE;
1570         }
1571         m_Status = 2;
1572         m_pTransformer = new CFX_ImageTransformer;
1573         m_pTransformer->Start(pSource, &m_Matrix, dib_flags, &m_ClipBox);
1574         return TRUE;
1575     }
1576     int dest_width = image_rect.Width();
1577     if (m_Matrix.a < 0) {
1578         dest_width = -dest_width;
1579     }
1580     int dest_height = image_rect.Height();
1581     if (m_Matrix.d > 0) {
1582         dest_height = -dest_height;
1583     }
1584     if (dest_width == 0 || dest_height == 0) {
1585         return FALSE;
1586     }
1587     FX_RECT bitmap_clip = m_ClipBox;
1588     bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1589     m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color,
1590                        m_ClipBox, FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag, pIccTransform, m_BlendType);
1591     m_Status = 1;
1592     ret = m_Stretcher.Start(&m_Composer, pSource, dest_width, dest_height, bitmap_clip, dib_flags);
1593     return ret;
1594 }
1595 FX_BOOL CFX_ImageRenderer::Continue(IFX_Pause* pPause)
1596 {
1597     if (m_Status == 1) {
1598         return m_Stretcher.Continue(pPause);
1599     } else if (m_Status == 2) {
1600         if (m_pTransformer->Continue(pPause)) {
1601             return TRUE;
1602         }
1603         CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach();
1604         if (pBitmap == NULL) {
1605             return FALSE;
1606         }
1607         if (pBitmap->GetBuffer() == NULL) {
1608             delete pBitmap;
1609             return FALSE;
1610         }
1611         if (pBitmap->IsAlphaMask()) {
1612             if (m_BitmapAlpha != 255) {
1613                 if (m_AlphaFlag >> 8) {
1614                     m_AlphaFlag = (((uint8_t)((m_AlphaFlag & 0xff) * m_BitmapAlpha / 255)) | ((m_AlphaFlag >> 8) << 8));
1615                 } else {
1616                     m_MaskColor = FXARGB_MUL_ALPHA(m_MaskColor, m_BitmapAlpha);
1617                 }
1618             }
1619             m_pDevice->CompositeMask(m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop,
1620                                      pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, m_MaskColor,
1621                                      0, 0, m_BlendType, m_pClipRgn, m_bRgbByteOrder, m_AlphaFlag, m_pIccTransform);
1622         } else {
1623             if (m_BitmapAlpha != 255) {
1624                 pBitmap->MultiplyAlpha(m_BitmapAlpha);
1625             }
1626             m_pDevice->CompositeBitmap(m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop,
1627                                        pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, 0, 0, m_BlendType, m_pClipRgn, m_bRgbByteOrder, m_pIccTransform);
1628         }
1629         delete pBitmap;
1630         return FALSE;
1631     }
1632     return FALSE;
1633 }
1634 CFX_BitmapStorer::CFX_BitmapStorer()
1635 {
1636     m_pBitmap = NULL;
1637 }
1638 CFX_BitmapStorer::~CFX_BitmapStorer()
1639 {
1640     if (m_pBitmap) {
1641         delete m_pBitmap;
1642     }
1643 }
1644 CFX_DIBitmap* CFX_BitmapStorer::Detach()
1645 {
1646     CFX_DIBitmap* pBitmap = m_pBitmap;
1647     m_pBitmap = NULL;
1648     return pBitmap;
1649 }
1650 void CFX_BitmapStorer::Replace(CFX_DIBitmap* pBitmap)
1651 {
1652     if (m_pBitmap) {
1653         delete m_pBitmap;
1654     }
1655     m_pBitmap = pBitmap;
1656 }
1657 void CFX_BitmapStorer::ComposeScanline(int line, const uint8_t* scanline, const uint8_t* scan_extra_alpha)
1658 {
1659     uint8_t* dest_buf = (uint8_t*)m_pBitmap->GetScanline(line);
1660     uint8_t* dest_alpha_buf = m_pBitmap->m_pAlphaMask ?
1661                                (uint8_t*)m_pBitmap->m_pAlphaMask->GetScanline(line) : NULL;
1662     if (dest_buf) {
1663         FXSYS_memcpy(dest_buf, scanline, m_pBitmap->GetPitch());
1664     }
1665     if (dest_alpha_buf) {
1666         FXSYS_memcpy(dest_alpha_buf, scan_extra_alpha, m_pBitmap->m_pAlphaMask->GetPitch());
1667     }
1668 }
1669 FX_BOOL CFX_BitmapStorer::SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette)
1670 {
1671     m_pBitmap = new CFX_DIBitmap;
1672     if (!m_pBitmap->Create(width, height, src_format)) {
1673         delete m_pBitmap;
1674         m_pBitmap = NULL;
1675         return FALSE;
1676     }
1677     if (pSrcPalette) {
1678         m_pBitmap->CopyPalette(pSrcPalette);
1679     }
1680     return TRUE;
1681 }