diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
---|---|---|
committer | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
commit | 764ec513eecbebd12781bcc96ce81ed5e736ee92 (patch) | |
tree | 12763fde4be1f10ea1183d92185917b2b587e00b /core/fxge/dib | |
parent | 97da97662417085774f75c26e535c6fbe70266ae (diff) | |
download | pdfium-764ec513eecbebd12781bcc96ce81ed5e736ee92.tar.xz |
Move core/src/ up to core/.
This CL moves the core/src/ files up to core/ and fixes up the include guards,
includes and build files.
R=tsepez@chromium.org
Review URL: https://codereview.chromium.org/1800523005 .
Diffstat (limited to 'core/fxge/dib')
-rw-r--r-- | core/fxge/dib/dib_int.h | 107 | ||||
-rw-r--r-- | core/fxge/dib/fx_dib_composite.cpp | 5210 | ||||
-rw-r--r-- | core/fxge/dib/fx_dib_convert.cpp | 1227 | ||||
-rw-r--r-- | core/fxge/dib/fx_dib_engine.cpp | 917 | ||||
-rw-r--r-- | core/fxge/dib/fx_dib_main.cpp | 1745 | ||||
-rw-r--r-- | core/fxge/dib/fx_dib_transform.cpp | 948 |
6 files changed, 10154 insertions, 0 deletions
diff --git a/core/fxge/dib/dib_int.h b/core/fxge/dib/dib_int.h new file mode 100644 index 0000000000..85888fed50 --- /dev/null +++ b/core/fxge/dib/dib_int.h @@ -0,0 +1,107 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXGE_DIB_DIB_INT_H_ +#define CORE_FXGE_DIB_DIB_INT_H_ + +#include <stdint.h> + +#include "core/include/fxcrt/fx_coordinates.h" +#include "core/include/fxge/fx_dib.h" + +class IFX_ScanlineComposer; + +extern const int16_t SDP_Table[513]; + +class CPDF_FixedMatrix { + public: + CPDF_FixedMatrix(const CFX_Matrix& src, int bits) { + base = 1 << bits; + a = FXSYS_round(src.a * base); + b = FXSYS_round(src.b * base); + c = FXSYS_round(src.c * base); + d = FXSYS_round(src.d * base); + e = FXSYS_round(src.e * base); + f = FXSYS_round(src.f * base); + } + inline void Transform(int x, int y, int& x1, int& y1) { + x1 = (a * x + c * y + e + base / 2) / base; + y1 = (b * x + d * y + f + base / 2) / base; + } + int a, b, c, d, e, f; + int base; +}; +#define FPDF_HUGE_IMAGE_SIZE 60000000 +struct PixelWeight { + int m_SrcStart; + int m_SrcEnd; + int m_Weights[1]; +}; +class CWeightTable { + public: + CWeightTable() { m_pWeightTables = NULL; } + ~CWeightTable() { + FX_Free(m_pWeightTables); + m_pWeightTables = NULL; + } + void Calc(int dest_len, + int dest_min, + int dest_max, + int src_len, + int src_min, + int src_max, + int flags); + PixelWeight* GetPixelWeight(int pixel) { + return (PixelWeight*)(m_pWeightTables + (pixel - m_DestMin) * m_ItemSize); + } + int m_DestMin, m_ItemSize; + uint8_t* m_pWeightTables; +}; +class CStretchEngine { + public: + CStretchEngine(IFX_ScanlineComposer* pDestBitmap, + FXDIB_Format dest_format, + int dest_width, + int dest_height, + const FX_RECT& clip_rect, + const CFX_DIBSource* pSrcBitmap, + int flags); + ~CStretchEngine(); + FX_BOOL Continue(IFX_Pause* pPause); + + public: + FXDIB_Format m_DestFormat; + int m_DestBpp, m_SrcBpp, m_bHasAlpha; + IFX_ScanlineComposer* m_pDestBitmap; + int m_DestWidth, m_DestHeight; + FX_RECT m_DestClip; + uint8_t* m_pDestScanline; + uint8_t* m_pDestMaskScanline; + FX_RECT m_SrcClip; + const CFX_DIBSource* m_pSource; + FX_DWORD* m_pSrcPalette; + int m_SrcWidth, m_SrcHeight; + int m_SrcPitch, m_InterPitch; + int m_ExtraMaskPitch; + unsigned char* m_pInterBuf; + unsigned char* m_pExtraAlphaBuf; + int m_TransMethod; + int m_Flags; + CWeightTable m_WeightTable; + int m_CurRow; + FX_BOOL StartStretchHorz(); + FX_BOOL ContinueStretchHorz(IFX_Pause* pPause); + void StretchVert(); + int m_State; +}; + +FX_RECT FXDIB_SwapClipBox(FX_RECT& clip, + int width, + int height, + FX_BOOL bFlipX, + FX_BOOL bFlipY); + +#endif // CORE_FXGE_DIB_DIB_INT_H_ diff --git a/core/fxge/dib/fx_dib_composite.cpp b/core/fxge/dib/fx_dib_composite.cpp new file mode 100644 index 0000000000..0bf67ccb71 --- /dev/null +++ b/core/fxge/dib/fx_dib_composite.cpp @@ -0,0 +1,5210 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/dib/dib_int.h" +#include "core/include/fxcodec/fx_codec.h" +#include "core/include/fxge/fx_ge.h" + +const uint8_t _color_sqrt[256] = { + 0x00, 0x03, 0x07, 0x0B, 0x0F, 0x12, 0x16, 0x19, 0x1D, 0x20, 0x23, 0x26, + 0x29, 0x2C, 0x2F, 0x32, 0x35, 0x37, 0x3A, 0x3C, 0x3F, 0x41, 0x43, 0x46, + 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x57, 0x59, 0x5B, 0x5C, + 0x5E, 0x60, 0x61, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, + 0x6E, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, + 0x7B, 0x7C, 0x7D, 0x7E, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x91, + 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, + 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA4, 0xA5, + 0xA6, 0xA7, 0xA7, 0xA8, 0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAE, + 0xAF, 0xB0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB3, 0xB4, 0xB5, 0xB5, 0xB6, 0xB7, + 0xB7, 0xB8, 0xB9, 0xBA, 0xBA, 0xBB, 0xBC, 0xBC, 0xBD, 0xBE, 0xBE, 0xBF, + 0xC0, 0xC0, 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC5, 0xC6, 0xC6, 0xC7, + 0xC7, 0xC8, 0xC9, 0xC9, 0xCA, 0xCB, 0xCB, 0xCC, 0xCC, 0xCD, 0xCE, 0xCE, + 0xCF, 0xD0, 0xD0, 0xD1, 0xD1, 0xD2, 0xD3, 0xD3, 0xD4, 0xD4, 0xD5, 0xD6, + 0xD6, 0xD7, 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDC, 0xDD, + 0xDD, 0xDE, 0xDE, 0xDF, 0xE0, 0xE0, 0xE1, 0xE1, 0xE2, 0xE2, 0xE3, 0xE4, + 0xE4, 0xE5, 0xE5, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA, + 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0xEE, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1, + 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7, + 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC, 0xFD, + 0xFD, 0xFE, 0xFE, 0xFF}; +int _BLEND(int blend_mode, int back_color, int src_color) { + switch (blend_mode) { + case FXDIB_BLEND_NORMAL: + return src_color; + case FXDIB_BLEND_MULTIPLY: + return src_color * back_color / 255; + case FXDIB_BLEND_SCREEN: + return src_color + back_color - src_color * back_color / 255; + case FXDIB_BLEND_OVERLAY: + return _BLEND(FXDIB_BLEND_HARDLIGHT, src_color, back_color); + case FXDIB_BLEND_DARKEN: + return src_color < back_color ? src_color : back_color; + case FXDIB_BLEND_LIGHTEN: + return src_color > back_color ? src_color : back_color; + case FXDIB_BLEND_COLORDODGE: { + if (src_color == 255) { + return src_color; + } + int result = back_color * 255 / (255 - src_color); + if (result > 255) { + return 255; + } + return result; + } + case FXDIB_BLEND_COLORBURN: { + if (src_color == 0) { + return src_color; + } + int result = (255 - back_color) * 255 / src_color; + if (result > 255) { + result = 255; + } + return 255 - result; + } + case FXDIB_BLEND_HARDLIGHT: + if (src_color < 128) { + return (src_color * back_color * 2) / 255; + } + return _BLEND(FXDIB_BLEND_SCREEN, back_color, 2 * src_color - 255); + case FXDIB_BLEND_SOFTLIGHT: { + if (src_color < 128) { + return back_color - + (255 - 2 * src_color) * back_color * (255 - back_color) / 255 / + 255; + } + return back_color + + (2 * src_color - 255) * (_color_sqrt[back_color] - back_color) / + 255; + } + case FXDIB_BLEND_DIFFERENCE: + return back_color < src_color ? src_color - back_color + : back_color - src_color; + case FXDIB_BLEND_EXCLUSION: + return back_color + src_color - 2 * back_color * src_color / 255; + } + return src_color; +} +struct _RGB { + int red; + int green; + int blue; +}; +static inline int _Lum(_RGB color) { + return (color.red * 30 + color.green * 59 + color.blue * 11) / 100; +} +static _RGB _ClipColor(_RGB color) { + int l = _Lum(color); + int n = color.red; + if (color.green < n) { + n = color.green; + } + if (color.blue < n) { + n = color.blue; + } + int x = color.red; + if (color.green > x) { + x = color.green; + } + if (color.blue > x) { + x = color.blue; + } + if (n < 0) { + color.red = l + ((color.red - l) * l / (l - n)); + color.green = l + ((color.green - l) * l / (l - n)); + color.blue = l + ((color.blue - l) * l / (l - n)); + } + if (x > 255) { + color.red = l + ((color.red - l) * (255 - l) / (x - l)); + color.green = l + ((color.green - l) * (255 - l) / (x - l)); + color.blue = l + ((color.blue - l) * (255 - l) / (x - l)); + } + return color; +} +static _RGB _SetLum(_RGB color, int l) { + int d = l - _Lum(color); + color.red += d; + color.green += d; + color.blue += d; + return _ClipColor(color); +} +static int _Sat(_RGB color) { + int n = color.red; + if (color.green < n) { + n = color.green; + } + if (color.blue < n) { + n = color.blue; + } + int x = color.red; + if (color.green > x) { + x = color.green; + } + if (color.blue > x) { + x = color.blue; + } + return x - n; +} +static _RGB _SetSat(_RGB color, int s) { + int* max = &color.red; + int* mid = &color.red; + int* min = &color.red; + if (color.green > *max) { + max = &color.green; + } + if (color.blue > *max) { + max = &color.blue; + } + if (color.green < *min) { + min = &color.green; + } + if (color.blue < *min) { + min = &color.blue; + } + if (*max == *min) { + color.red = 0; + color.green = 0; + color.blue = 0; + return color; + } + if (max == &color.red) { + if (min == &color.green) { + mid = &color.blue; + } else { + mid = &color.green; + } + } else if (max == &color.green) { + if (min == &color.red) { + mid = &color.blue; + } else { + mid = &color.red; + } + } else { + if (min == &color.green) { + mid = &color.red; + } else { + mid = &color.green; + } + } + if (*max > *min) { + *mid = (*mid - *min) * s / (*max - *min); + *max = s; + *min = 0; + } + return color; +} +void _RGB_Blend(int blend_mode, + const uint8_t* src_scan, + uint8_t* dest_scan, + int results[3]) { + _RGB src, back, result; + src.red = src_scan[2]; + src.green = src_scan[1]; + src.blue = src_scan[0]; + back.red = dest_scan[2]; + back.green = dest_scan[1]; + back.blue = dest_scan[0]; + switch (blend_mode) { + case FXDIB_BLEND_HUE: + result = _SetLum(_SetSat(src, _Sat(back)), _Lum(back)); + break; + case FXDIB_BLEND_SATURATION: + result = _SetLum(_SetSat(back, _Sat(src)), _Lum(back)); + break; + case FXDIB_BLEND_COLOR: + result = _SetLum(src, _Lum(back)); + break; + case FXDIB_BLEND_LUMINOSITY: + result = _SetLum(back, _Lum(src)); + break; + } + results[0] = result.blue; + results[1] = result.green; + results[2] = result.red; +} +inline void _CompositeRow_Argb2Mask(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + const uint8_t* clip_scan) { + src_scan += 3; + for (int col = 0; col < pixel_count; col++) { + int src_alpha = *src_scan; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + uint8_t back_alpha = *dest_scan; + if (!back_alpha) { + *dest_scan = src_alpha; + } else if (src_alpha) { + *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255; + } + dest_scan++; + src_scan += 4; + } +} +void _CompositeRow_Rgba2Mask(uint8_t* dest_scan, + const uint8_t* src_alpha_scan, + int pixel_count, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + uint8_t back_alpha = *dest_scan; + if (!back_alpha) { + *dest_scan = src_alpha; + } else if (src_alpha) { + *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255; + } + dest_scan++; + } +} +void _CompositeRow_Rgb2Mask(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + const uint8_t* clip_scan) { + if (clip_scan) { + for (int i = 0; i < width; i++) { + *dest_scan = FXDIB_ALPHA_UNION(*dest_scan, *clip_scan); + dest_scan++; + clip_scan++; + } + } else { + FXSYS_memset(dest_scan, 0xff, width); + } +} +void _CompositeRow_Argb2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan, + uint8_t* dst_alpha_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = nullptr; + if (pIccTransform) + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + if (src_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dst_alpha_scan; + if (back_alpha == 0) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, + 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + *dst_alpha_scan = src_alpha; + } + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + continue; + } + uint8_t src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha == 0) { + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + continue; + } + *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha); + int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan); + uint8_t gray; + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + } else { + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + } + } else { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dst_alpha_scan; + if (back_alpha == 0) { + int src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, + 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + *dst_alpha_scan = src_alpha; + } + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + continue; + } + uint8_t src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha == 0) { + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + continue; + } + *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha); + int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan); + uint8_t gray; + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + } + } + return; + } + if (src_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dst_alpha_scan; + if (back_alpha == 0) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, + 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + *dst_alpha_scan = src_alpha; + } + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + continue; + } + uint8_t src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha == 0) { + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + continue; + } + *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha); + int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan); + uint8_t gray; + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + dst_alpha_scan++; + src_scan += 3; + } + } else { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dst_alpha_scan; + if (back_alpha == 0) { + int src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, + 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + *dst_alpha_scan = src_alpha; + } + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + continue; + } + uint8_t src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha == 0) { + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + continue; + } + *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha); + int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan); + uint8_t gray; + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + dst_alpha_scan++; + src_scan += 4; + } + } +} + +inline void _CompositeRow_Argb2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = NULL; + uint8_t gray; + if (pIccTransform) + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + if (src_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } + dest_scan++; + src_scan += 3; + } + } else { + for (int col = 0; col < pixel_count; col++) { + int src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } + dest_scan++; + src_scan += 4; + } + } + return; + } + if (src_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } + dest_scan++; + src_scan += 3; + } + } else { + for (int col = 0; col < pixel_count; col++) { + int src_alpha = src_scan[3]; + if (clip_scan) + src_alpha = clip_scan[col] * src_alpha / 255; + + if (src_alpha) { + if (pIccTransform) + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + else + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } + dest_scan++; + src_scan += 4; + } + } +} + +inline void _CompositeRow_Rgb2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_Bpp, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = NULL; + uint8_t gray; + if (pIccTransform) { + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + } + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + } else { + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan += src_Bpp; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + } else { + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan += src_Bpp; + } +} +void _CompositeRow_Rgb2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_Bpp, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = NULL; + if (pIccTransform) { + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + } + if (blend_type) { + int blended_color; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + for (int col = 0; col < pixel_count; col++) { + int back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + dest_scan++; + dest_alpha_scan++; + src_scan += src_Bpp; + continue; + } + int src_alpha = 255; + if (clip_scan) { + src_alpha = clip_scan[col]; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + src_scan += src_Bpp; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + uint8_t gray; + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + } else { + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + src_scan += src_Bpp; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + int src_alpha = 255; + if (clip_scan) { + src_alpha = clip_scan[col]; + } + if (src_alpha == 255) { + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1); + } else { + *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + dest_scan++; + *dest_alpha_scan++ = 255; + src_scan += src_Bpp; + continue; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + src_scan += src_Bpp; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + uint8_t gray; + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1); + } else { + gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan); + } + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + src_scan += src_Bpp; + } +} +void _CompositeRow_Argb2Argb(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + const uint8_t* src_alpha_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + if (!dest_alpha_scan) { + if (!src_alpha_scan) { + uint8_t back_alpha = 0; + for (int col = 0; col < pixel_count; col++) { + back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * src_scan[3] / 255; + FXARGB_SETDIB(dest_scan, (FXARGB_GETDIB(src_scan) & 0xffffff) | + (src_alpha << 24)); + } else { + FXARGB_COPY(dest_scan, src_scan); + } + dest_scan += 4; + src_scan += 4; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * src_scan[3] / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += 4; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, *src_scan); + blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + } + dest_scan++; + src_scan++; + } + dest_scan++; + src_scan++; + } + } else { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255; + FXARGB_SETDIB(dest_scan, FXARGB_MAKE((src_alpha << 24), src_scan[2], + src_scan[1], *src_scan)); + } else { + FXARGB_SETDIB(dest_scan, + FXARGB_MAKE((*src_alpha_scan << 24), src_scan[2], + src_scan[1], *src_scan)); + } + dest_scan += 4; + src_scan += 3; + src_alpha_scan++; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += 3; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, *src_scan); + blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + } + dest_scan++; + src_scan++; + } + dest_scan++; + } + } + } else { + if (src_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255; + *dest_alpha_scan = src_alpha; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + } else { + *dest_alpha_scan = *src_alpha_scan; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + } + dest_alpha_scan++; + src_alpha_scan++; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 0) { + dest_scan += 3; + src_scan += 3; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, *src_scan); + blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + } + dest_scan++; + src_scan++; + } + } + } else { + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * src_scan[3] / 255; + *dest_alpha_scan = src_alpha; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + } else { + *dest_alpha_scan = src_scan[3]; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + } + dest_alpha_scan++; + src_scan++; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * src_scan[3] / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 0) { + dest_scan += 3; + src_scan += 4; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, *src_scan); + blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + } + dest_scan++; + src_scan++; + } + src_scan++; + } + } + } +} +void _CompositeRow_Rgb2Argb_Blend_NoClip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp, + uint8_t* dest_alpha_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + if (dest_alpha_scan) { + for (int col = 0; col < width; col++) { + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_alpha_scan++ = 0xff; + src_scan += src_gap; + continue; + } + *dest_alpha_scan++ = 0xff; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int src_color = *src_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, src_color); + *dest_scan = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + dest_scan++; + src_scan++; + } + src_scan += src_gap; + } + } else { + for (int col = 0; col < width; col++) { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (src_Bpp == 4) { + FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan)); + } else { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], + src_scan[0])); + } + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + dest_scan[3] = 0xff; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int src_color = *src_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, src_color); + *dest_scan = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + dest_scan++; + src_scan++; + } + dest_scan++; + src_scan += src_gap; + } + } +} +inline void _CompositeRow_Rgb2Argb_Blend_Clip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + if (dest_alpha_scan) { + for (int col = 0; col < width; col++) { + int src_alpha = *clip_scan++; + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + src_scan += src_gap; + dest_alpha_scan++; + continue; + } + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + src_scan += src_Bpp; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int src_color = *src_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, src_color); + blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + src_scan++; + } + src_scan += src_gap; + } + } else { + for (int col = 0; col < width; col++) { + int src_alpha = *clip_scan++; + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + src_scan += src_gap; + dest_scan++; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int src_color = *src_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, src_color); + blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + src_scan++; + } + dest_scan++; + src_scan += src_gap; + } + } +} +inline void _CompositeRow_Rgb2Argb_NoBlend_Clip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + int src_gap = src_Bpp - 3; + if (dest_alpha_scan) { + for (int col = 0; col < width; col++) { + int src_alpha = clip_scan[col]; + if (src_alpha == 255) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_alpha_scan++ = 255; + src_scan += src_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + src_scan += src_Bpp; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + for (int color = 0; color < 3; color++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + dest_scan++; + src_scan++; + } + src_scan += src_gap; + } + } else { + for (int col = 0; col < width; col++) { + int src_alpha = clip_scan[col]; + if (src_alpha == 255) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = 255; + src_scan += src_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + for (int color = 0; color < 3; color++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio); + dest_scan++; + src_scan++; + } + dest_scan++; + src_scan += src_gap; + } + } +} +inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp, + uint8_t* dest_alpha_scan) { + if (dest_alpha_scan) { + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_alpha_scan++ = 0xff; + src_scan += src_gap; + } + } else { + for (int col = 0; col < width; col++) { + if (src_Bpp == 4) { + FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan)); + } else { + FXARGB_SETDIB(dest_scan, + FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0])); + } + dest_scan += 4; + src_scan += src_Bpp; + } + } +} +inline void _CompositeRow_Argb2Rgb_Blend(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int dest_gap = dest_Bpp - 3; + if (src_alpha_scan) { + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 3; + continue; + } + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int back_color = *dest_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, *src_scan); + *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha); + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + } + } else { + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 4; + continue; + } + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int back_color = *dest_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, *src_scan); + *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha); + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + src_scan++; + } + } +} +inline void _CompositeRow_Argb2Rgb_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan) { + int dest_gap = dest_Bpp - 3; + if (src_alpha_scan) { + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 255) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + dest_scan += dest_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 3; + continue; + } + for (int color = 0; color < 3; color++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha); + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + } + } else { + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 255) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + dest_scan += dest_gap; + src_scan++; + continue; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 4; + continue; + } + for (int color = 0; color < 3; color++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha); + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + src_scan++; + } + } +} +inline void _CompositeRow_Rgb2Rgb_Blend_NoClip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int dest_gap = dest_Bpp - 3; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int back_color = *dest_scan; + int src_color = *src_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, src_color); + *dest_scan = blended; + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + src_scan += src_gap; + } +} +inline void _CompositeRow_Rgb2Rgb_Blend_Clip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int dest_gap = dest_Bpp - 3; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + uint8_t src_alpha = *clip_scan++; + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += src_Bpp; + continue; + } + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int src_color = *src_scan; + int back_color = *dest_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, src_color); + *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha); + dest_scan++; + src_scan++; + } + dest_scan += dest_gap; + src_scan += src_gap; + } +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp) { + if (dest_Bpp == src_Bpp) { + FXSYS_memcpy(dest_scan, src_scan, width * dest_Bpp); + return; + } + for (int col = 0; col < width; col++) { + dest_scan[0] = src_scan[0]; + dest_scan[1] = src_scan[1]; + dest_scan[2] = src_scan[2]; + dest_scan += dest_Bpp; + src_scan += src_Bpp; + } +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan) { + for (int col = 0; col < width; col++) { + int src_alpha = clip_scan[col]; + if (src_alpha == 255) { + dest_scan[0] = src_scan[0]; + dest_scan[1] = src_scan[1]; + dest_scan[2] = src_scan[2]; + } else if (src_alpha) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha); + dest_scan++; + src_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha); + dest_scan++; + src_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha); + dest_scan += dest_Bpp - 2; + src_scan += src_Bpp - 2; + continue; + } + dest_scan += dest_Bpp; + src_scan += src_Bpp; + } +} +void _CompositeRow_Argb2Argb_Transform(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + const uint8_t* src_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + uint8_t* dp = src_cache_scan; + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_alpha_scan) { + if (dest_alpha_scan) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, pixel_count); + } else { + for (int col = 0; col < pixel_count; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + dp[3] = *src_alpha_scan++; + src_scan += 3; + dp += 4; + } + src_alpha_scan = NULL; + } + } else { + if (dest_alpha_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + for (int col = 0; col < pixel_count; col++) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + 1); + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * src_scan[3] / 255; + *dest_alpha_scan = src_alpha; + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + } else { + *dest_alpha_scan = src_scan[3]; + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + } + dest_alpha_scan++; + src_scan += 4; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * src_scan[3] / 255; + } else { + src_alpha = src_scan[3]; + } + src_scan += 4; + if (src_alpha == 0) { + dest_scan += 3; + src_cache_scan += 3; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_cache_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, *dest_scan, *src_cache_scan); + blended = FXDIB_ALPHA_MERGE(*src_cache_scan, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, *src_cache_scan, alpha_ratio); + } + dest_scan++; + src_cache_scan++; + } + } + return; + } + for (int col = 0; col < pixel_count; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + dp[3] = src_scan[3]; + src_scan += 4; + dp += 4; + } + } + _CompositeRow_Argb2Argb(dest_scan, src_cache_scan, pixel_count, blend_type, + clip_scan, dest_alpha_scan, src_alpha_scan); +} +void _CompositeRow_Rgb2Argb_Blend_NoClip_Transform(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp, + uint8_t* dest_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Argb_Blend_NoClip(dest_scan, src_cache_scan, width, + blend_type, 3, dest_alpha_scan); +} +inline void _CompositeRow_Rgb2Argb_Blend_Clip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Argb_Blend_Clip(dest_scan, src_cache_scan, width, + blend_type, 3, clip_scan, dest_alpha_scan); +} +inline void _CompositeRow_Rgb2Argb_NoBlend_Clip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Argb_NoBlend_Clip(dest_scan, src_cache_scan, width, 3, + clip_scan, dest_alpha_scan); +} +inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp, + uint8_t* dest_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Argb_NoBlend_NoClip(dest_scan, src_cache_scan, width, 3, + dest_alpha_scan); +} +inline void _CompositeRow_Argb2Rgb_Blend_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_alpha_scan) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int dest_gap = dest_Bpp - 3; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, 1); + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + src_scan += 4; + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_cache_scan += 3; + continue; + } + if (bNonseparableBlend) { + _RGB_Blend(blend_type, src_cache_scan, dest_scan, blended_colors); + } + for (int color = 0; color < 3; color++) { + int back_color = *dest_scan; + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, *src_cache_scan); + *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha); + dest_scan++; + src_cache_scan++; + } + dest_scan += dest_gap; + } + return; + } + _CompositeRow_Argb2Rgb_Blend(dest_scan, src_cache_scan, width, blend_type, + dest_Bpp, clip_scan, src_alpha_scan); +} +inline void _CompositeRow_Argb2Rgb_NoBlend_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_alpha_scan) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + int dest_gap = dest_Bpp - 3; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, 1); + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + src_scan += 4; + if (src_alpha == 255) { + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + *dest_scan++ = *src_cache_scan++; + dest_scan += dest_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_cache_scan += 3; + continue; + } + for (int color = 0; color < 3; color++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_cache_scan, src_alpha); + dest_scan++; + src_cache_scan++; + } + dest_scan += dest_gap; + } + return; + } + _CompositeRow_Argb2Rgb_NoBlend(dest_scan, src_cache_scan, width, dest_Bpp, + clip_scan, src_alpha_scan); +} +inline void _CompositeRow_Rgb2Rgb_Blend_NoClip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Rgb_Blend_NoClip(dest_scan, src_cache_scan, width, + blend_type, dest_Bpp, 3); +} +inline void _CompositeRow_Rgb2Rgb_Blend_Clip_Transform(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Rgb_Blend_Clip(dest_scan, src_cache_scan, width, blend_type, + dest_Bpp, 3, clip_scan); +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Rgb_NoBlend_NoClip(dest_scan, src_cache_scan, width, + dest_Bpp, 3); +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip_Transform( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan, + uint8_t* src_cache_scan, + void* pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (src_Bpp == 3) { + pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, + width); + } else { + uint8_t* dp = src_cache_scan; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1); + src_scan += 4; + dp += 3; + } + } + _CompositeRow_Rgb2Rgb_NoBlend_Clip(dest_scan, src_cache_scan, width, dest_Bpp, + 3, clip_scan); +} +inline void _CompositeRow_8bppPal2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + const uint8_t* pPalette, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan) { + if (src_alpha_scan) { + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + int src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + if (src_alpha) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + int src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (src_alpha) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan++; + } + } else { + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + src_scan++; + } + } +} +inline void _CompositeRow_8bppPal2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + const uint8_t* pPalette, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + const uint8_t* src_alpha_scan) { + if (src_alpha_scan) { + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + src_scan++; + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (src_alpha) { + *dest_scan = gray; + *dest_alpha_scan = src_alpha; + } + dest_scan++; + dest_alpha_scan++; + continue; + } + uint8_t src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + *dest_alpha_scan = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan); + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_alpha_scan++; + dest_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + src_scan++; + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + int src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (src_alpha) { + *dest_scan = gray; + *dest_alpha_scan = src_alpha; + } + dest_scan++; + dest_alpha_scan++; + continue; + } + uint8_t src_alpha = *src_alpha_scan++; + if (clip_scan) { + src_alpha = clip_scan[col] * src_alpha / 255; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + *dest_alpha_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255; + int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan); + dest_alpha_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + } + } else { + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + src_scan++; + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = gray; + *dest_alpha_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = pPalette[*src_scan]; + src_scan++; + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = gray; + *dest_alpha_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + } + } +} +inline void _CompositeRow_1bppPal2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + const uint8_t* pPalette, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + int reset_gray = pPalette[0]; + int set_gray = pPalette[1]; + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = + (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) + ? set_gray + : reset_gray; + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = + (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) + ? set_gray + : reset_gray; + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]); + } else { + *dest_scan = gray; + } + dest_scan++; + } +} +inline void _CompositeRow_1bppPal2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + const uint8_t* pPalette, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + int reset_gray = pPalette[0]; + int set_gray = pPalette[1]; + if (blend_type) { + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int blended_color; + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = + (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) + ? set_gray + : reset_gray; + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = gray; + *dest_alpha_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + blended_color = + blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan; + } + gray = bNonseparableBlend ? blended_color + : _BLEND(blend_type, *dest_scan, gray); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + uint8_t gray = + (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) + ? set_gray + : reset_gray; + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = gray; + *dest_alpha_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio); + dest_scan++; + } +} +inline void _CompositeRow_8bppRgb2Rgb_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + FX_DWORD* pPalette, + int pixel_count, + int DestBpp, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan) { + if (src_alpha_scan) { + int dest_gap = DestBpp - 3; + FX_ARGB argb = 0; + for (int col = 0; col < pixel_count; col++) { + argb = pPalette[*src_scan]; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + src_scan++; + uint8_t src_alpha = 0; + if (clip_scan) { + src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 255) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + dest_scan += dest_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += DestBpp; + continue; + } + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha); + dest_scan++; + dest_scan += dest_gap; + } + } else { + FX_ARGB argb = 0; + for (int col = 0; col < pixel_count; col++) { + argb = pPalette[*src_scan]; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]); + dest_scan++; + } else { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + } + if (DestBpp == 4) { + dest_scan++; + } + src_scan++; + } + } +} +inline void _CompositeRow_1bppRgb2Rgb_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + FX_DWORD* pPalette, + int pixel_count, + int DestBpp, + const uint8_t* clip_scan) { + int reset_r, reset_g, reset_b; + int set_r, set_g, set_b; + reset_r = FXARGB_R(pPalette[0]); + reset_g = FXARGB_G(pPalette[0]); + reset_b = FXARGB_B(pPalette[0]); + set_r = FXARGB_R(pPalette[1]); + set_g = FXARGB_G(pPalette[1]); + set_b = FXARGB_B(pPalette[1]); + for (int col = 0; col < pixel_count; col++) { + int src_r, src_g, src_b; + if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) { + src_r = set_r; + src_g = set_g; + src_b = set_b; + } else { + src_r = reset_r; + src_g = reset_g; + src_b = reset_b; + } + if (clip_scan && clip_scan[col] < 255) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]); + dest_scan++; + } else { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + } + if (DestBpp == 4) { + dest_scan++; + } + } +} +inline void _CompositeRow_8bppRgb2Argb_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + FX_DWORD* pPalette, + const uint8_t* clip_scan, + const uint8_t* src_alpha_scan) { + if (src_alpha_scan) { + for (int col = 0; col < width; col++) { + FX_ARGB argb = pPalette[*src_scan]; + src_scan++; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255; + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + } else { + FXARGB_SETDIB(dest_scan, + FXARGB_MAKE(*src_alpha_scan, src_r, src_g, src_b)); + } + dest_scan += 4; + src_alpha_scan++; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 0) { + dest_scan += 4; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + dest_scan++; + } + } else { + for (int col = 0; col < width; col++) { + FX_ARGB argb = pPalette[*src_scan]; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_scan++ = 255; + src_scan++; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 4; + src_scan++; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + dest_scan++; + src_scan++; + } + } +} + +void _CompositeRow_8bppRgb2Rgba_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + FX_DWORD* pPalette, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan, + const uint8_t* src_alpha_scan) { + if (src_alpha_scan) { + for (int col = 0; col < width; col++) { + FX_ARGB argb = pPalette[*src_scan]; + src_scan++; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255; + *dest_alpha_scan++ = src_alpha; + } else { + *dest_alpha_scan++ = *src_alpha_scan; + } + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + src_alpha_scan++; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255; + } else { + src_alpha = *src_alpha_scan++; + } + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + } + } else { + for (int col = 0; col < width; col++) { + FX_ARGB argb = pPalette[*src_scan]; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_alpha_scan++ = 255; + src_scan++; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + src_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + src_scan++; + } + } +} + +inline void _CompositeRow_1bppRgb2Argb_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + int width, + FX_DWORD* pPalette, + const uint8_t* clip_scan) { + int reset_r, reset_g, reset_b; + int set_r, set_g, set_b; + reset_r = FXARGB_R(pPalette[0]); + reset_g = FXARGB_G(pPalette[0]); + reset_b = FXARGB_B(pPalette[0]); + set_r = FXARGB_R(pPalette[1]); + set_g = FXARGB_G(pPalette[1]); + set_b = FXARGB_B(pPalette[1]); + for (int col = 0; col < width; col++) { + int src_r, src_g, src_b; + if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) { + src_r = set_r; + src_g = set_g; + src_b = set_b; + } else { + src_r = reset_r; + src_g = reset_g; + src_b = reset_b; + } + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 4; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + dest_scan++; + } +} +void _CompositeRow_1bppRgb2Rgba_NoBlend(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + int width, + FX_DWORD* pPalette, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + int reset_r, reset_g, reset_b; + int set_r, set_g, set_b; + reset_r = FXARGB_R(pPalette[0]); + reset_g = FXARGB_G(pPalette[0]); + reset_b = FXARGB_B(pPalette[0]); + set_r = FXARGB_R(pPalette[1]); + set_g = FXARGB_G(pPalette[1]); + set_b = FXARGB_B(pPalette[1]); + for (int col = 0; col < width; col++) { + int src_r, src_g, src_b; + if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) { + src_r = set_r; + src_g = set_g; + src_b = set_b; + } else { + src_r = reset_r; + src_g = reset_g; + src_b = reset_b; + } + if (!clip_scan || clip_scan[col] == 255) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_alpha_scan++ = 255; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + continue; + } + int back_alpha = *dest_alpha_scan; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + } +} +void _CompositeRow_ByteMask2Argb(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + dest_scan += 4; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio); + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + } + dest_scan += 2; + } +} +void _CompositeRow_ByteMask2Rgba(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_alpha_scan++ = src_alpha; + continue; + } + if (src_alpha == 0) { + dest_scan += 3; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio); + dest_scan++; + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + } + } +} +void _CompositeRow_ByteMask2Rgb(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int pixel_count, + int blend_type, + int Bpp, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + if (src_alpha == 0) { + dest_scan += Bpp; + continue; + } + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha); + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha); + } + dest_scan += Bpp - 2; + } +} +void _CompositeRow_ByteMask2Mask(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int pixel_count, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + uint8_t back_alpha = *dest_scan; + if (!back_alpha) { + *dest_scan = src_alpha; + } else if (src_alpha) { + *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255; + } + dest_scan++; + } +} +void _CompositeRow_ByteMask2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_gray, + int pixel_count, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + if (src_alpha) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha); + } + dest_scan++; + } +} +void _CompositeRow_ByteMask2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_gray, + int pixel_count, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + *dest_scan++ = src_gray; + *dest_alpha_scan++ = src_alpha; + continue; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio); + dest_scan++; + } +} +void _CompositeRow_BitMask2Argb(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int src_left, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) { + FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b); + for (int col = 0; col < pixel_count; col++) { + if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) { + FXARGB_SETDIB(dest_scan, argb); + } + dest_scan += 4; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan += 4; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + dest_scan += 4; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio); + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + } + dest_scan += 2; + } +} +void _CompositeRow_BitMask2Rgba(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int src_left, + int pixel_count, + int blend_type, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) { + for (int col = 0; col < pixel_count; col++) { + if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) { + dest_scan[0] = src_b; + dest_scan[1] = src_g; + dest_scan[2] = src_r; + *dest_alpha_scan = mask_alpha; + } + dest_scan += 3; + dest_alpha_scan++; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan += 3; + dest_alpha_scan++; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + *dest_scan++ = src_b; + *dest_scan++ = src_g; + *dest_scan++ = src_r; + *dest_alpha_scan++ = mask_alpha; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio); + dest_scan++; + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio); + dest_scan++; + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio); + dest_scan++; + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio); + dest_scan++; + } + } +} +void _CompositeRow_BitMask2Rgb(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int src_left, + int pixel_count, + int blend_type, + int Bpp, + const uint8_t* clip_scan) { + if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) { + for (int col = 0; col < pixel_count; col++) { + if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) { + dest_scan[2] = src_r; + dest_scan[1] = src_g; + dest_scan[0] = src_b; + } + dest_scan += Bpp; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan += Bpp; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + if (src_alpha == 0) { + dest_scan += Bpp; + continue; + } + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha); + } else if (blend_type) { + int blended = _BLEND(blend_type, *dest_scan, src_b); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_g); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + dest_scan++; + blended = _BLEND(blend_type, *dest_scan, src_r); + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha); + } else { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha); + } + dest_scan += Bpp - 2; + } +} +void _CompositeRow_BitMask2Mask(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_left, + int pixel_count, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan++; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + uint8_t back_alpha = *dest_scan; + if (!back_alpha) { + *dest_scan = src_alpha; + } else if (src_alpha) { + *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255; + } + dest_scan++; + } +} +void _CompositeRow_BitMask2Gray(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_gray, + int src_left, + int pixel_count, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan++; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + if (src_alpha) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha); + } + dest_scan++; + } +} +void _CompositeRow_BitMask2Graya(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_gray, + int src_left, + int pixel_count, + const uint8_t* clip_scan, + uint8_t* dest_alpha_scan) { + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan++; + dest_alpha_scan++; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + uint8_t back_alpha = *dest_alpha_scan; + if (back_alpha == 0) { + *dest_scan++ = src_gray; + *dest_alpha_scan++ = src_alpha; + continue; + } + if (src_alpha == 0) { + dest_scan++; + dest_alpha_scan++; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_alpha_scan++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio); + dest_scan++; + } +} +void _CompositeRow_Argb2Argb_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + for (int col = 0; col < pixel_count; col++) { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (clip_scan) { + int src_alpha = clip_scan[col] * src_scan[3] / 255; + dest_scan[3] = src_alpha; + dest_scan[0] = src_scan[2]; + dest_scan[1] = src_scan[1]; + dest_scan[2] = src_scan[0]; + } else { + FXARGB_RGBORDERCOPY(dest_scan, src_scan); + } + dest_scan += 4; + src_scan += 4; + continue; + } + uint8_t src_alpha; + if (clip_scan) { + src_alpha = clip_scan[col] * src_scan[3] / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += 4; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + if (blend_type) { + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, dest_scan[index], *src_scan); + blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha); + dest_scan[index] = + FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio); + } else { + dest_scan[index] = + FXDIB_ALPHA_MERGE(dest_scan[index], *src_scan, alpha_ratio); + } + src_scan++; + } + dest_scan += 4; + src_scan++; + } +} +void _CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + if (src_Bpp == 4) { + FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan)); + } else { + FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], + src_scan[1], src_scan[0])); + } + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + dest_scan[3] = 0xff; + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + int src_color = FX_GAMMA(*src_scan); + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, dest_scan[index], src_color); + dest_scan[index] = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + src_scan++; + } + dest_scan += 4; + src_scan += src_gap; + } +} +inline void _CompositeRow_Argb2Rgb_Blend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + const uint8_t* clip_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 4; + continue; + } + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + int back_color = FX_GAMMA(dest_scan[index]); + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, *src_scan); + dest_scan[index] = + FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha)); + src_scan++; + } + dest_scan += dest_Bpp; + src_scan++; + } +} +inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp) { + for (int col = 0; col < width; col++) { + if (src_Bpp == 4) { + FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan)); + } else { + FXARGB_SETRGBORDERDIB( + dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0])); + } + dest_scan += 4; + src_scan += src_Bpp; + } +} +inline void _CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + int back_color = FX_GAMMA(dest_scan[index]); + int src_color = FX_GAMMA(*src_scan); + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, src_color); + dest_scan[index] = FX_GAMMA_INVERSE(blended); + src_scan++; + } + dest_scan += dest_Bpp; + src_scan += src_gap; + } +} +inline void _CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + const uint8_t* clip_scan) { + for (int col = 0; col < width; col++) { + uint8_t src_alpha; + if (clip_scan) { + src_alpha = src_scan[3] * (*clip_scan++) / 255; + } else { + src_alpha = src_scan[3]; + } + if (src_alpha == 255) { + dest_scan[2] = FX_GAMMA_INVERSE(*src_scan++); + dest_scan[1] = FX_GAMMA_INVERSE(*src_scan++); + dest_scan[0] = FX_GAMMA_INVERSE(*src_scan++); + dest_scan += dest_Bpp; + src_scan++; + continue; + } + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += 4; + continue; + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + dest_scan[index] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[index]), *src_scan, src_alpha)); + src_scan++; + } + dest_scan += dest_Bpp; + src_scan++; + } +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp) { + for (int col = 0; col < width; col++) { + dest_scan[2] = src_scan[0]; + dest_scan[1] = src_scan[1]; + dest_scan[0] = src_scan[2]; + dest_scan += dest_Bpp; + src_scan += src_Bpp; + } +} +inline void _CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int src_Bpp, + const uint8_t* clip_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + int src_alpha = *clip_scan++; + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + dest_scan[2] = FX_GAMMA(*src_scan++); + dest_scan[1] = FX_GAMMA(*src_scan++); + dest_scan[0] = FX_GAMMA(*src_scan++); + src_scan += src_gap; + dest_scan += 4; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + int src_color = FX_GAMMA(*src_scan); + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, dest_scan[index], src_color); + blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha); + dest_scan[index] = + FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio); + src_scan++; + } + dest_scan += 4; + src_scan += src_gap; + } +} +inline void _CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int blend_type, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan) { + int blended_colors[3]; + FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE; + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + uint8_t src_alpha = *clip_scan++; + if (src_alpha == 0) { + dest_scan += dest_Bpp; + src_scan += src_Bpp; + continue; + } + if (bNonseparableBlend) { + uint8_t dest_scan_o[3]; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + } + for (int color = 0; color < 3; color++) { + int index = 2 - color; + int src_color = FX_GAMMA(*src_scan); + int back_color = FX_GAMMA(dest_scan[index]); + int blended = bNonseparableBlend + ? blended_colors[color] + : _BLEND(blend_type, back_color, src_color); + dest_scan[index] = + FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha)); + src_scan++; + } + dest_scan += dest_Bpp; + src_scan += src_gap; + } +} +inline void _CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int src_Bpp, + const uint8_t* clip_scan) { + int src_gap = src_Bpp - 3; + for (int col = 0; col < width; col++) { + int src_alpha = clip_scan[col]; + if (src_alpha == 255) { + dest_scan[2] = FX_GAMMA(*src_scan++); + dest_scan[1] = FX_GAMMA(*src_scan++); + dest_scan[0] = FX_GAMMA(*src_scan++); + dest_scan[3] = 255; + dest_scan += 4; + src_scan += src_gap; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + src_scan += src_Bpp; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + for (int color = 0; color < 3; color++) { + int index = 2 - color; + dest_scan[index] = + FXDIB_ALPHA_MERGE(dest_scan[index], FX_GAMMA(*src_scan), alpha_ratio); + src_scan++; + } + dest_scan += 4; + src_scan += src_gap; + } +} +inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + int dest_Bpp, + int src_Bpp, + const uint8_t* clip_scan) { + for (int col = 0; col < width; col++) { + int src_alpha = clip_scan[col]; + if (src_alpha == 255) { + dest_scan[2] = src_scan[0]; + dest_scan[1] = src_scan[1]; + dest_scan[0] = src_scan[2]; + } else if (src_alpha) { + dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[2]), FX_GAMMA(*src_scan), src_alpha)); + src_scan++; + dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[1]), FX_GAMMA(*src_scan), src_alpha)); + src_scan++; + dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE( + FX_GAMMA(dest_scan[0]), FX_GAMMA(*src_scan), src_alpha)); + dest_scan += dest_Bpp; + src_scan += src_Bpp - 2; + continue; + } + dest_scan += dest_Bpp; + src_scan += src_Bpp; + } +} +inline void _CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + FX_ARGB* pPalette, + int pixel_count, + int DestBpp, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + FX_ARGB argb = pPalette ? pPalette[*src_scan] : (*src_scan) * 0x010101; + int src_r = FXARGB_R(argb); + int src_g = FXARGB_G(argb); + int src_b = FXARGB_B(argb); + if (clip_scan && clip_scan[col] < 255) { + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]); + } else { + dest_scan[2] = src_b; + dest_scan[1] = src_g; + dest_scan[0] = src_r; + } + dest_scan += DestBpp; + src_scan++; + } +} +inline void _CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + FX_ARGB* pPalette, + int pixel_count, + int DestBpp, + const uint8_t* clip_scan) { + int reset_r, reset_g, reset_b; + int set_r, set_g, set_b; + if (pPalette) { + reset_r = FXARGB_R(pPalette[0]); + reset_g = FXARGB_G(pPalette[0]); + reset_b = FXARGB_B(pPalette[0]); + set_r = FXARGB_R(pPalette[1]); + set_g = FXARGB_G(pPalette[1]); + set_b = FXARGB_B(pPalette[1]); + } else { + reset_r = reset_g = reset_b = 0; + set_r = set_g = set_b = 255; + } + for (int col = 0; col < pixel_count; col++) { + int src_r, src_g, src_b; + if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) { + src_r = set_r; + src_g = set_g; + src_b = set_b; + } else { + src_r = reset_r; + src_g = reset_g; + src_b = reset_b; + } + if (clip_scan && clip_scan[col] < 255) { + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]); + } else { + dest_scan[2] = src_b; + dest_scan[1] = src_g; + dest_scan[0] = src_r; + } + dest_scan += DestBpp; + } +} +inline void _CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + FX_ARGB* pPalette, + const uint8_t* clip_scan) { + for (int col = 0; col < width; col++) { + int src_r, src_g, src_b; + if (pPalette) { + FX_ARGB argb = pPalette[*src_scan]; + src_r = FXARGB_R(argb); + src_g = FXARGB_G(argb); + src_b = FXARGB_B(argb); + } else { + src_r = src_g = src_b = *src_scan; + } + if (!clip_scan || clip_scan[col] == 255) { + dest_scan[2] = FX_GAMMA(src_b); + dest_scan[1] = FX_GAMMA(src_g); + dest_scan[0] = FX_GAMMA(src_r); + dest_scan[3] = 255; + src_scan++; + dest_scan += 4; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 4; + src_scan++; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], FX_GAMMA(src_b), alpha_ratio); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], FX_GAMMA(src_g), alpha_ratio); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], FX_GAMMA(src_r), alpha_ratio); + dest_scan += 4; + src_scan++; + } +} +inline void _CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder( + uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + int width, + FX_ARGB* pPalette, + const uint8_t* clip_scan) { + int reset_r, reset_g, reset_b; + int set_r, set_g, set_b; + if (pPalette) { + reset_r = FXARGB_R(pPalette[0]); + reset_g = FXARGB_G(pPalette[0]); + reset_b = FXARGB_B(pPalette[0]); + set_r = FXARGB_R(pPalette[1]); + set_g = FXARGB_G(pPalette[1]); + set_b = FXARGB_B(pPalette[1]); + } else { + reset_r = reset_g = reset_b = 0; + set_r = set_g = set_b = 255; + } + for (int col = 0; col < width; col++) { + int src_r, src_g, src_b; + if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) { + src_r = set_r; + src_g = set_g; + src_b = set_b; + } else { + src_r = reset_r; + src_g = reset_g; + src_b = reset_b; + } + if (!clip_scan || clip_scan[col] == 255) { + dest_scan[2] = FX_GAMMA(src_b); + dest_scan[1] = FX_GAMMA(src_g); + dest_scan[0] = FX_GAMMA(src_r); + dest_scan[3] = 255; + dest_scan += 4; + continue; + } + int src_alpha = clip_scan[col]; + if (src_alpha == 0) { + dest_scan += 4; + continue; + } + int back_alpha = dest_scan[3]; + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], FX_GAMMA(src_b), alpha_ratio); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], FX_GAMMA(src_g), alpha_ratio); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], FX_GAMMA(src_r), alpha_ratio); + dest_scan += 4; + } +} +void _CompositeRow_ByteMask2Argb_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETRGBORDERDIB(dest_scan, + FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + dest_scan += 4; + continue; + } + if (src_alpha == 0) { + dest_scan += 4; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + uint8_t dest_scan_o[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio); + } else if (blend_type) { + int blended = _BLEND(blend_type, dest_scan[2], src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio); + blended = _BLEND(blend_type, dest_scan[1], src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio); + blended = _BLEND(blend_type, dest_scan[0], src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio); + } else { + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio); + } + dest_scan += 4; + } +} +void _CompositeRow_ByteMask2Rgb_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int pixel_count, + int blend_type, + int Bpp, + const uint8_t* clip_scan) { + for (int col = 0; col < pixel_count; col++) { + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255; + } else { + src_alpha = mask_alpha * src_scan[col] / 255; + } + if (src_alpha == 0) { + dest_scan += Bpp; + continue; + } + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + uint8_t dest_scan_o[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha); + } else if (blend_type) { + int blended = _BLEND(blend_type, dest_scan[2], src_b); + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, src_alpha); + blended = _BLEND(blend_type, dest_scan[1], src_g); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, src_alpha); + blended = _BLEND(blend_type, dest_scan[0], src_r); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, src_alpha); + } else { + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, src_alpha); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, src_alpha); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, src_alpha); + } + dest_scan += Bpp; + } +} +void _CompositeRow_BitMask2Argb_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int src_left, + int pixel_count, + int blend_type, + const uint8_t* clip_scan) { + if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) { + FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b); + for (int col = 0; col < pixel_count; col++) { + if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) { + FXARGB_SETRGBORDERDIB(dest_scan, argb); + } + dest_scan += 4; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan += 4; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETRGBORDERDIB(dest_scan, + FXARGB_MAKE(src_alpha, src_r, src_g, src_b)); + dest_scan += 4; + continue; + } + uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255; + dest_scan[3] = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + uint8_t dest_scan_o[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio); + } else if (blend_type) { + int blended = _BLEND(blend_type, dest_scan[2], src_b); + blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha); + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio); + blended = _BLEND(blend_type, dest_scan[1], src_g); + blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio); + blended = _BLEND(blend_type, dest_scan[0], src_r); + blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio); + } else { + dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio); + dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio); + dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio); + } + dest_scan += 4; + } +} +void _CompositeRow_BitMask2Rgb_RgbByteOrder(uint8_t* dest_scan, + const uint8_t* src_scan, + int mask_alpha, + int src_r, + int src_g, + int src_b, + int src_left, + int pixel_count, + int blend_type, + int Bpp, + const uint8_t* clip_scan) { + if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) { + for (int col = 0; col < pixel_count; col++) { + if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) { + dest_scan[2] = src_b; + dest_scan[1] = src_g; + dest_scan[0] = src_r; + } + dest_scan += Bpp; + } + return; + } + for (int col = 0; col < pixel_count; col++) { + if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) { + dest_scan += Bpp; + continue; + } + int src_alpha; + if (clip_scan) { + src_alpha = mask_alpha * clip_scan[col] / 255; + } else { + src_alpha = mask_alpha; + } + if (src_alpha == 0) { + dest_scan += Bpp; + continue; + } + if (blend_type >= FXDIB_BLEND_NONSEPARABLE) { + int blended_colors[3]; + uint8_t src_scan[3]; + uint8_t dest_scan_o[3]; + src_scan[0] = src_b; + src_scan[1] = src_g; + src_scan[2] = src_r; + dest_scan_o[0] = dest_scan[2]; + dest_scan_o[1] = dest_scan[1]; + dest_scan_o[2] = dest_scan[0]; + _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors); + dest_scan[2] = + FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha); + dest_scan[1] = + FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha); + dest_scan[0] = + FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha); + } else if (blend_type) { + int back_color = FX_GAMMA(dest_scan[2]); + int blended = _BLEND(blend_type, back_color, src_b); + dest_scan[2] = + FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha)); + back_color = FX_GAMMA(dest_scan[1]); + blended = _BLEND(blend_type, back_color, src_g); + dest_scan[1] = + FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha)); + back_color = FX_GAMMA(dest_scan[0]); + blended = _BLEND(blend_type, back_color, src_r); + dest_scan[0] = + FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha)); + } else { + dest_scan[2] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), src_b, src_alpha)); + dest_scan[1] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), src_g, src_alpha)); + dest_scan[0] = FX_GAMMA_INVERSE( + FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), src_r, src_alpha)); + } + dest_scan += Bpp; + } +} +inline FX_BOOL _ScanlineCompositor_InitSourceMask(FXDIB_Format dest_format, + int alpha_flag, + FX_DWORD mask_color, + int& mask_alpha, + int& mask_red, + int& mask_green, + int& mask_blue, + int& mask_black, + void* icc_module, + void* pIccTransform) { + ICodec_IccModule* pIccModule = (ICodec_IccModule*)icc_module; + if (alpha_flag >> 8) { + mask_alpha = alpha_flag & 0xff; + mask_red = FXSYS_GetCValue(mask_color); + mask_green = FXSYS_GetMValue(mask_color); + mask_blue = FXSYS_GetYValue(mask_color); + mask_black = FXSYS_GetKValue(mask_color); + } else { + mask_alpha = FXARGB_A(mask_color); + mask_red = FXARGB_R(mask_color); + mask_green = FXARGB_G(mask_color); + mask_blue = FXARGB_B(mask_color); + } + if (dest_format == FXDIB_8bppMask) { + return TRUE; + } + if ((dest_format & 0xff) == 8) { + if (pIccTransform) { + mask_color = (alpha_flag >> 8) ? FXCMYK_TODIB(mask_color) + : FXARGB_TODIB(mask_color); + uint8_t* gray_p = (uint8_t*)&mask_color; + pIccModule->TranslateScanline(pIccTransform, gray_p, gray_p, 1); + mask_red = dest_format & 0x0400 ? FX_CCOLOR(gray_p[0]) : gray_p[0]; + } else { + if (alpha_flag >> 8) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(mask_red, mask_green, mask_blue, mask_black, r, g, + b); + mask_red = FXRGB2GRAY(r, g, b); + } else { + mask_red = FXRGB2GRAY(mask_red, mask_green, mask_blue); + } + if (dest_format & 0x0400) { + mask_red = FX_CCOLOR(mask_red); + } + } + } else { + uint8_t* mask_color_p = (uint8_t*)&mask_color; + mask_color = + (alpha_flag >> 8) ? FXCMYK_TODIB(mask_color) : FXARGB_TODIB(mask_color); + if (pIccTransform) { + pIccModule->TranslateScanline(pIccTransform, mask_color_p, mask_color_p, + 1); + mask_red = mask_color_p[2]; + mask_green = mask_color_p[1]; + mask_blue = mask_color_p[0]; + } else if (alpha_flag >> 8) { + AdobeCMYK_to_sRGB1(mask_color_p[0], mask_color_p[1], mask_color_p[2], + mask_color_p[3], mask_color_p[2], mask_color_p[1], + mask_color_p[0]); + mask_red = mask_color_p[2]; + mask_green = mask_color_p[1]; + mask_blue = mask_color_p[0]; + } + } + return TRUE; +} +inline void _ScanlineCompositor_InitSourcePalette(FXDIB_Format src_format, + FXDIB_Format dest_format, + FX_DWORD*& pDestPalette, + FX_DWORD* pSrcPalette, + void* icc_module, + void* pIccTransform) { + ICodec_IccModule* pIccModule = (ICodec_IccModule*)icc_module; + FX_BOOL isSrcCmyk = !!(src_format & 0x0400); + FX_BOOL isDstCmyk = !!(dest_format & 0x0400); + pDestPalette = NULL; + if (pIccTransform) { + if (pSrcPalette) { + if ((dest_format & 0xff) == 8) { + int pal_count = 1 << (src_format & 0xff); + uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count); + pDestPalette = (FX_DWORD*)gray_pal; + for (int i = 0; i < pal_count; i++) { + FX_DWORD color = isSrcCmyk ? FXCMYK_TODIB(pSrcPalette[i]) + : FXARGB_TODIB(pSrcPalette[i]); + pIccModule->TranslateScanline(pIccTransform, gray_pal, + (const uint8_t*)&color, 1); + gray_pal++; + } + } else { + int palsize = 1 << (src_format & 0xff); + pDestPalette = FX_Alloc(FX_DWORD, palsize); + for (int i = 0; i < palsize; i++) { + FX_DWORD color = isSrcCmyk ? FXCMYK_TODIB(pSrcPalette[i]) + : FXARGB_TODIB(pSrcPalette[i]); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)&color, + (const uint8_t*)&color, 1); + pDestPalette[i] = + isDstCmyk ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + } + } + } else { + int pal_count = 1 << (src_format & 0xff); + uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count); + if (pal_count == 2) { + gray_pal[0] = 0; + gray_pal[1] = 255; + } else { + for (int i = 0; i < pal_count; i++) { + gray_pal[i] = i; + } + } + if ((dest_format & 0xff) == 8) { + pIccModule->TranslateScanline(pIccTransform, gray_pal, gray_pal, + pal_count); + pDestPalette = (FX_DWORD*)gray_pal; + } else { + pDestPalette = FX_Alloc(FX_DWORD, pal_count); + for (int i = 0; i < pal_count; i++) { + pIccModule->TranslateScanline( + pIccTransform, (uint8_t*)&pDestPalette[i], &gray_pal[i], 1); + pDestPalette[i] = isDstCmyk ? FXCMYK_TODIB(pDestPalette[i]) + : FXARGB_TODIB(pDestPalette[i]); + } + FX_Free(gray_pal); + } + } + } else { + if (pSrcPalette) { + if ((dest_format & 0xff) == 8) { + int pal_count = 1 << (src_format & 0xff); + uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count); + pDestPalette = (FX_DWORD*)gray_pal; + if (isSrcCmyk) { + for (int i = 0; i < pal_count; i++) { + FX_CMYK cmyk = pSrcPalette[i]; + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), + FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk), r, + g, b); + *gray_pal++ = FXRGB2GRAY(r, g, b); + } + } else { + for (int i = 0; i < pal_count; i++) { + FX_ARGB argb = pSrcPalette[i]; + *gray_pal++ = + FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb)); + } + } + } else { + int palsize = 1 << (src_format & 0xff); + pDestPalette = FX_Alloc(FX_DWORD, palsize); + if (isDstCmyk == isSrcCmyk) { + FXSYS_memcpy(pDestPalette, pSrcPalette, palsize * sizeof(FX_DWORD)); + } else { + for (int i = 0; i < palsize; i++) { + FX_CMYK cmyk = pSrcPalette[i]; + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), + FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk), r, + g, b); + pDestPalette[i] = FXARGB_MAKE(0xff, r, g, b); + } + } + } + } else { + if ((dest_format & 0xff) == 8) { + int pal_count = 1 << (src_format & 0xff); + uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count); + if (pal_count == 2) { + gray_pal[0] = 0; + gray_pal[1] = 255; + } else { + for (int i = 0; i < pal_count; i++) { + gray_pal[i] = i; + } + } + pDestPalette = (FX_DWORD*)gray_pal; + } else { + int palsize = 1 << (src_format & 0xff); + pDestPalette = FX_Alloc(FX_DWORD, palsize); + if (palsize == 2) { + pDestPalette[0] = isSrcCmyk ? 255 : 0xff000000; + pDestPalette[1] = isSrcCmyk ? 0 : 0xffffffff; + } else { + for (int i = 0; i < palsize; i++) { + pDestPalette[i] = isSrcCmyk ? FX_CCOLOR(i) : (i * 0x10101); + } + } + if (isSrcCmyk != isDstCmyk) { + for (int i = 0; i < palsize; i++) { + FX_CMYK cmyk = pDestPalette[i]; + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), + FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk), r, + g, b); + pDestPalette[i] = FXARGB_MAKE(0xff, r, g, b); + } + } + } + } + } +} +CFX_ScanlineCompositor::CFX_ScanlineCompositor() { + m_pSrcPalette = NULL; + m_pCacheScanline = NULL; + m_CacheSize = 0; + m_bRgbByteOrder = FALSE; + m_BlendType = FXDIB_BLEND_NORMAL; +} +CFX_ScanlineCompositor::~CFX_ScanlineCompositor() { + FX_Free(m_pSrcPalette); + FX_Free(m_pCacheScanline); +} +FX_BOOL CFX_ScanlineCompositor::Init(FXDIB_Format dest_format, + FXDIB_Format src_format, + int32_t width, + FX_DWORD* pSrcPalette, + FX_DWORD mask_color, + int blend_type, + FX_BOOL bClip, + FX_BOOL bRgbByteOrder, + int alpha_flag, + void* pIccTransform) { + m_SrcFormat = src_format; + m_DestFormat = dest_format; + m_BlendType = blend_type; + m_bRgbByteOrder = bRgbByteOrder; + ICodec_IccModule* pIccModule = NULL; + if (CFX_GEModule::Get()->GetCodecModule()) { + pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + } + if (!pIccModule) { + pIccTransform = NULL; + } + m_pIccTransform = pIccTransform; + if ((dest_format & 0xff) == 1) { + return FALSE; + } + if (m_SrcFormat == FXDIB_1bppMask || m_SrcFormat == FXDIB_8bppMask) { + return _ScanlineCompositor_InitSourceMask( + dest_format, alpha_flag, mask_color, m_MaskAlpha, m_MaskRed, + m_MaskGreen, m_MaskBlue, m_MaskBlack, pIccModule, pIccTransform); + } + if (!pIccTransform && (~src_format & 0x0400) && (dest_format & 0x0400)) { + return FALSE; + } + if ((m_SrcFormat & 0xff) <= 8) { + if (dest_format == FXDIB_8bppMask) { + return TRUE; + } + _ScanlineCompositor_InitSourcePalette(src_format, dest_format, + m_pSrcPalette, pSrcPalette, + pIccModule, pIccTransform); + m_Transparency = + (dest_format == FXDIB_Argb ? 1 : 0) + (dest_format & 0x0200 ? 2 : 0) + + (dest_format & 0x0400 ? 4 : 0) + ((src_format & 0xff) == 1 ? 8 : 0); + return TRUE; + } + m_Transparency = (src_format & 0x0200 ? 0 : 1) + + (dest_format & 0x0200 ? 0 : 2) + + (blend_type == FXDIB_BLEND_NORMAL ? 4 : 0) + + (bClip ? 8 : 0) + (src_format & 0x0400 ? 16 : 0) + + (dest_format & 0x0400 ? 32 : 0) + (pIccTransform ? 64 : 0); + return TRUE; +} +void CFX_ScanlineCompositor::CompositeRgbBitmapLine( + uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + const uint8_t* clip_scan, + const uint8_t* src_extra_alpha, + uint8_t* dst_extra_alpha) { + int src_Bpp = (m_SrcFormat & 0xff) >> 3; + int dest_Bpp = (m_DestFormat & 0xff) >> 3; + if (m_bRgbByteOrder) { + switch (m_Transparency) { + case 0: + case 4: + case 8: + case 12: + _CompositeRow_Argb2Argb_RgbByteOrder(dest_scan, src_scan, width, + m_BlendType, clip_scan); + break; + case 1: + _CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder( + dest_scan, src_scan, width, m_BlendType, src_Bpp); + break; + case 2: + case 10: + _CompositeRow_Argb2Rgb_Blend_RgbByteOrder( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan); + break; + case 3: + _CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp); + break; + case 5: + _CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder(dest_scan, src_scan, + width, src_Bpp); + break; + case 6: + case 14: + _CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder(dest_scan, src_scan, width, + dest_Bpp, clip_scan); + break; + case 7: + _CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder( + dest_scan, src_scan, width, dest_Bpp, src_Bpp); + break; + case 9: + _CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder( + dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan); + break; + case 11: + _CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, + clip_scan); + break; + case 13: + _CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder( + dest_scan, src_scan, width, src_Bpp, clip_scan); + break; + case 15: + _CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder( + dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan); + break; + } + return; + } + if (m_DestFormat == FXDIB_8bppMask) { + if (m_SrcFormat & 0x0200) { + if (m_SrcFormat == FXDIB_Argb) { + _CompositeRow_Argb2Mask(dest_scan, src_scan, width, clip_scan); + } else { + _CompositeRow_Rgba2Mask(dest_scan, src_extra_alpha, width, clip_scan); + } + } else { + _CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan); + } + } else if ((m_DestFormat & 0xff) == 8) { + if (m_DestFormat & 0x0400) { + for (int i = 0; i < width; i++) { + *dest_scan = ~*dest_scan; + dest_scan++; + } + } + if (m_SrcFormat & 0x0200) { + if (m_DestFormat & 0x0200) { + _CompositeRow_Argb2Graya(dest_scan, src_scan, width, m_BlendType, + clip_scan, src_extra_alpha, dst_extra_alpha, + m_pIccTransform); + } else { + _CompositeRow_Argb2Gray(dest_scan, src_scan, width, m_BlendType, + clip_scan, src_extra_alpha, m_pIccTransform); + } + } else { + if (m_DestFormat & 0x0200) { + _CompositeRow_Rgb2Graya(dest_scan, src_scan, src_Bpp, width, + m_BlendType, clip_scan, dst_extra_alpha, + m_pIccTransform); + } else { + _CompositeRow_Rgb2Gray(dest_scan, src_scan, src_Bpp, width, m_BlendType, + clip_scan, m_pIccTransform); + } + } + if (m_DestFormat & 0x0400) { + for (int i = 0; i < width; i++) { + *dest_scan = ~*dest_scan; + dest_scan++; + } + } + } else { + int dest_Size = width * dest_Bpp + 4; + if (dest_Size > m_CacheSize) { + m_pCacheScanline = FX_Realloc(uint8_t, m_pCacheScanline, dest_Size); + if (!m_pCacheScanline) { + return; + } + m_CacheSize = dest_Size; + } + switch (m_Transparency) { + case 0: + case 4: + case 8: + case 4 + 8: { + _CompositeRow_Argb2Argb(dest_scan, src_scan, width, m_BlendType, + clip_scan, dst_extra_alpha, src_extra_alpha); + } break; + case 64: + case 4 + 64: + case 8 + 64: + case 4 + 8 + 64: { + _CompositeRow_Argb2Argb_Transform( + dest_scan, src_scan, width, m_BlendType, clip_scan, dst_extra_alpha, + src_extra_alpha, m_pCacheScanline, m_pIccTransform); + } break; + case 1: + _CompositeRow_Rgb2Argb_Blend_NoClip( + dest_scan, src_scan, width, m_BlendType, src_Bpp, dst_extra_alpha); + break; + case 1 + 64: + _CompositeRow_Rgb2Argb_Blend_NoClip_Transform( + dest_scan, src_scan, width, m_BlendType, src_Bpp, dst_extra_alpha, + m_pCacheScanline, m_pIccTransform); + break; + case 1 + 8: + _CompositeRow_Rgb2Argb_Blend_Clip(dest_scan, src_scan, width, + m_BlendType, src_Bpp, clip_scan, + dst_extra_alpha); + break; + case 1 + 8 + 64: + _CompositeRow_Rgb2Argb_Blend_Clip_Transform( + dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan, + dst_extra_alpha, m_pCacheScanline, m_pIccTransform); + break; + case 1 + 4: + _CompositeRow_Rgb2Argb_NoBlend_NoClip(dest_scan, src_scan, width, + src_Bpp, dst_extra_alpha); + break; + case 1 + 4 + 64: + _CompositeRow_Rgb2Argb_NoBlend_NoClip_Transform( + dest_scan, src_scan, width, src_Bpp, dst_extra_alpha, + m_pCacheScanline, m_pIccTransform); + break; + case 1 + 4 + 8: + _CompositeRow_Rgb2Argb_NoBlend_Clip(dest_scan, src_scan, width, src_Bpp, + clip_scan, dst_extra_alpha); + break; + case 1 + 4 + 8 + 64: + _CompositeRow_Rgb2Argb_NoBlend_Clip_Transform( + dest_scan, src_scan, width, src_Bpp, clip_scan, dst_extra_alpha, + m_pCacheScanline, m_pIccTransform); + break; + case 2: + case 2 + 8: + _CompositeRow_Argb2Rgb_Blend(dest_scan, src_scan, width, m_BlendType, + dest_Bpp, clip_scan, src_extra_alpha); + break; + case 2 + 64: + case 2 + 8 + 64: + _CompositeRow_Argb2Rgb_Blend_Transform( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan, + src_extra_alpha, m_pCacheScanline, m_pIccTransform); + break; + case 2 + 4: + case 2 + 4 + 8: + _CompositeRow_Argb2Rgb_NoBlend(dest_scan, src_scan, width, dest_Bpp, + clip_scan, src_extra_alpha); + break; + case 2 + 4 + 64: + case 2 + 4 + 8 + 64: + _CompositeRow_Argb2Rgb_NoBlend_Transform( + dest_scan, src_scan, width, dest_Bpp, clip_scan, src_extra_alpha, + m_pCacheScanline, m_pIccTransform); + break; + case 1 + 2: + _CompositeRow_Rgb2Rgb_Blend_NoClip(dest_scan, src_scan, width, + m_BlendType, dest_Bpp, src_Bpp); + break; + case 1 + 2 + 64: + _CompositeRow_Rgb2Rgb_Blend_NoClip_Transform( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, + m_pCacheScanline, m_pIccTransform); + break; + case 1 + 2 + 8: + _CompositeRow_Rgb2Rgb_Blend_Clip(dest_scan, src_scan, width, + m_BlendType, dest_Bpp, src_Bpp, + clip_scan); + break; + case 1 + 2 + 8 + 64: + _CompositeRow_Rgb2Rgb_Blend_Clip_Transform( + dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, + clip_scan, m_pCacheScanline, m_pIccTransform); + break; + case 1 + 2 + 4: + _CompositeRow_Rgb2Rgb_NoBlend_NoClip(dest_scan, src_scan, width, + dest_Bpp, src_Bpp); + break; + case 1 + 2 + 4 + 64: + _CompositeRow_Rgb2Rgb_NoBlend_NoClip_Transform( + dest_scan, src_scan, width, dest_Bpp, src_Bpp, m_pCacheScanline, + m_pIccTransform); + break; + case 1 + 2 + 4 + 8: + _CompositeRow_Rgb2Rgb_NoBlend_Clip(dest_scan, src_scan, width, dest_Bpp, + src_Bpp, clip_scan); + break; + case 1 + 2 + 4 + 8 + 64: + _CompositeRow_Rgb2Rgb_NoBlend_Clip_Transform( + dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan, + m_pCacheScanline, m_pIccTransform); + break; + } + } +} +void CFX_ScanlineCompositor::CompositePalBitmapLine( + uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + int width, + const uint8_t* clip_scan, + const uint8_t* src_extra_alpha, + uint8_t* dst_extra_alpha) { + if (m_bRgbByteOrder) { + if (m_SrcFormat == FXDIB_1bppRgb) { + if (m_DestFormat == FXDIB_8bppRgb) { + return; + } + if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder( + dest_scan, src_scan, src_left, width, m_pSrcPalette, clip_scan); + } else { + _CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder( + dest_scan, src_scan, src_left, m_pSrcPalette, width, + (m_DestFormat & 0xff) >> 3, clip_scan); + } + } else { + if (m_DestFormat == FXDIB_8bppRgb) { + return; + } + if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder( + dest_scan, src_scan, width, m_pSrcPalette, clip_scan); + } else { + _CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder( + dest_scan, src_scan, m_pSrcPalette, width, + (m_DestFormat & 0xff) >> 3, clip_scan); + } + } + return; + } + if (m_DestFormat == FXDIB_8bppMask) { + _CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan); + return; + } + if ((m_DestFormat & 0xff) == 8) { + if (m_Transparency & 8) { + if (m_DestFormat & 0x0200) { + _CompositeRow_1bppPal2Graya(dest_scan, src_scan, src_left, + (const uint8_t*)m_pSrcPalette, width, + m_BlendType, clip_scan, dst_extra_alpha); + } else { + _CompositeRow_1bppPal2Gray(dest_scan, src_scan, src_left, + (const uint8_t*)m_pSrcPalette, width, + m_BlendType, clip_scan); + } + } else { + if (m_DestFormat & 0x0200) + _CompositeRow_8bppPal2Graya( + dest_scan, src_scan, (const uint8_t*)m_pSrcPalette, width, + m_BlendType, clip_scan, dst_extra_alpha, src_extra_alpha); + else + _CompositeRow_8bppPal2Gray(dest_scan, src_scan, + (const uint8_t*)m_pSrcPalette, width, + m_BlendType, clip_scan, src_extra_alpha); + } + } else { + switch (m_Transparency) { + case 1 + 2: + _CompositeRow_8bppRgb2Argb_NoBlend(dest_scan, src_scan, width, + m_pSrcPalette, clip_scan, + src_extra_alpha); + break; + case 1 + 2 + 8: + _CompositeRow_1bppRgb2Argb_NoBlend(dest_scan, src_scan, src_left, width, + m_pSrcPalette, clip_scan); + break; + case 0: + _CompositeRow_8bppRgb2Rgb_NoBlend(dest_scan, src_scan, m_pSrcPalette, + width, (m_DestFormat & 0xff) >> 3, + clip_scan, src_extra_alpha); + break; + case 0 + 8: + _CompositeRow_1bppRgb2Rgb_NoBlend( + dest_scan, src_scan, src_left, m_pSrcPalette, width, + (m_DestFormat & 0xff) >> 3, clip_scan); + break; + case 0 + 2: + _CompositeRow_8bppRgb2Rgb_NoBlend(dest_scan, src_scan, m_pSrcPalette, + width, (m_DestFormat & 0xff) >> 3, + clip_scan, src_extra_alpha); + break; + case 0 + 2 + 8: + _CompositeRow_1bppRgb2Rgba_NoBlend(dest_scan, src_scan, src_left, width, + m_pSrcPalette, clip_scan, + dst_extra_alpha); + break; + break; + } + } +} +void CFX_ScanlineCompositor::CompositeByteMaskLine(uint8_t* dest_scan, + const uint8_t* src_scan, + int width, + const uint8_t* clip_scan, + uint8_t* dst_extra_alpha) { + if (m_DestFormat == FXDIB_8bppMask) { + _CompositeRow_ByteMask2Mask(dest_scan, src_scan, m_MaskAlpha, width, + clip_scan); + } else if ((m_DestFormat & 0xff) == 8) { + if (m_DestFormat & 0x0200) { + _CompositeRow_ByteMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + width, clip_scan, dst_extra_alpha); + } else { + _CompositeRow_ByteMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + width, clip_scan); + } + } else if (m_bRgbByteOrder) { + if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_ByteMask2Argb_RgbByteOrder( + dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, + width, m_BlendType, clip_scan); + } else { + _CompositeRow_ByteMask2Rgb_RgbByteOrder( + dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, + width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan); + } + return; + } else if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_ByteMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + m_MaskGreen, m_MaskBlue, width, m_BlendType, + clip_scan); + } else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32) { + _CompositeRow_ByteMask2Rgb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + m_MaskGreen, m_MaskBlue, width, m_BlendType, + (m_DestFormat & 0xff) >> 3, clip_scan); + } else if (m_DestFormat == FXDIB_Rgba) { + _CompositeRow_ByteMask2Rgba(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + m_MaskGreen, m_MaskBlue, width, m_BlendType, + clip_scan, dst_extra_alpha); + } +} +void CFX_ScanlineCompositor::CompositeBitMaskLine(uint8_t* dest_scan, + const uint8_t* src_scan, + int src_left, + int width, + const uint8_t* clip_scan, + uint8_t* dst_extra_alpha) { + if (m_DestFormat == FXDIB_8bppMask) { + _CompositeRow_BitMask2Mask(dest_scan, src_scan, m_MaskAlpha, src_left, + width, clip_scan); + } else if ((m_DestFormat & 0xff) == 8) { + if (m_DestFormat & 0x0200) { + _CompositeRow_BitMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + src_left, width, clip_scan, dst_extra_alpha); + } else { + _CompositeRow_BitMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + src_left, width, clip_scan); + } + } else if (m_bRgbByteOrder) { + if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_BitMask2Argb_RgbByteOrder( + dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, + src_left, width, m_BlendType, clip_scan); + } else { + _CompositeRow_BitMask2Rgb_RgbByteOrder( + dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, + src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan); + } + return; + } else if (m_DestFormat == FXDIB_Argb) { + _CompositeRow_BitMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, + m_MaskGreen, m_MaskBlue, src_left, width, + m_BlendType, clip_scan); + } else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32) { + _CompositeRow_BitMask2Rgb( + dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, + src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan); + } +} + +FX_BOOL CFX_DIBitmap::CompositeBitmap(int dest_left, + int dest_top, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + int blend_type, + const CFX_ClipRgn* pClipRgn, + FX_BOOL bRgbByteOrder, + void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + ASSERT(!pSrcBitmap->IsAlphaMask()); + ASSERT(m_bpp >= 8); + if (pSrcBitmap->IsAlphaMask() || m_bpp < 8) { + return FALSE; + } + GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(), + pSrcBitmap->GetHeight(), src_left, src_top, pClipRgn); + if (width == 0 || height == 0) { + return TRUE; + } + const CFX_DIBitmap* pClipMask = NULL; + FX_RECT clip_box; + if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) { + ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF); + pClipMask = pClipRgn->GetMask(); + clip_box = pClipRgn->GetBox(); + } + CFX_ScanlineCompositor compositor; + if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(), width, + pSrcBitmap->GetPalette(), 0, blend_type, + pClipMask != NULL, bRgbByteOrder, 0, pIccTransform)) { + return FALSE; + } + int dest_Bpp = m_bpp / 8; + int src_Bpp = pSrcBitmap->GetBPP() / 8; + FX_BOOL bRgb = src_Bpp > 1 && !pSrcBitmap->IsCmykImage(); + CFX_DIBitmap* pSrcAlphaMask = pSrcBitmap->m_pAlphaMask; + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = + m_pBuffer + (dest_top + row) * m_Pitch + dest_left * dest_Bpp; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * src_Bpp; + const uint8_t* src_scan_extra_alpha = + pSrcAlphaMask ? pSrcAlphaMask->GetScanline(src_top + row) + src_left + : NULL; + uint8_t* dst_scan_extra_alpha = + m_pAlphaMask + ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left + : NULL; + const uint8_t* clip_scan = NULL; + if (pClipMask) { + clip_scan = pClipMask->m_pBuffer + + (dest_top + row - clip_box.top) * pClipMask->m_Pitch + + (dest_left - clip_box.left); + } + if (bRgb) { + compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan, + src_scan_extra_alpha, + dst_scan_extra_alpha); + } else { + compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width, + clip_scan, src_scan_extra_alpha, + dst_scan_extra_alpha); + } + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::CompositeMask(int dest_left, + int dest_top, + int width, + int height, + const CFX_DIBSource* pMask, + FX_DWORD color, + int src_left, + int src_top, + int blend_type, + const CFX_ClipRgn* pClipRgn, + FX_BOOL bRgbByteOrder, + int alpha_flag, + void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + ASSERT(pMask->IsAlphaMask()); + ASSERT(m_bpp >= 8); + if (!pMask->IsAlphaMask() || m_bpp < 8) { + return FALSE; + } + GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(), + pMask->GetHeight(), src_left, src_top, pClipRgn); + if (width == 0 || height == 0) { + return TRUE; + } + int src_alpha = + (uint8_t)(alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color); + if (src_alpha == 0) { + return TRUE; + } + const CFX_DIBitmap* pClipMask = NULL; + FX_RECT clip_box; + if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) { + ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF); + pClipMask = pClipRgn->GetMask(); + clip_box = pClipRgn->GetBox(); + } + int src_bpp = pMask->GetBPP(); + int Bpp = GetBPP() / 8; + CFX_ScanlineCompositor compositor; + if (!compositor.Init(GetFormat(), pMask->GetFormat(), width, NULL, color, + blend_type, pClipMask != NULL, bRgbByteOrder, alpha_flag, + pIccTransform)) { + return FALSE; + } + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = + m_pBuffer + (dest_top + row) * m_Pitch + dest_left * Bpp; + const uint8_t* src_scan = pMask->GetScanline(src_top + row); + uint8_t* dst_scan_extra_alpha = + m_pAlphaMask + ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left + : NULL; + const uint8_t* clip_scan = NULL; + if (pClipMask) { + clip_scan = pClipMask->m_pBuffer + + (dest_top + row - clip_box.top) * pClipMask->m_Pitch + + (dest_left - clip_box.left); + } + if (src_bpp == 1) { + compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width, + clip_scan, dst_scan_extra_alpha); + } else { + compositor.CompositeByteMaskLine(dest_scan, src_scan + src_left, width, + clip_scan, dst_scan_extra_alpha); + } + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::CompositeRect(int left, + int top, + int width, + int height, + FX_DWORD color, + int alpha_flag, + void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + int src_alpha = (alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color); + if (src_alpha == 0) { + return TRUE; + } + FX_RECT rect(left, top, left + width, top + height); + rect.Intersect(0, 0, m_Width, m_Height); + if (rect.IsEmpty()) { + return TRUE; + } + width = rect.Width(); + FX_DWORD dst_color; + if (alpha_flag >> 8) { + dst_color = FXCMYK_TODIB(color); + } else { + dst_color = FXARGB_TODIB(color); + } + uint8_t* color_p = (uint8_t*)&dst_color; + if (m_bpp == 8) { + uint8_t gray = 255; + if (!IsAlphaMask()) { + if (pIccTransform && CFX_GEModule::Get()->GetCodecModule() && + CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, &gray, color_p, 1); + } else { + if (alpha_flag >> 8) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(color_p[0], color_p[1], color_p[2], color_p[3], r, + g, b); + gray = FXRGB2GRAY(r, g, b); + } else { + gray = (uint8_t)FXRGB2GRAY((int)color_p[2], color_p[1], color_p[0]); + } + } + if (IsCmykImage()) { + gray = ~gray; + } + } + for (int row = rect.top; row < rect.bottom; row++) { + uint8_t* dest_scan = m_pBuffer + row * m_Pitch + rect.left; + if (src_alpha == 255) { + FXSYS_memset(dest_scan, gray, width); + } else { + for (int col = 0; col < width; col++) { + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha); + dest_scan++; + } + } + } + return TRUE; + } + if (m_bpp == 1) { + ASSERT(!IsCmykImage() && (uint8_t)(alpha_flag >> 8) == 0); + int left_shift = rect.left % 8; + int right_shift = rect.right % 8; + int width = rect.right / 8 - rect.left / 8; + int index = 0; + if (m_pPalette) { + for (int i = 0; i < 2; i++) { + if (m_pPalette[i] == color) { + index = i; + } + } + } else { + index = ((uint8_t)color == 0xff) ? 1 : 0; + } + for (int row = rect.top; row < rect.bottom; row++) { + uint8_t* dest_scan_top = (uint8_t*)GetScanline(row) + rect.left / 8; + uint8_t* dest_scan_top_r = (uint8_t*)GetScanline(row) + rect.right / 8; + uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift)); + uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift); + if (width) { + FXSYS_memset(dest_scan_top + 1, index ? 255 : 0, width - 1); + if (!index) { + *dest_scan_top &= left_flag; + *dest_scan_top_r &= right_flag; + } else { + *dest_scan_top |= ~left_flag; + *dest_scan_top_r |= ~right_flag; + } + } else { + if (!index) { + *dest_scan_top &= left_flag | right_flag; + } else { + *dest_scan_top |= ~(left_flag | right_flag); + } + } + } + return TRUE; + } + ASSERT(m_bpp >= 24); + if (m_bpp < 24) { + return FALSE; + } + if (pIccTransform && CFX_GEModule::Get()->GetCodecModule()) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, color_p, color_p, 1); + } else { + if (alpha_flag >> 8 && !IsCmykImage()) { + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), + FXSYS_GetYValue(color), FXSYS_GetKValue(color), + color_p[2], color_p[1], color_p[0]); + } else if (!(alpha_flag >> 8) && IsCmykImage()) { + return FALSE; + } + } + if (!IsCmykImage()) { + color_p[3] = (uint8_t)src_alpha; + } + int Bpp = m_bpp / 8; + FX_BOOL bAlpha = HasAlpha(); + bool bArgb = GetFormat() == FXDIB_Argb; + if (src_alpha == 255) { + for (int row = rect.top; row < rect.bottom; row++) { + uint8_t* dest_scan = m_pBuffer + row * m_Pitch + rect.left * Bpp; + uint8_t* dest_scan_alpha = + m_pAlphaMask ? (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left + : NULL; + if (dest_scan_alpha) { + FXSYS_memset(dest_scan_alpha, 0xff, width); + } + if (Bpp == 4) { + FX_DWORD* scan = (FX_DWORD*)dest_scan; + for (int col = 0; col < width; col++) { + *scan++ = dst_color; + } + } else { + for (int col = 0; col < width; col++) { + *dest_scan++ = color_p[0]; + *dest_scan++ = color_p[1]; + *dest_scan++ = color_p[2]; + } + } + } + return TRUE; + } + for (int row = rect.top; row < rect.bottom; row++) { + uint8_t* dest_scan = m_pBuffer + row * m_Pitch + rect.left * Bpp; + if (bAlpha) { + if (bArgb) { + for (int col = 0; col < width; col++) { + uint8_t back_alpha = dest_scan[3]; + if (back_alpha == 0) { + FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, color_p[2], + color_p[1], color_p[0])); + dest_scan += 4; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + int alpha_ratio = src_alpha * 255 / dest_alpha; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio); + dest_scan++; + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio); + dest_scan++; + *dest_scan++ = dest_alpha; + } + } else { + uint8_t* dest_scan_alpha = + (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left; + for (int col = 0; col < width; col++) { + uint8_t back_alpha = *dest_scan_alpha; + if (back_alpha == 0) { + *dest_scan_alpha++ = src_alpha; + FXSYS_memcpy(dest_scan, color_p, Bpp); + dest_scan += Bpp; + continue; + } + uint8_t dest_alpha = + back_alpha + src_alpha - back_alpha * src_alpha / 255; + *dest_scan_alpha++ = dest_alpha; + int alpha_ratio = src_alpha * 255 / dest_alpha; + for (int comps = 0; comps < Bpp; comps++) { + *dest_scan = + FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], alpha_ratio); + dest_scan++; + } + } + } + } else { + for (int col = 0; col < width; col++) { + for (int comps = 0; comps < Bpp; comps++) { + if (comps == 3) { + *dest_scan++ = 255; + continue; + } + *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha); + dest_scan++; + } + } + } + } + return TRUE; +} +CFX_BitmapComposer::CFX_BitmapComposer() { + m_pScanlineV = NULL; + m_pScanlineAlphaV = NULL; + m_pClipScanV = NULL; + m_pAddClipScan = NULL; + m_bRgbByteOrder = FALSE; + m_BlendType = FXDIB_BLEND_NORMAL; +} +CFX_BitmapComposer::~CFX_BitmapComposer() { + FX_Free(m_pScanlineV); + FX_Free(m_pScanlineAlphaV); + FX_Free(m_pClipScanV); + FX_Free(m_pAddClipScan); +} +void CFX_BitmapComposer::Compose(CFX_DIBitmap* pDest, + const CFX_ClipRgn* pClipRgn, + int bitmap_alpha, + FX_DWORD mask_color, + FX_RECT& dest_rect, + FX_BOOL bVertical, + FX_BOOL bFlipX, + FX_BOOL bFlipY, + FX_BOOL bRgbByteOrder, + int alpha_flag, + void* pIccTransform, + int blend_type) { + m_pBitmap = pDest; + m_pClipRgn = pClipRgn; + m_DestLeft = dest_rect.left; + m_DestTop = dest_rect.top; + m_DestWidth = dest_rect.Width(); + m_DestHeight = dest_rect.Height(); + m_BitmapAlpha = bitmap_alpha; + m_MaskColor = mask_color; + m_pClipMask = NULL; + if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) { + m_pClipMask = pClipRgn->GetMask(); + } + m_bVertical = bVertical; + m_bFlipX = bFlipX; + m_bFlipY = bFlipY; + m_AlphaFlag = alpha_flag; + m_pIccTransform = pIccTransform; + m_bRgbByteOrder = bRgbByteOrder; + m_BlendType = blend_type; +} +FX_BOOL CFX_BitmapComposer::SetInfo(int width, + int height, + FXDIB_Format src_format, + FX_DWORD* pSrcPalette) { + m_SrcFormat = src_format; + if (!m_Compositor.Init(m_pBitmap->GetFormat(), src_format, width, pSrcPalette, + m_MaskColor, FXDIB_BLEND_NORMAL, + m_pClipMask != NULL || (m_BitmapAlpha < 255), + m_bRgbByteOrder, m_AlphaFlag, m_pIccTransform)) { + return FALSE; + } + if (m_bVertical) { + m_pScanlineV = FX_Alloc(uint8_t, m_pBitmap->GetBPP() / 8 * width + 4); + m_pClipScanV = FX_Alloc(uint8_t, m_pBitmap->GetHeight()); + if (m_pBitmap->m_pAlphaMask) { + m_pScanlineAlphaV = FX_Alloc(uint8_t, width + 4); + } + } + if (m_BitmapAlpha < 255) { + m_pAddClipScan = FX_Alloc( + uint8_t, m_bVertical ? m_pBitmap->GetHeight() : m_pBitmap->GetWidth()); + } + return TRUE; +} +void CFX_BitmapComposer::DoCompose(uint8_t* dest_scan, + const uint8_t* src_scan, + int dest_width, + const uint8_t* clip_scan, + const uint8_t* src_extra_alpha, + uint8_t* dst_extra_alpha) { + if (m_BitmapAlpha < 255) { + if (clip_scan) { + for (int i = 0; i < dest_width; i++) { + m_pAddClipScan[i] = clip_scan[i] * m_BitmapAlpha / 255; + } + } else { + FXSYS_memset(m_pAddClipScan, m_BitmapAlpha, dest_width); + } + clip_scan = m_pAddClipScan; + } + if (m_SrcFormat == FXDIB_8bppMask) { + m_Compositor.CompositeByteMaskLine(dest_scan, src_scan, dest_width, + clip_scan, dst_extra_alpha); + } else if ((m_SrcFormat & 0xff) == 8) { + m_Compositor.CompositePalBitmapLine(dest_scan, src_scan, 0, dest_width, + clip_scan, src_extra_alpha, + dst_extra_alpha); + } else { + m_Compositor.CompositeRgbBitmapLine(dest_scan, src_scan, dest_width, + clip_scan, src_extra_alpha, + dst_extra_alpha); + } +} +void CFX_BitmapComposer::ComposeScanline(int line, + const uint8_t* scanline, + const uint8_t* scan_extra_alpha) { + if (m_bVertical) { + ComposeScanlineV(line, scanline, scan_extra_alpha); + return; + } + const uint8_t* clip_scan = NULL; + if (m_pClipMask) + clip_scan = m_pClipMask->GetBuffer() + + (m_DestTop + line - m_pClipRgn->GetBox().top) * + m_pClipMask->GetPitch() + + (m_DestLeft - m_pClipRgn->GetBox().left); + uint8_t* dest_scan = (uint8_t*)m_pBitmap->GetScanline(line + m_DestTop) + + m_DestLeft * m_pBitmap->GetBPP() / 8; + uint8_t* dest_alpha_scan = + m_pBitmap->m_pAlphaMask + ? (uint8_t*)m_pBitmap->m_pAlphaMask->GetScanline(line + m_DestTop) + + m_DestLeft + : NULL; + DoCompose(dest_scan, scanline, m_DestWidth, clip_scan, scan_extra_alpha, + dest_alpha_scan); +} +void CFX_BitmapComposer::ComposeScanlineV(int line, + const uint8_t* scanline, + const uint8_t* scan_extra_alpha) { + int i; + int Bpp = m_pBitmap->GetBPP() / 8; + int dest_pitch = m_pBitmap->GetPitch(); + int dest_alpha_pitch = + m_pBitmap->m_pAlphaMask ? m_pBitmap->m_pAlphaMask->GetPitch() : 0; + int dest_x = m_DestLeft + (m_bFlipX ? (m_DestWidth - line - 1) : line); + uint8_t* dest_buf = + m_pBitmap->GetBuffer() + dest_x * Bpp + m_DestTop * dest_pitch; + uint8_t* dest_alpha_buf = m_pBitmap->m_pAlphaMask + ? m_pBitmap->m_pAlphaMask->GetBuffer() + + dest_x + m_DestTop * dest_alpha_pitch + : NULL; + if (m_bFlipY) { + dest_buf += dest_pitch * (m_DestHeight - 1); + dest_alpha_buf += dest_alpha_pitch * (m_DestHeight - 1); + } + int y_step = dest_pitch; + int y_alpha_step = dest_alpha_pitch; + if (m_bFlipY) { + y_step = -y_step; + y_alpha_step = -y_alpha_step; + } + uint8_t* src_scan = m_pScanlineV; + uint8_t* dest_scan = dest_buf; + for (i = 0; i < m_DestHeight; i++) { + for (int j = 0; j < Bpp; j++) { + *src_scan++ = dest_scan[j]; + } + dest_scan += y_step; + } + uint8_t* src_alpha_scan = m_pScanlineAlphaV; + uint8_t* dest_alpha_scan = dest_alpha_buf; + if (dest_alpha_scan) { + for (i = 0; i < m_DestHeight; i++) { + *src_alpha_scan++ = *dest_alpha_scan; + dest_alpha_scan += y_alpha_step; + } + } + uint8_t* clip_scan = NULL; + if (m_pClipMask) { + clip_scan = m_pClipScanV; + int clip_pitch = m_pClipMask->GetPitch(); + const uint8_t* src_clip = + m_pClipMask->GetBuffer() + + (m_DestTop - m_pClipRgn->GetBox().top) * clip_pitch + + (dest_x - m_pClipRgn->GetBox().left); + if (m_bFlipY) { + src_clip += clip_pitch * (m_DestHeight - 1); + clip_pitch = -clip_pitch; + } + for (i = 0; i < m_DestHeight; i++) { + clip_scan[i] = *src_clip; + src_clip += clip_pitch; + } + } + DoCompose(m_pScanlineV, scanline, m_DestHeight, clip_scan, scan_extra_alpha, + m_pScanlineAlphaV); + src_scan = m_pScanlineV; + dest_scan = dest_buf; + for (i = 0; i < m_DestHeight; i++) { + for (int j = 0; j < Bpp; j++) { + dest_scan[j] = *src_scan++; + } + dest_scan += y_step; + } + src_alpha_scan = m_pScanlineAlphaV; + dest_alpha_scan = dest_alpha_buf; + if (dest_alpha_scan) { + for (i = 0; i < m_DestHeight; i++) { + *dest_alpha_scan = *src_alpha_scan++; + dest_alpha_scan += y_alpha_step; + } + } +} diff --git a/core/fxge/dib/fx_dib_convert.cpp b/core/fxge/dib/fx_dib_convert.cpp new file mode 100644 index 0000000000..a1c18ae121 --- /dev/null +++ b/core/fxge/dib/fx_dib_convert.cpp @@ -0,0 +1,1227 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxcodec/fx_codec.h" +#include "core/include/fxge/fx_dib.h" +#include "core/include/fxge/fx_ge.h" + +const FX_DWORD g_dwWinPalette[256] = { + 0xff000000, 0xff800000, 0xff008000, 0xff808000, 0xff000080, 0xff800080, + 0xff008080, 0xff808080, 0xffC0DCC0, 0xffA6CAF0, 0xff2A3FAA, 0xff2A3FFF, + 0xff2A5F00, 0xff2A5F55, 0xff2A5FAA, 0xff2A5FFF, 0xff2A7F00, 0xff2A7F55, + 0xff2A7FAA, 0xff2A7FFF, 0xff2A9F00, 0xff2A9F55, 0xff2A9FAA, 0xff2A9FFF, + 0xff2ABF00, 0xff2ABF55, 0xff2ABFAA, 0xff2ABFFF, 0xff2ADF00, 0xff2ADF55, + 0xff2ADFAA, 0xff2ADFFF, 0xff2AFF00, 0xff2AFF55, 0xff2AFFAA, 0xff2AFFFF, + 0xff550000, 0xff550055, 0xff5500AA, 0xff5500FF, 0xff551F00, 0xff551F55, + 0xff551FAA, 0xff551FFF, 0xff553F00, 0xff553F55, 0xff553FAA, 0xff553FFF, + 0xff555F00, 0xff555F55, 0xff555FAA, 0xff555FFF, 0xff557F00, 0xff557F55, + 0xff557FAA, 0xff557FFF, 0xff559F00, 0xff559F55, 0xff559FAA, 0xff559FFF, + 0xff55BF00, 0xff55BF55, 0xff55BFAA, 0xff55BFFF, 0xff55DF00, 0xff55DF55, + 0xff55DFAA, 0xff55DFFF, 0xff55FF00, 0xff55FF55, 0xff55FFAA, 0xff55FFFF, + 0xff7F0000, 0xff7F0055, 0xff7F00AA, 0xff7F00FF, 0xff7F1F00, 0xff7F1F55, + 0xff7F1FAA, 0xff7F1FFF, 0xff7F3F00, 0xff7F3F55, 0xff7F3FAA, 0xff7F3FFF, + 0xff7F5F00, 0xff7F5F55, 0xff7F5FAA, 0xff7F5FFF, 0xff7F7F00, 0xff7F7F55, + 0xff7F7FAA, 0xff7F7FFF, 0xff7F9F00, 0xff7F9F55, 0xff7F9FAA, 0xff7F9FFF, + 0xff7FBF00, 0xff7FBF55, 0xff7FBFAA, 0xff7FBFFF, 0xff7FDF00, 0xff7FDF55, + 0xff7FDFAA, 0xff7FDFFF, 0xff00FF7F, 0xff7FFF55, 0xff7FFFAA, 0xff7FFFFF, + 0xffAA0000, 0xffAA0055, 0xffAA00AA, 0xffAA00FF, 0xffAA1F00, 0xffAA1F55, + 0xffAA1FAA, 0xffAA1FFF, 0xffAA3F00, 0xffAA3F55, 0xffAA3FAA, 0xffAA3FFF, + 0xffAA5F00, 0xffAA5F55, 0xffAA5FAA, 0xffAA5FFF, 0xffAA7F00, 0xffAA7F55, + 0xffAA7FAA, 0xffAA7FFF, 0xffAA9F00, 0xffAA9F55, 0xffAA9FAA, 0xffAA9FFF, + 0xffAABF00, 0xffAABF55, 0xffAABFAA, 0xffAABFFF, 0xffAADF00, 0xffAADF55, + 0xffAADFAA, 0xffAADFFF, 0xffAAFF00, 0xffAAFF55, 0xffAAFFAA, 0xffAAFFFF, + 0xffD40000, 0xffD40055, 0xffD400AA, 0xffD400FF, 0xffD41F00, 0xffD41F55, + 0xffD41FAA, 0xffD41FFF, 0xffD43F00, 0xffD43F55, 0xffD43FAA, 0xffD43FFF, + 0xffD45F00, 0xffD45F55, 0xffD45FAA, 0xffD45FFF, 0xffD47F00, 0xffD47F55, + 0xffD47FAA, 0xffD4F7FF, 0xffD49F00, 0xffD49F55, 0xffD49FAA, 0xffD49FFF, + 0xffD4BF00, 0xffD4BF55, 0xffD4BFAA, 0xffD4BFFF, 0xffD4DF00, 0xffD4DF55, + 0xffD4DFAA, 0xffD4DFFF, 0xffD4FF00, 0xffD4FF55, 0xffD4FFAA, 0xffD4FFFF, + 0xffFF0055, 0xffFF00AA, 0xffFF1F00, 0xffFF1F55, 0xffFF1FAA, 0xffFF1FFF, + 0xffFF3F00, 0xffFF3F55, 0xffFF3FAA, 0xffFF3FFF, 0xffFF5F00, 0xffFF5F55, + 0xffFF5FAA, 0xffFF5FFF, 0xffFF7F00, 0xffFF7F55, 0xffFF7FAA, 0xffFF7FFF, + 0xffFF9F00, 0xffFF9F55, 0xffFF9FAA, 0xffFF9FFF, 0xffFFBF00, 0xffFFBF55, + 0xffFFBFAA, 0xffFFBFFF, 0xffFFDF00, 0xffFFDF55, 0xffFFDFAA, 0xffFFDFFF, + 0xffFFFF55, 0xffFFFFAA, 0xffCCCCFF, 0xffFFCCFF, 0xff33FFFF, 0xff66FFFF, + 0xff99FFFF, 0xffCCFFFF, 0xff007F00, 0xff007F55, 0xff007FAA, 0xff007FFF, + 0xff009F00, 0xff009F55, 0xff009FAA, 0xff009FFF, 0xff00BF00, 0xff00BF55, + 0xff00BFAA, 0xff00BFFF, 0xff00DF00, 0xff00DF55, 0xff00DFAA, 0xff00DFFF, + 0xff00FF55, 0xff00FFAA, 0xff2A0000, 0xff2A0055, 0xff2A00AA, 0xff2A00FF, + 0xff2A1F00, 0xff2A1F55, 0xff2A1FAA, 0xff2A1FFF, 0xff2A3F00, 0xff2A3F55, + 0xffFFFBF0, 0xffA0A0A4, 0xff808080, 0xffFF0000, 0xff00FF00, 0xffFF0000, + 0xff0000FF, 0xffFF00FF, 0xff00FFFF, 0xffFFFFFF}; +const FX_DWORD g_dwMacPalette[256] = { + 0xffFFFFFF, 0xffFFFFCC, 0xffFFFF99, 0xffFFFF66, 0xffFFFF33, 0xffFFFF00, + 0xffFFCCFF, 0xffFFCCCC, 0xffFFCC99, 0xffFFCC66, 0xffFFCC33, 0xffFFCC00, + 0xffFF99FF, 0xffFF99CC, 0xffFF9999, 0xffFF9966, 0xffFF9933, 0xffFF9900, + 0xffFF66FF, 0xffFF66CC, 0xffFF6699, 0xffFF6666, 0xffFF6633, 0xffFF6600, + 0xffFF33FF, 0xffFF33CC, 0xffFF3399, 0xffFF3366, 0xffFF3333, 0xffFF3300, + 0xffFF00FF, 0xffFF00CC, 0xffFF0099, 0xffFF0066, 0xffFF0033, 0xffFF0000, + 0xffCCFFFF, 0xffCCFFCC, 0xffCCFF99, 0xffCCFF66, 0xffCCFF33, 0xffCCFF00, + 0xffCCCCFF, 0xffCCCCCC, 0xffCCCC99, 0xffCCCC66, 0xffCCCC33, 0xffCCCC00, + 0xffCC99FF, 0xffCC99CC, 0xffCC9999, 0xffCC9966, 0xffCC9933, 0xffCC9900, + 0xffCC66FF, 0xffCC66CC, 0xffCC6699, 0xffCC6666, 0xffCC6633, 0xffCC6600, + 0xffCC33FF, 0xffCC33CC, 0xffCC3399, 0xffCC3366, 0xffCC3333, 0xffCC3300, + 0xffCC00FF, 0xffCC00CC, 0xffCC0099, 0xffCC0066, 0xffCC0033, 0xffCC0000, + 0xff99FFFF, 0xff99FFCC, 0xff99FF99, 0xff99FF66, 0xff99FF33, 0xff99FF00, + 0xff99CCFF, 0xff99CCCC, 0xff99CC99, 0xff99CC66, 0xff99CC33, 0xff99CC00, + 0xff9999FF, 0xff9999CC, 0xff999999, 0xff999966, 0xff999933, 0xff999900, + 0xff9966FF, 0xff9966CC, 0xff996699, 0xff996666, 0xff996633, 0xff996600, + 0xff9933FF, 0xff9933CC, 0xff993399, 0xff993366, 0xff993333, 0xff993300, + 0xff9900FF, 0xff9900CC, 0xff990099, 0xff990066, 0xff990033, 0xff990000, + 0xff66FFFF, 0xff66FFCC, 0xff66FF99, 0xff66FF66, 0xff66FF33, 0xff66FF00, + 0xff66CCFF, 0xff66CCCC, 0xff66CC99, 0xff66CC66, 0xff66CC33, 0xff66CC00, + 0xff6699FF, 0xff6699CC, 0xff669999, 0xff669966, 0xff669933, 0xff669900, + 0xff6666FF, 0xff6666CC, 0xff666699, 0xff666666, 0xff666633, 0xff666600, + 0xff6633FF, 0xff6633CC, 0xff663399, 0xff663366, 0xff663333, 0xff663300, + 0xff6600FF, 0xff6600CC, 0xff660099, 0xff660066, 0xff660033, 0xff660000, + 0xff33FFFF, 0xff33FFCC, 0xff33FF99, 0xff33FF66, 0xff33FF33, 0xff33FF00, + 0xff33CCFF, 0xff33CCCC, 0xff33CC99, 0xff33CC66, 0xff33CC33, 0xff33CC00, + 0xff3399FF, 0xff3399CC, 0xff339999, 0xff339966, 0xff339933, 0xff339900, + 0xff3366FF, 0xff3366CC, 0xff336699, 0xff336666, 0xff336633, 0xff336600, + 0xff3333FF, 0xff3333CC, 0xff333399, 0xff333366, 0xff333333, 0xff333300, + 0xff3300FF, 0xff3300CC, 0xff330099, 0xff330066, 0xff330033, 0xff330000, + 0xff00FFFF, 0xff00FFCC, 0xff00FF99, 0xff00FF66, 0xff00FF33, 0xff00FF00, + 0xff00CCFF, 0xff00CCCC, 0xff00CC99, 0xff00CC66, 0xff00CC33, 0xff00CC00, + 0xff0099FF, 0xff0099CC, 0xff009999, 0xff009966, 0xff009933, 0xff009900, + 0xff0066FF, 0xff0066CC, 0xff006699, 0xff006666, 0xff006633, 0xff006600, + 0xff0033FF, 0xff0033CC, 0xff003399, 0xff003366, 0xff003333, 0xff003300, + 0xff0000FF, 0xff0000CC, 0xff000099, 0xff000066, 0xff000033, 0xffEE0000, + 0xffDD0000, 0xffBB0000, 0xffAA0000, 0xff880000, 0xff770000, 0xff550000, + 0xff440000, 0xff220000, 0xff110000, 0xff00EE00, 0xff00DD00, 0xff00BB00, + 0xff00AA00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, + 0xff001100, 0xff0000EE, 0xff0000DD, 0xff0000BB, 0xff0000AA, 0xff000088, + 0xff000077, 0xff000055, 0xff000044, 0xff000022, 0xff000011, 0xffEEEEEE, + 0xffDDDDDD, 0xffBBBBBB, 0xffAAAAAA, 0xff888888, 0xff777777, 0xff555555, + 0xff444444, 0xff222222, 0xff111111, 0xff000000}; +class CFX_Palette { + public: + CFX_Palette(); + ~CFX_Palette(); + + public: + FX_BOOL BuildPalette(const CFX_DIBSource* pBitmap, int dwPaletteType); + FX_DWORD* GetPalette() const { return m_pPalette; } + + FX_DWORD* GetColorLut() const { return m_cLut; } + FX_DWORD* GetAmountLut() const { return m_aLut; } + int32_t Getlut() const { return m_lut; } + + protected: + FX_DWORD* m_pPalette; + FX_DWORD* m_cLut; + FX_DWORD* m_aLut; + int m_lut; +}; +int _Partition(FX_DWORD* alut, FX_DWORD* clut, int l, int r) { + FX_DWORD p_a = alut[l]; + FX_DWORD p_c = clut[l]; + while (l < r) { + while (l < r && alut[r] >= p_a) { + r--; + } + if (l < r) { + alut[l] = alut[r]; + clut[l++] = clut[r]; + } + while (l < r && alut[l] <= p_a) { + l++; + } + if (l < r) { + alut[r] = alut[l]; + clut[r--] = clut[l]; + } + } + alut[l] = p_a; + clut[l] = p_c; + return l; +} +void _Qsort(FX_DWORD* alut, FX_DWORD* clut, int l, int r) { + if (l < r) { + int pI = _Partition(alut, clut, l, r); + _Qsort(alut, clut, l, pI - 1); + _Qsort(alut, clut, pI + 1, r); + } +} +void _ColorDecode(FX_DWORD pal_v, uint8_t& r, uint8_t& g, uint8_t& b) { + r = (uint8_t)((pal_v & 0xf00) >> 4); + g = (uint8_t)(pal_v & 0x0f0); + b = (uint8_t)((pal_v & 0x00f) << 4); +} +void _Obtain_Pal(FX_DWORD* aLut, + FX_DWORD* cLut, + FX_DWORD* dest_pal, + int pal_type, + FX_DWORD* win_mac_pal, + FX_DWORD lut) { + int row, col; + FX_DWORD lut_1 = lut - 1; + if (pal_type == FXDIB_PALETTE_LOC) { + for (row = 0; row < 256; row++) { + int lut_offset = lut_1 - row; + if (lut_offset < 0) { + lut_offset += 256; + } + FX_DWORD color = cLut[lut_offset]; + uint8_t r, g, b; + _ColorDecode(color, r, g, b); + dest_pal[row] = ((FX_DWORD)r << 16) | ((FX_DWORD)g << 8) | b | 0xff000000; + aLut[lut_offset] = row; + } + } else { + for (row = 0; row < 256; row++) { + int lut_offset = lut_1 - row; + if (lut_offset < 0) { + lut_offset += 256; + } + uint8_t r, g, b; + _ColorDecode(cLut[lut_offset], r, g, b); + int error, min_error = 1000000; + int c_index = 0; + for (col = 0; col < 256; col++) { + FX_DWORD p_color = win_mac_pal[col]; + int d_r = r - (uint8_t)(p_color >> 16); + int d_g = g - (uint8_t)(p_color >> 8); + int d_b = b - (uint8_t)p_color; + error = d_r * d_r + d_g * d_g + d_b * d_b; + if (error < min_error) { + min_error = error; + c_index = col; + } + } + dest_pal[row] = win_mac_pal[c_index]; + aLut[lut_offset] = row; + } + } +} +CFX_Palette::CFX_Palette() { + m_pPalette = NULL; + m_cLut = NULL; + m_aLut = NULL; + m_lut = 0; +} +CFX_Palette::~CFX_Palette() { + FX_Free(m_pPalette); + FX_Free(m_cLut); + FX_Free(m_aLut); + m_lut = 0; +} +FX_BOOL CFX_Palette::BuildPalette(const CFX_DIBSource* pBitmap, int pal_type) { + if (!pBitmap) { + return FALSE; + } + FX_Free(m_pPalette); + m_pPalette = FX_Alloc(FX_DWORD, 256); + int bpp = pBitmap->GetBPP() / 8; + int width = pBitmap->GetWidth(); + int height = pBitmap->GetHeight(); + FX_Free(m_cLut); + m_cLut = NULL; + FX_Free(m_aLut); + m_aLut = NULL; + m_cLut = FX_Alloc(FX_DWORD, 4096); + m_aLut = FX_Alloc(FX_DWORD, 4096); + int row, col; + m_lut = 0; + for (row = 0; row < height; row++) { + uint8_t* scan_line = (uint8_t*)pBitmap->GetScanline(row); + for (col = 0; col < width; col++) { + uint8_t* src_port = scan_line + col * bpp; + FX_DWORD b = src_port[0] & 0xf0; + FX_DWORD g = src_port[1] & 0xf0; + FX_DWORD r = src_port[2] & 0xf0; + FX_DWORD index = (r << 4) + g + (b >> 4); + m_aLut[index]++; + } + } + for (row = 0; row < 4096; row++) { + if (m_aLut[row] != 0) { + m_aLut[m_lut] = m_aLut[row]; + m_cLut[m_lut] = row; + m_lut++; + } + } + _Qsort(m_aLut, m_cLut, 0, m_lut - 1); + FX_DWORD* win_mac_pal = NULL; + if (pal_type == FXDIB_PALETTE_WIN) { + win_mac_pal = (FX_DWORD*)g_dwWinPalette; + } else if (pal_type == FXDIB_PALETTE_MAC) { + win_mac_pal = (FX_DWORD*)g_dwMacPalette; + } + _Obtain_Pal(m_aLut, m_cLut, m_pPalette, pal_type, win_mac_pal, m_lut); + return TRUE; +} +FX_BOOL ConvertBuffer_1bppMask2Gray(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + uint8_t set_gray, reset_gray; + set_gray = 0xff; + reset_gray = 0x00; + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + FXSYS_memset(dest_scan, reset_gray, width); + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = src_left; col < src_left + width; col++) { + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + *dest_scan = set_gray; + } + dest_scan++; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_8bppMask2Gray(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left; + FXSYS_memcpy(dest_scan, src_scan, width); + } + return TRUE; +} +FX_BOOL ConvertBuffer_1bppPlt2Gray(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + FX_DWORD* src_plt = pSrcBitmap->GetPalette(); + uint8_t gray[2]; + if (pIccTransform) { + FX_DWORD plt[2]; + if (pSrcBitmap->IsCmykImage()) { + plt[0] = FXCMYK_TODIB(src_plt[0]); + plt[1] = FXCMYK_TODIB(src_plt[1]); + } else { + uint8_t* bgr_ptr = (uint8_t*)plt; + bgr_ptr[0] = FXARGB_B(src_plt[0]); + bgr_ptr[1] = FXARGB_G(src_plt[0]); + bgr_ptr[2] = FXARGB_R(src_plt[0]); + bgr_ptr[3] = FXARGB_B(src_plt[1]); + bgr_ptr[4] = FXARGB_G(src_plt[1]); + bgr_ptr[5] = FXARGB_R(src_plt[1]); + } + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, gray, (const uint8_t*)plt, 2); + } else { + uint8_t reset_r, reset_g, reset_b, set_r, set_g, set_b; + if (pSrcBitmap->IsCmykImage()) { + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]), + FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]), reset_r, + reset_g, reset_b); + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(src_plt[1]), + FXSYS_GetMValue(src_plt[1]), + FXSYS_GetYValue(src_plt[1]), + FXSYS_GetKValue(src_plt[1]), set_r, set_g, set_b); + } else { + reset_r = FXARGB_R(src_plt[0]); + reset_g = FXARGB_G(src_plt[0]); + reset_b = FXARGB_B(src_plt[0]); + set_r = FXARGB_R(src_plt[1]); + set_g = FXARGB_G(src_plt[1]); + set_b = FXARGB_B(src_plt[1]); + } + gray[0] = FXRGB2GRAY(reset_r, reset_g, reset_b); + gray[1] = FXRGB2GRAY(set_r, set_g, set_b); + } + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + FXSYS_memset(dest_scan, gray[0], width); + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = src_left; col < src_left + width; col++) { + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + *dest_scan = gray[1]; + } + dest_scan++; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_8bppPlt2Gray(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + FX_DWORD* src_plt = pSrcBitmap->GetPalette(); + uint8_t gray[256]; + if (pIccTransform) { + FX_DWORD plt[256]; + if (pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < 256; i++) { + plt[i] = FXCMYK_TODIB(src_plt[i]); + } + } else { + uint8_t* bgr_ptr = (uint8_t*)plt; + for (int i = 0; i < 256; i++) { + *bgr_ptr++ = FXARGB_B(src_plt[i]); + *bgr_ptr++ = FXARGB_G(src_plt[i]); + *bgr_ptr++ = FXARGB_R(src_plt[i]); + } + } + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, gray, (const uint8_t*)plt, + 256); + } else { + if (pSrcBitmap->IsCmykImage()) { + uint8_t r, g, b; + for (int i = 0; i < 256; i++) { + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]), + FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), r, g, b); + gray[i] = FXRGB2GRAY(r, g, b); + } + } else { + for (int i = 0; i < 256; i++) { + gray[i] = FXRGB2GRAY(FXARGB_R(src_plt[i]), FXARGB_G(src_plt[i]), + FXARGB_B(src_plt[i])); + } + } + } + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left; + for (int col = 0; col < width; col++) { + *dest_scan++ = gray[*src_scan++]; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_RgbOrCmyk2Gray(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + int Bpp = pSrcBitmap->GetBPP() / 8; + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + if (Bpp == 3 || pSrcBitmap->IsCmykImage()) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp; + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, + width); + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1); + dest_scan++; + src_scan += 4; + } + } + } + } else { + if (pSrcBitmap->IsCmykImage()) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue((FX_DWORD)src_scan[0]), + FXSYS_GetMValue((FX_DWORD)src_scan[1]), + FXSYS_GetYValue((FX_DWORD)src_scan[2]), + FXSYS_GetKValue((FX_DWORD)src_scan[3]), r, g, b); + *dest_scan++ = FXRGB2GRAY(r, g, b); + src_scan += 4; + } + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp; + for (int col = 0; col < width; col++) { + *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]); + src_scan += Bpp; + } + } + } + } + return TRUE; +} +inline void ConvertBuffer_IndexCopy(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + if (pSrcBitmap->GetBPP() == 1) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + FXSYS_memset(dest_scan, 0, width); + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = src_left; col < src_left + width; col++) { + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + *dest_scan = 1; + } + dest_scan++; + } + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left; + FXSYS_memcpy(dest_scan, src_scan, width); + } + } +} +FX_BOOL ConvertBuffer_Plt2PltRgb8(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + FX_DWORD* dst_plt, + void* pIccTransform) { + ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap, + src_left, src_top); + FX_DWORD* src_plt = pSrcBitmap->GetPalette(); + int plt_size = pSrcBitmap->GetPaletteSize(); + if (pIccTransform) { + FX_DWORD plt[256]; + uint8_t* bgr_ptr = (uint8_t*)plt; + if (pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < plt_size; i++) { + plt[i] = FXCMYK_TODIB(src_plt[i]); + } + } else { + for (int i = 0; i < plt_size; i++) { + *bgr_ptr++ = FXARGB_B(src_plt[i]); + *bgr_ptr++ = FXARGB_G(src_plt[i]); + *bgr_ptr++ = FXARGB_R(src_plt[i]); + } + bgr_ptr = (uint8_t*)plt; + } + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)plt, + (const uint8_t*)plt, plt_size); + for (int i = 0; i < plt_size; i++) { + dst_plt[i] = FXARGB_MAKE(0xff, bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]); + bgr_ptr += 3; + } + } else { + if (pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < plt_size; i++) { + uint8_t r, g, b; + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]), + FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), r, g, b); + dst_plt[i] = FXARGB_MAKE(0xff, r, g, b); + } + } else { + FXSYS_memcpy(dst_plt, src_plt, plt_size * 4); + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_Rgb2PltRgb8_NoTransform(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + FX_DWORD* dst_plt) { + int bpp = pSrcBitmap->GetBPP() / 8; + int row, col; + CFX_Palette palette; + palette.BuildPalette(pSrcBitmap, FXDIB_PALETTE_LOC); + FX_DWORD* cLut = palette.GetColorLut(); + FX_DWORD* aLut = palette.GetAmountLut(); + if (!cLut || !aLut) { + return FALSE; + } + int lut = palette.Getlut(); + FX_DWORD* pPalette = palette.GetPalette(); + if (lut > 256) { + int err, min_err; + int lut_256 = lut - 256; + for (row = 0; row < lut_256; row++) { + min_err = 1000000; + uint8_t r, g, b; + _ColorDecode(cLut[row], r, g, b); + int clrindex = 0; + for (int col = 0; col < 256; col++) { + FX_DWORD p_color = *(pPalette + col); + int d_r = r - (uint8_t)(p_color >> 16); + int d_g = g - (uint8_t)(p_color >> 8); + int d_b = b - (uint8_t)(p_color); + err = d_r * d_r + d_g * d_g + d_b * d_b; + if (err < min_err) { + min_err = err; + clrindex = col; + } + } + aLut[row] = clrindex; + } + } + int32_t lut_1 = lut - 1; + for (row = 0; row < height; row++) { + uint8_t* src_scan = + (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left; + uint8_t* dest_scan = dest_buf + row * dest_pitch; + for (col = 0; col < width; col++) { + uint8_t* src_port = src_scan + col * bpp; + int r = src_port[2] & 0xf0; + int g = src_port[1] & 0xf0; + int b = src_port[0] & 0xf0; + FX_DWORD clrindex = (r << 4) + g + (b >> 4); + for (int i = lut_1; i >= 0; i--) + if (clrindex == cLut[i]) { + *(dest_scan + col) = (uint8_t)(aLut[i]); + break; + } + } + } + FXSYS_memcpy(dst_plt, pPalette, sizeof(FX_DWORD) * 256); + return TRUE; +} +FX_BOOL ConvertBuffer_Rgb2PltRgb8(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + FX_DWORD* dst_plt, + void* pIccTransform) { + FX_BOOL ret = ConvertBuffer_Rgb2PltRgb8_NoTransform( + dest_buf, dest_pitch, width, height, pSrcBitmap, src_left, src_top, + dst_plt); + if (ret && pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + for (int i = 0; i < 256; i++) { + FX_ARGB* plt = dst_plt + i; + FX_ARGB plt_entry = FXARGB_TODIB(*plt); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)&plt_entry, + (const uint8_t*)&plt_entry, 1); + *plt = FXARGB_TODIB(plt_entry); + } + } + return ret; +} +FX_BOOL ConvertBuffer_1bppMask2Rgb(FXDIB_Format dst_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + int comps = (dst_format & 0xff) / 8; + uint8_t set_gray, reset_gray; + set_gray = 0xff; + reset_gray = 0x00; + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = src_left; col < src_left + width; col++) { + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + dest_scan[0] = set_gray; + dest_scan[1] = set_gray; + dest_scan[2] = set_gray; + } else { + dest_scan[0] = reset_gray; + dest_scan[1] = reset_gray; + dest_scan[2] = reset_gray; + } + dest_scan += comps; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_8bppMask2Rgb(FXDIB_Format dst_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top) { + int comps = (dst_format & 0xff) / 8; + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left; + uint8_t src_pixel; + for (int col = 0; col < width; col++) { + src_pixel = *src_scan++; + *dest_scan++ = src_pixel; + *dest_scan++ = src_pixel; + *dest_scan = src_pixel; + dest_scan += comps - 2; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dst_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + int comps = (dst_format & 0xff) / 8; + FX_DWORD* src_plt = pSrcBitmap->GetPalette(); + FX_DWORD plt[2]; + uint8_t* bgr_ptr = (uint8_t*)plt; + if (pSrcBitmap->IsCmykImage()) { + plt[0] = FXCMYK_TODIB(src_plt[0]); + plt[1] = FXCMYK_TODIB(src_plt[1]); + } else { + bgr_ptr[0] = FXARGB_B(src_plt[0]); + bgr_ptr[1] = FXARGB_G(src_plt[0]); + bgr_ptr[2] = FXARGB_R(src_plt[0]); + bgr_ptr[3] = FXARGB_B(src_plt[1]); + bgr_ptr[4] = FXARGB_G(src_plt[1]); + bgr_ptr[5] = FXARGB_R(src_plt[1]); + } + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)plt, + (const uint8_t*)plt, 2); + } else { + if (pSrcBitmap->IsCmykImage()) { + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]), + FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]), bgr_ptr[2], + bgr_ptr[1], bgr_ptr[0]); + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]), + FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]), bgr_ptr[5], + bgr_ptr[4], bgr_ptr[3]); + } + } + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = src_left; col < src_left + width; col++) { + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + *dest_scan++ = bgr_ptr[3]; + *dest_scan++ = bgr_ptr[4]; + *dest_scan = bgr_ptr[5]; + } else { + *dest_scan++ = bgr_ptr[0]; + *dest_scan++ = bgr_ptr[1]; + *dest_scan = bgr_ptr[2]; + } + dest_scan += comps - 2; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dst_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + int comps = (dst_format & 0xff) / 8; + FX_DWORD* src_plt = pSrcBitmap->GetPalette(); + FX_DWORD plt[256]; + uint8_t* bgr_ptr = (uint8_t*)plt; + if (!pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < 256; i++) { + *bgr_ptr++ = FXARGB_B(src_plt[i]); + *bgr_ptr++ = FXARGB_G(src_plt[i]); + *bgr_ptr++ = FXARGB_R(src_plt[i]); + } + bgr_ptr = (uint8_t*)plt; + } + if (pIccTransform) { + if (pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < 256; i++) { + plt[i] = FXCMYK_TODIB(src_plt[i]); + } + } + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, (uint8_t*)plt, + (const uint8_t*)plt, 256); + } else { + if (pSrcBitmap->IsCmykImage()) { + for (int i = 0; i < 256; i++) { + AdobeCMYK_to_sRGB1( + FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]), + FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]), + bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]); + bgr_ptr += 3; + } + bgr_ptr = (uint8_t*)plt; + } + } + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left; + for (int col = 0; col < width; col++) { + uint8_t* src_pixel = bgr_ptr + 3 * (*src_scan++); + *dest_scan++ = *src_pixel++; + *dest_scan++ = *src_pixel++; + *dest_scan = *src_pixel++; + dest_scan += comps - 2; + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_24bppRgb2Rgb24(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 3; + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, width); + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 3; + FXSYS_memcpy(dest_scan, src_scan, width * 3); + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_32bppRgb2Rgb24(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + src_scan++; + } + } + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + pIccModule->TranslateScanline(pIccTransform, dest_scan, dest_scan, width); + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_Rgb2Rgb32(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + int comps = pSrcBitmap->GetBPP() / 8; + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * comps; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1); + dest_scan += 4; + src_scan += comps; + } + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * comps; + for (int col = 0; col < width; col++) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + dest_scan++; + src_scan += comps - 3; + } + } + } + return TRUE; +} +FX_BOOL ConvertBuffer_32bppCmyk2Rgb32(uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + if (pIccTransform) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1); + dest_scan += 4; + src_scan += 4; + } + } + } else { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = dest_buf + row * dest_pitch; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * 4; + for (int col = 0; col < width; col++) { + AdobeCMYK_to_sRGB1(src_scan[0], src_scan[1], src_scan[2], src_scan[3], + dest_scan[2], dest_scan[1], dest_scan[0]); + dest_scan += 4; + src_scan += 4; + } + } + } + return TRUE; +} +FX_BOOL ConvertBuffer(FXDIB_Format dest_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + FX_DWORD*& d_pal, + void* pIccTransform) { + FXDIB_Format src_format = pSrcBitmap->GetFormat(); + if (!CFX_GEModule::Get()->GetCodecModule() || + !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + pIccTransform = NULL; + } + switch (dest_format) { + case FXDIB_Invalid: + case FXDIB_1bppCmyk: + case FXDIB_1bppMask: + case FXDIB_1bppRgb: + ASSERT(FALSE); + return FALSE; + case FXDIB_8bppMask: { + if ((src_format & 0xff) == 1) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + return ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top); + } + if ((src_format & 0xff) == 8) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + return ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top); + } + if ((src_format & 0xff) >= 24) { + return ConvertBuffer_RgbOrCmyk2Gray(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + return FALSE; + } + case FXDIB_8bppRgb: + case FXDIB_8bppRgba: { + if ((src_format & 0xff) == 8 && !pSrcBitmap->GetPalette()) { + return ConvertBuffer(FXDIB_8bppMask, dest_buf, dest_pitch, width, + height, pSrcBitmap, src_left, src_top, d_pal, + pIccTransform); + } + d_pal = FX_Alloc(FX_DWORD, 256); + if (((src_format & 0xff) == 1 || (src_format & 0xff) == 8) && + pSrcBitmap->GetPalette()) { + return ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, d_pal, + pIccTransform); + } + if ((src_format & 0xff) >= 24) { + return ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, d_pal, + pIccTransform); + } + return FALSE; + } + case FXDIB_Rgb: + case FXDIB_Rgba: { + if ((src_format & 0xff) == 1) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top, pIccTransform); + } + return ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top); + } + if ((src_format & 0xff) == 8) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top, pIccTransform); + } + return ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top); + } + if ((src_format & 0xff) == 24) { + return ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + if ((src_format & 0xff) == 32) { + return ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + return FALSE; + } + case FXDIB_Argb: + case FXDIB_Rgb32: { + if ((src_format & 0xff) == 1) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top, pIccTransform); + } + return ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top); + } + if ((src_format & 0xff) == 8) { + if (pSrcBitmap->GetPalette()) { + return ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top, pIccTransform); + } + return ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, + width, height, pSrcBitmap, src_left, + src_top); + } + if ((src_format & 0xff) >= 24) { + if (src_format & 0x0400) { + return ConvertBuffer_32bppCmyk2Rgb32(dest_buf, dest_pitch, width, + height, pSrcBitmap, src_left, + src_top, pIccTransform); + } + return ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, + pSrcBitmap, src_left, src_top, + pIccTransform); + } + return FALSE; + } + default: + return FALSE; + } + return FALSE; +} +CFX_DIBitmap* CFX_DIBSource::CloneConvert(FXDIB_Format dest_format, + const FX_RECT* pClip, + void* pIccTransform) const { + if (dest_format == GetFormat() && !pIccTransform) { + return Clone(pClip); + } + if (pClip) { + CFX_DIBitmap* pClone = Clone(pClip); + if (!pClone) { + return NULL; + } + if (!pClone->ConvertFormat(dest_format, pIccTransform)) { + delete pClone; + return NULL; + } + return pClone; + } + CFX_DIBitmap* pClone = new CFX_DIBitmap; + if (!pClone->Create(m_Width, m_Height, dest_format)) { + delete pClone; + return NULL; + } + FX_BOOL ret = TRUE; + CFX_DIBitmap* pSrcAlpha = NULL; + if (HasAlpha()) { + pSrcAlpha = (GetFormat() == FXDIB_Argb) ? GetAlphaMask() : m_pAlphaMask; + if (!pSrcAlpha) { + delete pClone; + return NULL; + } + } + if (dest_format & 0x0200) { + if (dest_format == FXDIB_Argb) { + ret = pSrcAlpha ? pClone->LoadChannel(FXDIB_Alpha, pSrcAlpha, FXDIB_Alpha) + : pClone->LoadChannel(FXDIB_Alpha, 0xff); + } else { + ret = pClone->CopyAlphaMask(pSrcAlpha); + } + } + if (pSrcAlpha && pSrcAlpha != m_pAlphaMask) { + delete pSrcAlpha; + pSrcAlpha = NULL; + } + if (!ret) { + delete pClone; + return NULL; + } + FX_DWORD* pal_8bpp = NULL; + ret = ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(), + m_Width, m_Height, this, 0, 0, pal_8bpp, pIccTransform); + if (!ret) { + FX_Free(pal_8bpp); + delete pClone; + return NULL; + } + if (pal_8bpp) { + pClone->CopyPalette(pal_8bpp); + FX_Free(pal_8bpp); + pal_8bpp = NULL; + } + return pClone; +} +FX_BOOL CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format, + void* pIccTransform) { + FXDIB_Format src_format = GetFormat(); + if (dest_format == src_format && !pIccTransform) { + return TRUE; + } + if (dest_format == FXDIB_8bppMask && src_format == FXDIB_8bppRgb && + !m_pPalette) { + m_AlphaFlag = 1; + return TRUE; + } + if (dest_format == FXDIB_Argb && src_format == FXDIB_Rgb32 && + !pIccTransform) { + m_AlphaFlag = 2; + for (int row = 0; row < m_Height; row++) { + uint8_t* scanline = m_pBuffer + row * m_Pitch + 3; + for (int col = 0; col < m_Width; col++) { + *scanline = 0xff; + scanline += 4; + } + } + return TRUE; + } + int dest_bpp = dest_format & 0xff; + int dest_pitch = (dest_bpp * m_Width + 31) / 32 * 4; + uint8_t* dest_buf = FX_TryAlloc(uint8_t, dest_pitch * m_Height + 4); + if (!dest_buf) { + return FALSE; + } + CFX_DIBitmap* pAlphaMask = NULL; + if (dest_format == FXDIB_Argb) { + FXSYS_memset(dest_buf, 0xff, dest_pitch * m_Height + 4); + if (m_pAlphaMask) { + for (int row = 0; row < m_Height; row++) { + uint8_t* pDstScanline = dest_buf + row * dest_pitch + 3; + const uint8_t* pSrcScanline = m_pAlphaMask->GetScanline(row); + for (int col = 0; col < m_Width; col++) { + *pDstScanline = *pSrcScanline++; + pDstScanline += 4; + } + } + } + } else if (dest_format & 0x0200) { + if (src_format == FXDIB_Argb) { + pAlphaMask = GetAlphaMask(); + if (!pAlphaMask) { + FX_Free(dest_buf); + return FALSE; + } + } else { + if (!m_pAlphaMask) { + if (!BuildAlphaMask()) { + FX_Free(dest_buf); + return FALSE; + } + pAlphaMask = m_pAlphaMask; + m_pAlphaMask = NULL; + } else { + pAlphaMask = m_pAlphaMask; + } + } + } + FX_BOOL ret = FALSE; + FX_DWORD* pal_8bpp = NULL; + ret = ConvertBuffer(dest_format, dest_buf, dest_pitch, m_Width, m_Height, + this, 0, 0, pal_8bpp, pIccTransform); + if (!ret) { + FX_Free(pal_8bpp); + if (pAlphaMask != m_pAlphaMask) { + delete pAlphaMask; + } + FX_Free(dest_buf); + return FALSE; + } + if (m_pAlphaMask && pAlphaMask != m_pAlphaMask) { + delete m_pAlphaMask; + } + m_pAlphaMask = pAlphaMask; + FX_Free(m_pPalette); + m_pPalette = pal_8bpp; + if (!m_bExtBuf) { + FX_Free(m_pBuffer); + } + m_bExtBuf = FALSE; + m_pBuffer = dest_buf; + m_bpp = (uint8_t)dest_format; + m_AlphaFlag = (uint8_t)(dest_format >> 8); + m_Pitch = dest_pitch; + return TRUE; +} diff --git a/core/fxge/dib/fx_dib_engine.cpp b/core/fxge/dib/fx_dib_engine.cpp new file mode 100644 index 0000000000..10e5e67bbc --- /dev/null +++ b/core/fxge/dib/fx_dib_engine.cpp @@ -0,0 +1,917 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include <limits.h> + +#include "core/fxge/dib/dib_int.h" +#include "core/include/fxge/fx_dib.h" +#include "core/include/fxge/fx_ge.h" + +void CWeightTable::Calc(int dest_len, + int dest_min, + int dest_max, + int src_len, + int src_min, + int src_max, + int flags) { + FX_Free(m_pWeightTables); + m_pWeightTables = NULL; + double scale, base; + scale = (FX_FLOAT)src_len / (FX_FLOAT)dest_len; + if (dest_len < 0) { + base = (FX_FLOAT)(src_len); + } else { + base = 0; + } + int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1; + m_ItemSize = + sizeof(int) * 2 + + (int)(sizeof(int) * (FXSYS_ceil(FXSYS_fabs((FX_FLOAT)scale)) + ext_size)); + m_DestMin = dest_min; + if ((dest_max - dest_min) > (int)((1U << 30) - 4) / m_ItemSize) { + return; + } + m_pWeightTables = + FX_TryAlloc(uint8_t, (dest_max - dest_min) * m_ItemSize + 4); + if (!m_pWeightTables) { + return; + } + if ((flags & FXDIB_NOSMOOTH) != 0 || FXSYS_fabs((FX_FLOAT)scale) < 1.0f) { + for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel++) { + PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); + double src_pos = dest_pixel * scale + scale / 2 + base; + if (flags & FXDIB_INTERPOL) { + pixel_weights.m_SrcStart = + (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2); + pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2); + if (pixel_weights.m_SrcStart < src_min) { + pixel_weights.m_SrcStart = src_min; + } + if (pixel_weights.m_SrcEnd >= src_max) { + pixel_weights.m_SrcEnd = src_max - 1; + } + if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { + pixel_weights.m_Weights[0] = 65536; + } else { + pixel_weights.m_Weights[1] = FXSYS_round( + (FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * + 65536); + pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1]; + } + } else if (flags & FXDIB_BICUBIC_INTERPOL) { + pixel_weights.m_SrcStart = + (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2); + pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2); + int start = pixel_weights.m_SrcStart - 1; + int end = pixel_weights.m_SrcEnd + 1; + if (start < src_min) { + start = src_min; + } + if (end >= src_max) { + end = src_max - 1; + } + if (pixel_weights.m_SrcStart < src_min) { + src_pos += src_min - pixel_weights.m_SrcStart; + pixel_weights.m_SrcStart = src_min; + } + if (pixel_weights.m_SrcEnd >= src_max) { + pixel_weights.m_SrcEnd = src_max - 1; + } + int weight; + weight = FXSYS_round( + (FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 256); + if (start == end) { + pixel_weights.m_Weights[0] = + (SDP_Table[256 + weight] + SDP_Table[weight] + + SDP_Table[256 - weight] + SDP_Table[512 - weight]) + << 8; + } else if ((start == pixel_weights.m_SrcStart && + (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd || + end == pixel_weights.m_SrcEnd) && + start < end) || + (start < pixel_weights.m_SrcStart && + pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd && + end == pixel_weights.m_SrcEnd)) { + if (start < pixel_weights.m_SrcStart) { + pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; + pixel_weights.m_Weights[1] = + (SDP_Table[weight] + SDP_Table[256 - weight] + + SDP_Table[512 - weight]) + << 8; + } else { + if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { + pixel_weights.m_Weights[0] = + (SDP_Table[256 + weight] + SDP_Table[weight] + + SDP_Table[256 - weight]) + << 8; + pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8; + } else { + pixel_weights.m_Weights[0] = + (SDP_Table[256 + weight] + SDP_Table[weight]) << 8; + pixel_weights.m_Weights[1] = + (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; + } + } + if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { + pixel_weights.m_SrcEnd = end; + } + if (start < pixel_weights.m_SrcStart) { + pixel_weights.m_SrcStart = start; + } + } else if (start == pixel_weights.m_SrcStart && + start < pixel_weights.m_SrcEnd && + pixel_weights.m_SrcEnd < end) { + pixel_weights.m_Weights[0] = + (SDP_Table[256 + weight] + SDP_Table[weight]) << 8; + pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8; + pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8; + pixel_weights.m_SrcEnd = end; + } else if (start < pixel_weights.m_SrcStart && + pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd && + pixel_weights.m_SrcEnd == end) { + pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; + pixel_weights.m_Weights[1] = SDP_Table[weight] << 8; + pixel_weights.m_Weights[2] = + (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; + pixel_weights.m_SrcStart = start; + } else { + pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; + pixel_weights.m_Weights[1] = SDP_Table[weight] << 8; + pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8; + pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8; + pixel_weights.m_SrcStart = start; + pixel_weights.m_SrcEnd = end; + } + } else { + pixel_weights.m_SrcStart = pixel_weights.m_SrcEnd = + (int)FXSYS_floor((FX_FLOAT)src_pos); + if (pixel_weights.m_SrcStart < src_min) { + pixel_weights.m_SrcStart = src_min; + } + if (pixel_weights.m_SrcEnd >= src_max) { + pixel_weights.m_SrcEnd = src_max - 1; + } + pixel_weights.m_Weights[0] = 65536; + } + } + return; + } + for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel++) { + PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); + double src_start = dest_pixel * scale + base; + double src_end = src_start + scale; + int start_i, end_i; + if (src_start < src_end) { + start_i = (int)FXSYS_floor((FX_FLOAT)src_start); + end_i = (int)FXSYS_ceil((FX_FLOAT)src_end); + } else { + start_i = (int)FXSYS_floor((FX_FLOAT)src_end); + end_i = (int)FXSYS_ceil((FX_FLOAT)src_start); + } + if (start_i < src_min) { + start_i = src_min; + } + if (end_i >= src_max) { + end_i = src_max - 1; + } + if (start_i > end_i) { + if (start_i >= src_max) { + start_i = src_max - 1; + } + pixel_weights.m_SrcStart = start_i; + pixel_weights.m_SrcEnd = start_i; + continue; + } + pixel_weights.m_SrcStart = start_i; + pixel_weights.m_SrcEnd = end_i; + for (int j = start_i; j <= end_i; j++) { + double dest_start = ((FX_FLOAT)j - base) / scale; + double dest_end = ((FX_FLOAT)(j + 1) - base) / scale; + if (dest_start > dest_end) { + double temp = dest_start; + dest_start = dest_end; + dest_end = temp; + } + double area_start = dest_start > (FX_FLOAT)(dest_pixel) + ? dest_start + : (FX_FLOAT)(dest_pixel); + double area_end = dest_end > (FX_FLOAT)(dest_pixel + 1) + ? (FX_FLOAT)(dest_pixel + 1) + : dest_end; + double weight = area_start >= area_end ? 0.0f : area_end - area_start; + if (weight == 0 && j == end_i) { + pixel_weights.m_SrcEnd--; + break; + } + pixel_weights.m_Weights[j - start_i] = + FXSYS_round((FX_FLOAT)(weight * 65536)); + } + } +} +CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap, + FXDIB_Format dest_format, + int dest_width, + int dest_height, + const FX_RECT& clip_rect, + const CFX_DIBSource* pSrcBitmap, + int flags) { + m_State = 0; + m_DestFormat = dest_format; + m_DestBpp = dest_format & 0xff; + m_SrcBpp = pSrcBitmap->GetFormat() & 0xff; + m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200; + m_pSrcPalette = pSrcBitmap->GetPalette(); + m_pDestBitmap = pDestBitmap; + m_DestWidth = dest_width; + m_DestHeight = dest_height; + m_pInterBuf = NULL; + m_pExtraAlphaBuf = NULL; + m_pDestMaskScanline = NULL; + m_DestClip = clip_rect; + FX_DWORD size = clip_rect.Width(); + if (size && m_DestBpp > (int)(INT_MAX / size)) { + return; + } + size *= m_DestBpp; + if (size > INT_MAX - 31) { + return; + } + size += 31; + size = size / 32 * 4; + m_pDestScanline = FX_TryAlloc(uint8_t, size); + if (!m_pDestScanline) { + return; + } + if (dest_format == FXDIB_Rgb32) { + FXSYS_memset(m_pDestScanline, 255, size); + } + m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4; + m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4; + m_pInterBuf = NULL; + m_pSource = pSrcBitmap; + m_SrcWidth = pSrcBitmap->GetWidth(); + m_SrcHeight = pSrcBitmap->GetHeight(); + m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4; + if ((flags & FXDIB_NOSMOOTH) == 0) { + FX_BOOL bInterpol = + flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL; + if (!bInterpol && FXSYS_abs(dest_width) != 0 && + FXSYS_abs(dest_height) < + m_SrcWidth * m_SrcHeight * 8 / FXSYS_abs(dest_width)) { + flags = FXDIB_INTERPOL; + } + m_Flags = flags; + } else { + m_Flags = FXDIB_NOSMOOTH; + if (flags & FXDIB_DOWNSAMPLE) { + m_Flags |= FXDIB_DOWNSAMPLE; + } + } + double scale_x = (FX_FLOAT)m_SrcWidth / (FX_FLOAT)m_DestWidth; + double scale_y = (FX_FLOAT)m_SrcHeight / (FX_FLOAT)m_DestHeight; + double base_x = m_DestWidth > 0 ? 0.0f : (FX_FLOAT)(m_DestWidth); + double base_y = m_DestHeight > 0 ? 0.0f : (FX_FLOAT)(m_DestHeight); + double src_left = scale_x * ((FX_FLOAT)(clip_rect.left) + base_x); + double src_right = scale_x * ((FX_FLOAT)(clip_rect.right) + base_x); + double src_top = scale_y * ((FX_FLOAT)(clip_rect.top) + base_y); + double src_bottom = scale_y * ((FX_FLOAT)(clip_rect.bottom) + base_y); + if (src_left > src_right) { + double temp = src_left; + src_left = src_right; + src_right = temp; + } + if (src_top > src_bottom) { + double temp = src_top; + src_top = src_bottom; + src_bottom = temp; + } + m_SrcClip.left = (int)FXSYS_floor((FX_FLOAT)src_left); + m_SrcClip.right = (int)FXSYS_ceil((FX_FLOAT)src_right); + m_SrcClip.top = (int)FXSYS_floor((FX_FLOAT)src_top); + m_SrcClip.bottom = (int)FXSYS_ceil((FX_FLOAT)src_bottom); + FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight); + m_SrcClip.Intersect(src_rect); + if (m_SrcBpp == 1) { + if (m_DestBpp == 8) { + m_TransMethod = 1; + } else { + m_TransMethod = 2; + } + } else if (m_SrcBpp == 8) { + if (m_DestBpp == 8) { + if (!m_bHasAlpha) { + m_TransMethod = 3; + } else { + m_TransMethod = 4; + } + } else { + if (!m_bHasAlpha) { + m_TransMethod = 5; + } else { + m_TransMethod = 6; + } + } + } else { + if (!m_bHasAlpha) { + m_TransMethod = 7; + } else { + m_TransMethod = 8; + } + } +} +FX_BOOL CStretchEngine::Continue(IFX_Pause* pPause) { + while (m_State == 1) { + if (ContinueStretchHorz(pPause)) { + return TRUE; + } + m_State = 2; + StretchVert(); + } + return FALSE; +} +CStretchEngine::~CStretchEngine() { + FX_Free(m_pDestScanline); + FX_Free(m_pInterBuf); + FX_Free(m_pExtraAlphaBuf); + FX_Free(m_pDestMaskScanline); +} +FX_BOOL CStretchEngine::StartStretchHorz() { + if (m_DestWidth == 0 || !m_pDestScanline || + m_SrcClip.Height() > (int)((1U << 29) / m_InterPitch) || + m_SrcClip.Height() == 0) { + return FALSE; + } + m_pInterBuf = FX_TryAlloc(unsigned char, m_SrcClip.Height() * m_InterPitch); + if (!m_pInterBuf) { + return FALSE; + } + if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) { + m_pExtraAlphaBuf = + FX_Alloc2D(unsigned char, m_SrcClip.Height(), m_ExtraMaskPitch); + FX_DWORD size = (m_DestClip.Width() * 8 + 31) / 32 * 4; + m_pDestMaskScanline = FX_TryAlloc(unsigned char, size); + if (!m_pDestMaskScanline) { + return FALSE; + } + } + m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right, m_SrcWidth, + m_SrcClip.left, m_SrcClip.right, m_Flags); + if (!m_WeightTable.m_pWeightTables) { + return FALSE; + } + m_CurRow = m_SrcClip.top; + m_State = 1; + return TRUE; +} +#define FX_STRECH_PAUSE_ROWS 10 +FX_BOOL CStretchEngine::ContinueStretchHorz(IFX_Pause* pPause) { + if (!m_DestWidth) { + return 0; + } + if (m_pSource->SkipToScanline(m_CurRow, pPause)) { + return TRUE; + } + int Bpp = m_DestBpp / 8; + int rows_to_go = FX_STRECH_PAUSE_ROWS; + for (; m_CurRow < m_SrcClip.bottom; m_CurRow++) { + if (rows_to_go == 0) { + if (pPause && pPause->NeedToPauseNow()) { + return TRUE; + } + rows_to_go = FX_STRECH_PAUSE_ROWS; + } + const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow); + uint8_t* dest_scan = + m_pInterBuf + (m_CurRow - m_SrcClip.top) * m_InterPitch; + const uint8_t* src_scan_mask = NULL; + uint8_t* dest_scan_mask = NULL; + if (m_pExtraAlphaBuf) { + src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow); + dest_scan_mask = + m_pExtraAlphaBuf + (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch; + } + switch (m_TransMethod) { + case 1: + case 2: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_a = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + if (src_scan[j / 8] & (1 << (7 - j % 8))) { + dest_a += pixel_weight * 255; + } + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a; + } + *dest_scan++ = (uint8_t)(dest_a >> 16); + } + break; + } + case 3: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_a = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + dest_a += pixel_weight * src_scan[j]; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a; + } + *dest_scan++ = (uint8_t)(dest_a >> 16); + } + break; + } + case 4: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_a = 0, dest_r = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + pixel_weight = pixel_weight * src_scan_mask[j] / 255; + dest_r += pixel_weight * src_scan[j]; + dest_a += pixel_weight; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_r = dest_r < 0 ? 0 : dest_r > 16711680 ? 16711680 : dest_r; + dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a; + } + *dest_scan++ = (uint8_t)(dest_r >> 16); + *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16); + } + break; + } + case 5: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]]; + if (m_DestFormat == FXDIB_Rgb) { + dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 16); + dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 8); + dest_b_c += pixel_weight * (uint8_t)argb_cmyk; + } else { + dest_b_c += pixel_weight * (uint8_t)(argb_cmyk >> 24); + dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 16); + dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 8); + } + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + } + *dest_scan++ = (uint8_t)(dest_b_c >> 16); + *dest_scan++ = (uint8_t)(dest_g_m >> 16); + *dest_scan++ = (uint8_t)(dest_r_y >> 16); + } + break; + } + case 6: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + pixel_weight = pixel_weight * src_scan_mask[j] / 255; + unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]]; + if (m_DestFormat == FXDIB_Rgba) { + dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 16); + dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 8); + dest_b_c += pixel_weight * (uint8_t)argb_cmyk; + } else { + dest_b_c += pixel_weight * (uint8_t)(argb_cmyk >> 24); + dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 16); + dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 8); + } + dest_a += pixel_weight; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a; + } + *dest_scan++ = (uint8_t)(dest_b_c >> 16); + *dest_scan++ = (uint8_t)(dest_g_m >> 16); + *dest_scan++ = (uint8_t)(dest_r_y >> 16); + *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16); + } + break; + } + case 7: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + const uint8_t* src_pixel = src_scan + j * Bpp; + dest_b_c += pixel_weight * (*src_pixel++); + dest_g_m += pixel_weight * (*src_pixel++); + dest_r_y += pixel_weight * (*src_pixel); + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + } + *dest_scan++ = (uint8_t)((dest_b_c) >> 16); + *dest_scan++ = (uint8_t)((dest_g_m) >> 16); + *dest_scan++ = (uint8_t)((dest_r_y) >> 16); + dest_scan += Bpp - 3; + } + break; + } + case 8: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col); + int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + const uint8_t* src_pixel = src_scan + j * Bpp; + if (m_DestFormat == FXDIB_Argb) { + pixel_weight = pixel_weight * src_pixel[3] / 255; + } else { + pixel_weight = pixel_weight * src_scan_mask[j] / 255; + } + dest_b_c += pixel_weight * (*src_pixel++); + dest_g_m += pixel_weight * (*src_pixel++); + dest_r_y += pixel_weight * (*src_pixel); + dest_a += pixel_weight; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a; + } + *dest_scan++ = (uint8_t)((dest_b_c) >> 16); + *dest_scan++ = (uint8_t)((dest_g_m) >> 16); + *dest_scan++ = (uint8_t)((dest_r_y) >> 16); + if (m_DestFormat == FXDIB_Argb) { + *dest_scan = (uint8_t)((dest_a * 255) >> 16); + } + if (dest_scan_mask) { + *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16); + } + dest_scan += Bpp - 3; + } + break; + } + } + rows_to_go--; + } + return FALSE; +} +void CStretchEngine::StretchVert() { + if (m_DestHeight == 0) { + return; + } + CWeightTable table; + table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom, m_SrcHeight, + m_SrcClip.top, m_SrcClip.bottom, m_Flags); + if (!table.m_pWeightTables) { + return; + } + int DestBpp = m_DestBpp / 8; + for (int row = m_DestClip.top; row < m_DestClip.bottom; row++) { + unsigned char* dest_scan = m_pDestScanline; + unsigned char* dest_sacn_mask = m_pDestMaskScanline; + PixelWeight* pPixelWeights = table.GetPixelWeight(row); + switch (m_TransMethod) { + case 1: + case 2: + case 3: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + unsigned char* src_scan = + m_pInterBuf + (col - m_DestClip.left) * DestBpp; + int dest_a = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + dest_a += + pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch]; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a; + } + *dest_scan = (uint8_t)(dest_a >> 16); + dest_scan += DestBpp; + } + break; + } + case 4: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + unsigned char* src_scan = + m_pInterBuf + (col - m_DestClip.left) * DestBpp; + unsigned char* src_scan_mask = + m_pExtraAlphaBuf + (col - m_DestClip.left); + int dest_a = 0, dest_k = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + dest_k += + pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch]; + dest_a += pixel_weight * + src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch]; + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_k = dest_k < 0 ? 0 : dest_k > 16711680 ? 16711680 : dest_k; + dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a; + } + *dest_scan = (uint8_t)(dest_k >> 16); + dest_scan += DestBpp; + *dest_sacn_mask++ = (uint8_t)(dest_a >> 16); + } + break; + } + case 5: + case 7: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + unsigned char* src_scan = + m_pInterBuf + (col - m_DestClip.left) * DestBpp; + int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + const uint8_t* src_pixel = + src_scan + (j - m_SrcClip.top) * m_InterPitch; + dest_b_c += pixel_weight * (*src_pixel++); + dest_g_m += pixel_weight * (*src_pixel++); + dest_r_y += pixel_weight * (*src_pixel); + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + } + dest_scan[0] = (uint8_t)((dest_b_c) >> 16); + dest_scan[1] = (uint8_t)((dest_g_m) >> 16); + dest_scan[2] = (uint8_t)((dest_r_y) >> 16); + dest_scan += DestBpp; + } + break; + } + case 6: + case 8: { + for (int col = m_DestClip.left; col < m_DestClip.right; col++) { + unsigned char* src_scan = + m_pInterBuf + (col - m_DestClip.left) * DestBpp; + unsigned char* src_scan_mask = NULL; + if (m_DestFormat != FXDIB_Argb) { + src_scan_mask = m_pExtraAlphaBuf + (col - m_DestClip.left); + } + int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0; + for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; + j++) { + int pixel_weight = + pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart]; + const uint8_t* src_pixel = + src_scan + (j - m_SrcClip.top) * m_InterPitch; + int mask_v = 255; + if (src_scan_mask) { + mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch]; + } + dest_b_c += pixel_weight * (*src_pixel++); + dest_g_m += pixel_weight * (*src_pixel++); + dest_r_y += pixel_weight * (*src_pixel); + if (m_DestFormat == FXDIB_Argb) { + dest_a += pixel_weight * (*(src_pixel + 1)); + } else { + dest_a += pixel_weight * mask_v; + } + } + if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + dest_r_y = + dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y; + dest_g_m = + dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m; + dest_b_c = + dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c; + dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a; + } + if (dest_a) { + int r = ((FX_DWORD)dest_r_y) * 255 / dest_a; + int g = ((FX_DWORD)dest_g_m) * 255 / dest_a; + int b = ((FX_DWORD)dest_b_c) * 255 / dest_a; + dest_scan[0] = b > 255 ? 255 : b < 0 ? 0 : b; + dest_scan[1] = g > 255 ? 255 : g < 0 ? 0 : g; + dest_scan[2] = r > 255 ? 255 : r < 0 ? 0 : r; + } + if (m_DestFormat == FXDIB_Argb) { + dest_scan[3] = (uint8_t)((dest_a) >> 16); + } else { + *dest_sacn_mask = (uint8_t)((dest_a) >> 16); + } + dest_scan += DestBpp; + if (dest_sacn_mask) { + dest_sacn_mask++; + } + } + break; + } + } + m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_pDestScanline, + m_pDestMaskScanline); + } +} +CFX_ImageStretcher::CFX_ImageStretcher() { + m_pScanline = NULL; + m_pStretchEngine = NULL; + m_pMaskScanline = NULL; +} +CFX_ImageStretcher::~CFX_ImageStretcher() { + FX_Free(m_pScanline); + delete m_pStretchEngine; + FX_Free(m_pMaskScanline); +} +FXDIB_Format _GetStretchedFormat(const CFX_DIBSource* pSrc) { + FXDIB_Format format = pSrc->GetFormat(); + if (format == FXDIB_1bppMask) { + format = FXDIB_8bppMask; + } else if (format == FXDIB_1bppRgb) { + format = FXDIB_8bppRgb; + } else if (format == FXDIB_8bppRgb) { + if (pSrc->GetPalette()) { + format = FXDIB_Rgb; + } + } + return format; +} +FX_BOOL CFX_ImageStretcher::Start(IFX_ScanlineComposer* pDest, + const CFX_DIBSource* pSource, + int dest_width, + int dest_height, + const FX_RECT& rect, + FX_DWORD flags) { + m_DestFormat = _GetStretchedFormat(pSource); + m_DestBPP = m_DestFormat & 0xff; + m_pDest = pDest; + m_pSource = pSource; + m_DestWidth = dest_width; + m_DestHeight = dest_height; + m_ClipRect = rect; + m_Flags = flags; + if (pSource->GetFormat() == FXDIB_1bppRgb && pSource->GetPalette()) { + FX_ARGB pal[256]; + int a0, r0, g0, b0, a1, r1, g1, b1; + ArgbDecode(pSource->GetPaletteEntry(0), a0, r0, g0, b0); + ArgbDecode(pSource->GetPaletteEntry(1), a1, r1, g1, b1); + for (int i = 0; i < 256; i++) { + int a = a0 + (a1 - a0) * i / 255; + int r = r0 + (r1 - r0) * i / 255; + int g = g0 + (g1 - g0) * i / 255; + int b = b0 + (b1 - b0) * i / 255; + pal[i] = ArgbEncode(a, r, g, b); + } + if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) { + return FALSE; + } + } else if (pSource->GetFormat() == FXDIB_1bppCmyk && pSource->GetPalette()) { + FX_CMYK pal[256]; + int c0, m0, y0, k0, c1, m1, y1, k1; + CmykDecode(pSource->GetPaletteEntry(0), c0, m0, y0, k0); + CmykDecode(pSource->GetPaletteEntry(1), c1, m1, y1, k1); + for (int i = 0; i < 256; i++) { + int c = c0 + (c1 - c0) * i / 255; + int m = m0 + (m1 - m0) * i / 255; + int y = y0 + (y1 - y0) * i / 255; + int k = k0 + (k1 - k0) * i / 255; + pal[i] = CmykEncode(c, m, y, k); + } + if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) { + return FALSE; + } + } else if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, NULL)) { + return FALSE; + } + if (flags & FXDIB_DOWNSAMPLE) { + return StartQuickStretch(); + } + return StartStretch(); +} +FX_BOOL CFX_ImageStretcher::Continue(IFX_Pause* pPause) { + if (m_Flags & FXDIB_DOWNSAMPLE) { + return ContinueQuickStretch(pPause); + } + return ContinueStretch(pPause); +} +#define MAX_PROGRESSIVE_STRETCH_PIXELS 1000000 +FX_BOOL CFX_ImageStretcher::StartStretch() { + m_pStretchEngine = + new CStretchEngine(m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, + m_ClipRect, m_pSource, m_Flags); + m_pStretchEngine->StartStretchHorz(); + if (m_pSource->GetWidth() * m_pSource->GetHeight() < + MAX_PROGRESSIVE_STRETCH_PIXELS) { + m_pStretchEngine->Continue(NULL); + return FALSE; + } + return TRUE; +} +FX_BOOL CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) { + return m_pStretchEngine && m_pStretchEngine->Continue(pPause); +} +FX_BOOL CFX_ImageStretcher::StartQuickStretch() { + m_bFlipX = FALSE; + m_bFlipY = FALSE; + if (m_DestWidth < 0) { + m_bFlipX = TRUE; + m_DestWidth = -m_DestWidth; + } + if (m_DestHeight < 0) { + m_bFlipY = TRUE; + m_DestHeight = -m_DestHeight; + } + m_LineIndex = 0; + FX_DWORD size = m_ClipRect.Width(); + if (size && m_DestBPP > (int)(INT_MAX / size)) { + return FALSE; + } + size *= m_DestBPP; + m_pScanline = FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4); + if (m_pSource->m_pAlphaMask) { + m_pMaskScanline = FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4); + } + if (m_pSource->GetWidth() * m_pSource->GetHeight() < + MAX_PROGRESSIVE_STRETCH_PIXELS) { + ContinueQuickStretch(NULL); + return FALSE; + } + return TRUE; +} +FX_BOOL CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) { + if (!m_pScanline) { + return FALSE; + } + int result_width = m_ClipRect.Width(), result_height = m_ClipRect.Height(); + int src_height = m_pSource->GetHeight(); + for (; m_LineIndex < result_height; m_LineIndex++) { + int dest_y, src_y; + if (m_bFlipY) { + dest_y = result_height - m_LineIndex - 1; + src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height / + m_DestHeight; + } else { + dest_y = m_LineIndex; + src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight; + } + if (src_y >= src_height) { + src_y = src_height - 1; + } + if (src_y < 0) { + src_y = 0; + } + if (m_pSource->SkipToScanline(src_y, pPause)) { + return TRUE; + } + m_pSource->DownSampleScanline(src_y, m_pScanline, m_DestBPP, m_DestWidth, + m_bFlipX, m_ClipRect.left, result_width); + if (m_pMaskScanline) { + m_pSource->m_pAlphaMask->DownSampleScanline( + src_y, m_pMaskScanline, 1, m_DestWidth, m_bFlipX, m_ClipRect.left, + result_width); + } + m_pDest->ComposeScanline(dest_y, m_pScanline, m_pMaskScanline); + } + return FALSE; +} diff --git a/core/fxge/dib/fx_dib_main.cpp b/core/fxge/dib/fx_dib_main.cpp new file mode 100644 index 0000000000..8ce20568df --- /dev/null +++ b/core/fxge/dib/fx_dib_main.cpp @@ -0,0 +1,1745 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/include/fxge/fx_dib.h" + +#include <limits.h> + +#include "core/fxge/dib/dib_int.h" +#include "core/include/fxcodec/fx_codec.h" +#include "core/include/fxge/fx_ge.h" + +FX_BOOL ConvertBuffer(FXDIB_Format dest_format, + uint8_t* dest_buf, + int dest_pitch, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + FX_DWORD*& pal, + void* pIccTransform); +void CmykDecode(FX_DWORD cmyk, int& c, int& m, int& y, int& k) { + c = FXSYS_GetCValue(cmyk); + m = FXSYS_GetMValue(cmyk); + y = FXSYS_GetYValue(cmyk); + k = FXSYS_GetKValue(cmyk); +} +void ArgbDecode(FX_DWORD argb, int& a, int& r, int& g, int& b) { + a = FXARGB_A(argb); + r = FXARGB_R(argb); + g = FXARGB_G(argb); + b = FXARGB_B(argb); +} +void ArgbDecode(FX_DWORD argb, int& a, FX_COLORREF& rgb) { + a = FXARGB_A(argb); + rgb = FXSYS_RGB(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb)); +} +FX_DWORD ArgbEncode(int a, FX_COLORREF rgb) { + return FXARGB_MAKE(a, FXSYS_GetRValue(rgb), FXSYS_GetGValue(rgb), + FXSYS_GetBValue(rgb)); +} + +CFX_DIBSource::CFX_DIBSource() { + m_bpp = 0; + m_AlphaFlag = 0; + m_Width = m_Height = 0; + m_Pitch = 0; + m_pPalette = NULL; + m_pAlphaMask = NULL; +} + +CFX_DIBSource::~CFX_DIBSource() { + FX_Free(m_pPalette); + delete m_pAlphaMask; +} + +uint8_t* CFX_DIBSource::GetBuffer() const { + return NULL; +} + +FX_BOOL CFX_DIBSource::SkipToScanline(int line, IFX_Pause* pPause) const { + return FALSE; +} + +CFX_DIBitmap::CFX_DIBitmap() { + m_bExtBuf = FALSE; + m_pBuffer = NULL; + m_pPalette = NULL; +} + +#define _MAX_OOM_LIMIT_ 12000000 +FX_BOOL CFX_DIBitmap::Create(int width, + int height, + FXDIB_Format format, + uint8_t* pBuffer, + int pitch) { + m_pBuffer = NULL; + m_bpp = (uint8_t)format; + m_AlphaFlag = (uint8_t)(format >> 8); + m_Width = m_Height = m_Pitch = 0; + if (width <= 0 || height <= 0 || pitch < 0) { + return FALSE; + } + if ((INT_MAX - 31) / width < (format & 0xff)) { + return FALSE; + } + if (!pitch) { + pitch = (width * (format & 0xff) + 31) / 32 * 4; + } + if ((1 << 30) / pitch < height) { + return FALSE; + } + if (pBuffer) { + m_pBuffer = pBuffer; + m_bExtBuf = TRUE; + } else { + int size = pitch * height + 4; + int oomlimit = _MAX_OOM_LIMIT_; + if (oomlimit >= 0 && size >= oomlimit) { + m_pBuffer = FX_TryAlloc(uint8_t, size); + if (!m_pBuffer) { + return FALSE; + } + } else { + m_pBuffer = FX_Alloc(uint8_t, size); + } + } + m_Width = width; + m_Height = height; + m_Pitch = pitch; + if (HasAlpha() && format != FXDIB_Argb) { + FX_BOOL ret = TRUE; + ret = BuildAlphaMask(); + if (!ret) { + if (!m_bExtBuf) { + FX_Free(m_pBuffer); + m_pBuffer = NULL; + m_Width = m_Height = m_Pitch = 0; + return FALSE; + } + } + } + return TRUE; +} + +FX_BOOL CFX_DIBitmap::Copy(const CFX_DIBSource* pSrc) { + if (m_pBuffer) { + return FALSE; + } + if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat())) { + return FALSE; + } + CopyPalette(pSrc->GetPalette()); + CopyAlphaMask(pSrc->m_pAlphaMask); + for (int row = 0; row < pSrc->GetHeight(); row++) { + FXSYS_memcpy(m_pBuffer + row * m_Pitch, pSrc->GetScanline(row), m_Pitch); + } + return TRUE; +} + +CFX_DIBitmap::~CFX_DIBitmap() { + if (!m_bExtBuf) + FX_Free(m_pBuffer); + + m_pBuffer = nullptr; +} + +uint8_t* CFX_DIBitmap::GetBuffer() const { + return m_pBuffer; +} + +const uint8_t* CFX_DIBitmap::GetScanline(int line) const { + return m_pBuffer ? m_pBuffer + line * m_Pitch : nullptr; +} + +void CFX_DIBitmap::TakeOver(CFX_DIBitmap* pSrcBitmap) { + if (!m_bExtBuf) + FX_Free(m_pBuffer); + + FX_Free(m_pPalette); + delete m_pAlphaMask; + m_pBuffer = pSrcBitmap->m_pBuffer; + m_pPalette = pSrcBitmap->m_pPalette; + m_pAlphaMask = pSrcBitmap->m_pAlphaMask; + pSrcBitmap->m_pBuffer = nullptr; + pSrcBitmap->m_pPalette = nullptr; + pSrcBitmap->m_pAlphaMask = nullptr; + m_bpp = pSrcBitmap->m_bpp; + m_bExtBuf = pSrcBitmap->m_bExtBuf; + m_AlphaFlag = pSrcBitmap->m_AlphaFlag; + m_Width = pSrcBitmap->m_Width; + m_Height = pSrcBitmap->m_Height; + m_Pitch = pSrcBitmap->m_Pitch; +} + +CFX_DIBitmap* CFX_DIBSource::Clone(const FX_RECT* pClip) const { + FX_RECT rect(0, 0, m_Width, m_Height); + if (pClip) { + rect.Intersect(*pClip); + if (rect.IsEmpty()) { + return NULL; + } + } + CFX_DIBitmap* pNewBitmap = new CFX_DIBitmap; + if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat())) { + delete pNewBitmap; + return NULL; + } + pNewBitmap->CopyPalette(m_pPalette); + pNewBitmap->CopyAlphaMask(m_pAlphaMask, pClip); + if (GetBPP() == 1 && rect.left % 8 != 0) { + int left_shift = rect.left % 32; + int right_shift = 32 - left_shift; + int dword_count = pNewBitmap->m_Pitch / 4; + for (int row = rect.top; row < rect.bottom; row++) { + FX_DWORD* src_scan = (FX_DWORD*)GetScanline(row) + rect.left / 32; + FX_DWORD* dest_scan = (FX_DWORD*)pNewBitmap->GetScanline(row - rect.top); + for (int i = 0; i < dword_count; i++) { + dest_scan[i] = + (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift); + } + } + } else { + int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8; + if (m_Pitch < (FX_DWORD)copy_len) { + copy_len = m_Pitch; + } + for (int row = rect.top; row < rect.bottom; row++) { + const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8; + uint8_t* dest_scan = (uint8_t*)pNewBitmap->GetScanline(row - rect.top); + FXSYS_memcpy(dest_scan, src_scan, copy_len); + } + } + return pNewBitmap; +} +void CFX_DIBSource::BuildPalette() { + if (m_pPalette) { + return; + } + if (GetBPP() == 1) { + m_pPalette = FX_Alloc(FX_DWORD, 2); + if (IsCmykImage()) { + m_pPalette[0] = 0xff; + m_pPalette[1] = 0; + } else { + m_pPalette[0] = 0xff000000; + m_pPalette[1] = 0xffffffff; + } + } else if (GetBPP() == 8) { + m_pPalette = FX_Alloc(FX_DWORD, 256); + if (IsCmykImage()) { + for (int i = 0; i < 256; i++) { + m_pPalette[i] = 0xff - i; + } + } else { + for (int i = 0; i < 256; i++) { + m_pPalette[i] = 0xff000000 | (i * 0x10101); + } + } + } +} +FX_BOOL CFX_DIBSource::BuildAlphaMask() { + if (m_pAlphaMask) { + return TRUE; + } + m_pAlphaMask = new CFX_DIBitmap; + if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) { + delete m_pAlphaMask; + m_pAlphaMask = NULL; + return FALSE; + } + FXSYS_memset(m_pAlphaMask->GetBuffer(), 0xff, + m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch()); + return TRUE; +} +FX_DWORD CFX_DIBSource::GetPaletteEntry(int index) const { + ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask()); + if (m_pPalette) { + return m_pPalette[index]; + } + if (IsCmykImage()) { + if (GetBPP() == 1) { + return index ? 0 : 0xff; + } + return 0xff - index; + } + if (GetBPP() == 1) { + return index ? 0xffffffff : 0xff000000; + } + return index * 0x10101 | 0xff000000; +} +void CFX_DIBSource::SetPaletteEntry(int index, FX_DWORD color) { + ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask()); + if (!m_pPalette) { + BuildPalette(); + } + m_pPalette[index] = color; +} +int CFX_DIBSource::FindPalette(FX_DWORD color) const { + ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask()); + if (!m_pPalette) { + if (IsCmykImage()) { + if (GetBPP() == 1) { + return ((uint8_t)color == 0xff) ? 0 : 1; + } + return 0xff - (uint8_t)color; + } + if (GetBPP() == 1) { + return ((uint8_t)color == 0xff) ? 1 : 0; + } + return (uint8_t)color; + } + int palsize = (1 << GetBPP()); + for (int i = 0; i < palsize; i++) + if (m_pPalette[i] == color) { + return i; + } + return -1; +} +void CFX_DIBitmap::Clear(FX_DWORD color) { + if (!m_pBuffer) { + return; + } + switch (GetFormat()) { + case FXDIB_1bppMask: + FXSYS_memset(m_pBuffer, (color & 0xff000000) ? 0xff : 0, + m_Pitch * m_Height); + break; + case FXDIB_1bppRgb: { + int index = FindPalette(color); + FXSYS_memset(m_pBuffer, index ? 0xff : 0, m_Pitch * m_Height); + break; + } + case FXDIB_8bppMask: + FXSYS_memset(m_pBuffer, color >> 24, m_Pitch * m_Height); + break; + case FXDIB_8bppRgb: { + int index = FindPalette(color); + FXSYS_memset(m_pBuffer, index, m_Pitch * m_Height); + break; + } + case FXDIB_Rgb: + case FXDIB_Rgba: { + int a, r, g, b; + ArgbDecode(color, a, r, g, b); + if (r == g && g == b) { + FXSYS_memset(m_pBuffer, r, m_Pitch * m_Height); + } else { + int byte_pos = 0; + for (int col = 0; col < m_Width; col++) { + m_pBuffer[byte_pos++] = b; + m_pBuffer[byte_pos++] = g; + m_pBuffer[byte_pos++] = r; + } + for (int row = 1; row < m_Height; row++) { + FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch); + } + } + break; + } + case FXDIB_Rgb32: + case FXDIB_Argb: { + color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color); + for (int i = 0; i < m_Width; i++) { + ((FX_DWORD*)m_pBuffer)[i] = color; + } + for (int row = 1; row < m_Height; row++) { + FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch); + } + break; + } + default: + break; + } +} +void CFX_DIBSource::GetOverlapRect(int& dest_left, + int& dest_top, + int& width, + int& height, + int src_width, + int src_height, + int& src_left, + int& src_top, + const CFX_ClipRgn* pClipRgn) { + if (width == 0 || height == 0) { + return; + } + ASSERT(width > 0 && height > 0); + if (dest_left > m_Width || dest_top > m_Height) { + width = 0; + height = 0; + return; + } + int x_offset = dest_left - src_left; + int y_offset = dest_top - src_top; + FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height); + FX_RECT src_bound(0, 0, src_width, src_height); + src_rect.Intersect(src_bound); + FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset, + src_rect.right + x_offset, src_rect.bottom + y_offset); + FX_RECT dest_bound(0, 0, m_Width, m_Height); + dest_rect.Intersect(dest_bound); + if (pClipRgn) { + dest_rect.Intersect(pClipRgn->GetBox()); + } + dest_left = dest_rect.left; + dest_top = dest_rect.top; + src_left = dest_left - x_offset; + src_top = dest_top - y_offset; + width = dest_rect.right - dest_rect.left; + height = dest_rect.bottom - dest_rect.top; +} +FX_BOOL CFX_DIBitmap::TransferBitmap(int dest_left, + int dest_top, + int width, + int height, + const CFX_DIBSource* pSrcBitmap, + int src_left, + int src_top, + void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(), + pSrcBitmap->GetHeight(), src_left, src_top, NULL); + if (width == 0 || height == 0) { + return TRUE; + } + FXDIB_Format dest_format = GetFormat(); + FXDIB_Format src_format = pSrcBitmap->GetFormat(); + if (dest_format == src_format && !pIccTransform) { + if (GetBPP() == 1) { + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = m_pBuffer + (dest_top + row) * m_Pitch; + const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row); + for (int col = 0; col < width; col++) { + if (src_scan[(src_left + col) / 8] & + (1 << (7 - (src_left + col) % 8))) { + dest_scan[(dest_left + col) / 8] |= 1 + << (7 - (dest_left + col) % 8); + } else { + dest_scan[(dest_left + col) / 8] &= + ~(1 << (7 - (dest_left + col) % 8)); + } + } + } + } else { + int Bpp = GetBPP() / 8; + for (int row = 0; row < height; row++) { + uint8_t* dest_scan = + m_pBuffer + (dest_top + row) * m_Pitch + dest_left * Bpp; + const uint8_t* src_scan = + pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp; + FXSYS_memcpy(dest_scan, src_scan, width * Bpp); + } + } + } else { + if (m_pPalette) { + return FALSE; + } + if (m_bpp == 8) { + dest_format = FXDIB_8bppMask; + } + uint8_t* dest_buf = + m_pBuffer + dest_top * m_Pitch + dest_left * GetBPP() / 8; + FX_DWORD* d_plt = NULL; + if (!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height, + pSrcBitmap, src_left, src_top, d_plt, pIccTransform)) { + return FALSE; + } + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::TransferMask(int dest_left, + int dest_top, + int width, + int height, + const CFX_DIBSource* pMask, + FX_DWORD color, + int src_left, + int src_top, + int alpha_flag, + void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + ASSERT(HasAlpha() && (m_bpp >= 24)); + ASSERT(pMask->IsAlphaMask()); + if (!HasAlpha() || !pMask->IsAlphaMask() || m_bpp < 24) { + return FALSE; + } + GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(), + pMask->GetHeight(), src_left, src_top, NULL); + if (width == 0 || height == 0) { + return TRUE; + } + int src_bpp = pMask->GetBPP(); + int alpha; + FX_DWORD dst_color; + if (alpha_flag >> 8) { + alpha = alpha_flag & 0xff; + dst_color = FXCMYK_TODIB(color); + } else { + alpha = FXARGB_A(color); + dst_color = FXARGB_TODIB(color); + } + uint8_t* color_p = (uint8_t*)&dst_color; + if (pIccTransform && CFX_GEModule::Get()->GetCodecModule() && + CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) { + ICodec_IccModule* pIccModule = + CFX_GEModule::Get()->GetCodecModule()->GetIccModule(); + pIccModule->TranslateScanline(pIccTransform, color_p, color_p, 1); + } else { + if (alpha_flag >> 8 && !IsCmykImage()) { + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), + FXSYS_GetYValue(color), FXSYS_GetKValue(color), + color_p[2], color_p[1], color_p[0]); + } else if (!(alpha_flag >> 8) && IsCmykImage()) { + return FALSE; + } + } + if (!IsCmykImage()) { + color_p[3] = (uint8_t)alpha; + } + if (GetFormat() == FXDIB_Argb) { + for (int row = 0; row < height; row++) { + FX_DWORD* dest_pos = + (FX_DWORD*)(m_pBuffer + (dest_top + row) * m_Pitch + dest_left * 4); + const uint8_t* src_scan = pMask->GetScanline(src_top + row); + if (src_bpp == 1) { + for (int col = 0; col < width; col++) { + int src_bitpos = src_left + col; + if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) { + *dest_pos = dst_color; + } else { + *dest_pos = 0; + } + dest_pos++; + } + } else { + src_scan += src_left; + dst_color = FXARGB_TODIB(dst_color); + dst_color &= 0xffffff; + for (int col = 0; col < width; col++) { + FXARGB_SETDIB(dest_pos++, + dst_color | ((alpha * (*src_scan++) / 255) << 24)); + } + } + } + } else { + int comps = m_bpp / 8; + for (int row = 0; row < height; row++) { + uint8_t* dest_color_pos = + m_pBuffer + (dest_top + row) * m_Pitch + dest_left * comps; + uint8_t* dest_alpha_pos = + (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left; + const uint8_t* src_scan = pMask->GetScanline(src_top + row); + if (src_bpp == 1) { + for (int col = 0; col < width; col++) { + int src_bitpos = src_left + col; + if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) { + FXSYS_memcpy(dest_color_pos, color_p, comps); + *dest_alpha_pos = 0xff; + } else { + FXSYS_memset(dest_color_pos, 0, comps); + *dest_alpha_pos = 0; + } + dest_color_pos += comps; + dest_alpha_pos++; + } + } else { + src_scan += src_left; + for (int col = 0; col < width; col++) { + FXSYS_memcpy(dest_color_pos, color_p, comps); + dest_color_pos += comps; + *dest_alpha_pos++ = (alpha * (*src_scan++) / 255); + } + } + } + } + return TRUE; +} +void CFX_DIBSource::CopyPalette(const FX_DWORD* pSrc, FX_DWORD size) { + if (!pSrc || GetBPP() > 8) { + FX_Free(m_pPalette); + m_pPalette = NULL; + } else { + FX_DWORD pal_size = 1 << GetBPP(); + if (!m_pPalette) { + m_pPalette = FX_Alloc(FX_DWORD, pal_size); + } + if (pal_size > size) { + pal_size = size; + } + FXSYS_memcpy(m_pPalette, pSrc, pal_size * sizeof(FX_DWORD)); + } +} +void CFX_DIBSource::GetPalette(FX_DWORD* pal, int alpha) const { + ASSERT(GetBPP() <= 8 && !IsCmykImage()); + if (GetBPP() == 1) { + pal[0] = + ((m_pPalette ? m_pPalette[0] : 0xff000000) & 0xffffff) | (alpha << 24); + pal[1] = + ((m_pPalette ? m_pPalette[1] : 0xffffffff) & 0xffffff) | (alpha << 24); + return; + } + if (m_pPalette) { + for (int i = 0; i < 256; i++) { + pal[i] = (m_pPalette[i] & 0x00ffffff) | (alpha << 24); + } + } else { + for (int i = 0; i < 256; i++) { + pal[i] = (i * 0x10101) | (alpha << 24); + } + } +} +CFX_DIBitmap* CFX_DIBSource::GetAlphaMask(const FX_RECT* pClip) const { + ASSERT(GetFormat() == FXDIB_Argb); + FX_RECT rect(0, 0, m_Width, m_Height); + if (pClip) { + rect.Intersect(*pClip); + if (rect.IsEmpty()) { + return NULL; + } + } + CFX_DIBitmap* pMask = new CFX_DIBitmap; + if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask)) { + delete pMask; + return NULL; + } + for (int row = rect.top; row < rect.bottom; row++) { + const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3; + uint8_t* dest_scan = (uint8_t*)pMask->GetScanline(row - rect.top); + for (int col = rect.left; col < rect.right; col++) { + *dest_scan++ = *src_scan; + src_scan += 4; + } + } + return pMask; +} +FX_BOOL CFX_DIBSource::CopyAlphaMask(const CFX_DIBSource* pAlphaMask, + const FX_RECT* pClip) { + if (!HasAlpha() || GetFormat() == FXDIB_Argb) { + return FALSE; + } + if (pAlphaMask) { + FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height); + if (pClip) { + rect.Intersect(*pClip); + if (rect.IsEmpty() || rect.Width() != m_Width || + rect.Height() != m_Height) { + return FALSE; + } + } else { + if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height) { + return FALSE; + } + } + for (int row = 0; row < m_Height; row++) + FXSYS_memcpy((void*)m_pAlphaMask->GetScanline(row), + pAlphaMask->GetScanline(row + rect.top) + rect.left, + m_pAlphaMask->m_Pitch); + } else { + m_pAlphaMask->Clear(0xff000000); + } + return TRUE; +} +const int g_ChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3}; +FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, + const CFX_DIBSource* pSrcBitmap, + FXDIB_Channel srcChannel) { + if (!m_pBuffer) { + return FALSE; + } + CFX_DIBSource* pSrcClone = (CFX_DIBSource*)pSrcBitmap; + CFX_DIBitmap* pDst = this; + int destOffset, srcOffset; + if (srcChannel == FXDIB_Alpha) { + if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask()) { + return FALSE; + } + if (pSrcBitmap->GetBPP() == 1) { + pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask); + if (!pSrcClone) { + return FALSE; + } + } + if (pSrcBitmap->GetFormat() == FXDIB_Argb) { + srcOffset = 3; + } else { + srcOffset = 0; + } + } else { + if (pSrcBitmap->IsAlphaMask()) { + return FALSE; + } + if (pSrcBitmap->GetBPP() < 24) { + if (pSrcBitmap->IsCmykImage()) { + pSrcClone = pSrcBitmap->CloneConvert( + (FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x20)); + } else { + pSrcClone = pSrcBitmap->CloneConvert( + (FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x18)); + } + if (!pSrcClone) { + return FALSE; + } + } + srcOffset = g_ChannelOffset[srcChannel]; + } + if (destChannel == FXDIB_Alpha) { + if (IsAlphaMask()) { + if (!ConvertFormat(FXDIB_8bppMask)) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + destOffset = 0; + } else { + destOffset = 0; + if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + if (GetFormat() == FXDIB_Argb) { + destOffset = 3; + } + } + } else { + if (IsAlphaMask()) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + if (GetBPP() < 24) { + if (HasAlpha()) { + if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) { +#else + } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) { +#endif + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + } + destOffset = g_ChannelOffset[destChannel]; + } + if (srcChannel == FXDIB_Alpha && pSrcClone->m_pAlphaMask) { + CFX_DIBitmap* pAlphaMask = pSrcClone->m_pAlphaMask; + if (pSrcClone->GetWidth() != m_Width || + pSrcClone->GetHeight() != m_Height) { + if (pAlphaMask) { + pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height); + if (!pAlphaMask) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + } + } + if (pSrcClone != pSrcBitmap) { + pSrcClone->m_pAlphaMask = NULL; + delete pSrcClone; + } + pSrcClone = pAlphaMask; + srcOffset = 0; + } else if (pSrcClone->GetWidth() != m_Width || + pSrcClone->GetHeight() != m_Height) { + CFX_DIBitmap* pSrcMatched = pSrcClone->StretchTo(m_Width, m_Height); + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + if (!pSrcMatched) { + return FALSE; + } + pSrcClone = pSrcMatched; + } + if (destChannel == FXDIB_Alpha && m_pAlphaMask) { + pDst = m_pAlphaMask; + destOffset = 0; + } + int srcBytes = pSrcClone->GetBPP() / 8; + int destBytes = pDst->GetBPP() / 8; + for (int row = 0; row < m_Height; row++) { + uint8_t* dest_pos = (uint8_t*)pDst->GetScanline(row) + destOffset; + const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset; + for (int col = 0; col < m_Width; col++) { + *dest_pos = *src_pos; + dest_pos += destBytes; + src_pos += srcBytes; + } + } + if (pSrcClone != pSrcBitmap && pSrcClone != pSrcBitmap->m_pAlphaMask) { + delete pSrcClone; + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value) { + if (!m_pBuffer) { + return FALSE; + } + int destOffset; + if (destChannel == FXDIB_Alpha) { + if (IsAlphaMask()) { + if (!ConvertFormat(FXDIB_8bppMask)) { + return FALSE; + } + destOffset = 0; + } else { + destOffset = 0; + if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) { + return FALSE; + } + if (GetFormat() == FXDIB_Argb) { + destOffset = 3; + } + } + } else { + if (IsAlphaMask()) { + return FALSE; + } + if (GetBPP() < 24) { + if (HasAlpha()) { + if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) { + return FALSE; + } +#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ + } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) { +#else + } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) { +#endif + return FALSE; + } + } + destOffset = g_ChannelOffset[destChannel]; + } + int Bpp = GetBPP() / 8; + if (Bpp == 1) { + FXSYS_memset(m_pBuffer, value, m_Height * m_Pitch); + return TRUE; + } + if (destChannel == FXDIB_Alpha && m_pAlphaMask) { + FXSYS_memset(m_pAlphaMask->GetBuffer(), value, + m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch()); + return TRUE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* scan_line = m_pBuffer + row * m_Pitch + destOffset; + for (int col = 0; col < m_Width; col++) { + *scan_line = value; + scan_line += Bpp; + } + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::MultiplyAlpha(const CFX_DIBSource* pSrcBitmap) { + if (!m_pBuffer) { + return FALSE; + } + ASSERT(pSrcBitmap->IsAlphaMask()); + if (!pSrcBitmap->IsAlphaMask()) { + return FALSE; + } + if (!IsAlphaMask() && !HasAlpha()) { + return LoadChannel(FXDIB_Alpha, pSrcBitmap, FXDIB_Alpha); + } + CFX_DIBitmap* pSrcClone = (CFX_DIBitmap*)pSrcBitmap; + if (pSrcBitmap->GetWidth() != m_Width || + pSrcBitmap->GetHeight() != m_Height) { + pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height); + if (!pSrcClone) { + return FALSE; + } + } + if (IsAlphaMask()) { + if (!ConvertFormat(FXDIB_8bppMask)) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* dest_scan = m_pBuffer + m_Pitch * row; + uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row; + if (pSrcClone->GetBPP() == 1) { + for (int col = 0; col < m_Width; col++) { + if (!((1 << (7 - col % 8)) & src_scan[col / 8])) { + dest_scan[col] = 0; + } + } + } else { + for (int col = 0; col < m_Width; col++) { + *dest_scan = (*dest_scan) * src_scan[col] / 255; + dest_scan++; + } + } + } + } else { + if (GetFormat() == FXDIB_Argb) { + if (pSrcClone->GetBPP() == 1) { + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return FALSE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* dest_scan = m_pBuffer + m_Pitch * row + 3; + uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row; + for (int col = 0; col < m_Width; col++) { + *dest_scan = (*dest_scan) * src_scan[col] / 255; + dest_scan += 4; + } + } + } else { + m_pAlphaMask->MultiplyAlpha(pSrcClone); + } + } + if (pSrcClone != pSrcBitmap) { + delete pSrcClone; + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::GetGrayData(void* pIccTransform) { + if (!m_pBuffer) { + return FALSE; + } + switch (GetFormat()) { + case FXDIB_1bppRgb: { + if (!m_pPalette) { + return FALSE; + } + uint8_t gray[2]; + for (int i = 0; i < 2; i++) { + int r = (uint8_t)(m_pPalette[i] >> 16); + int g = (uint8_t)(m_pPalette[i] >> 8); + int b = (uint8_t)m_pPalette[i]; + gray[i] = (uint8_t)FXRGB2GRAY(r, g, b); + } + CFX_DIBitmap* pMask = new CFX_DIBitmap; + if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) { + delete pMask; + return FALSE; + } + FXSYS_memset(pMask->GetBuffer(), gray[0], pMask->GetPitch() * m_Height); + for (int row = 0; row < m_Height; row++) { + uint8_t* src_pos = m_pBuffer + row * m_Pitch; + uint8_t* dest_pos = (uint8_t*)pMask->GetScanline(row); + for (int col = 0; col < m_Width; col++) { + if (src_pos[col / 8] & (1 << (7 - col % 8))) { + *dest_pos = gray[1]; + } + dest_pos++; + } + } + TakeOver(pMask); + delete pMask; + break; + } + case FXDIB_8bppRgb: { + if (!m_pPalette) { + return FALSE; + } + uint8_t gray[256]; + for (int i = 0; i < 256; i++) { + int r = (uint8_t)(m_pPalette[i] >> 16); + int g = (uint8_t)(m_pPalette[i] >> 8); + int b = (uint8_t)m_pPalette[i]; + gray[i] = (uint8_t)FXRGB2GRAY(r, g, b); + } + CFX_DIBitmap* pMask = new CFX_DIBitmap; + if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) { + delete pMask; + return FALSE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch(); + uint8_t* src_pos = m_pBuffer + row * m_Pitch; + for (int col = 0; col < m_Width; col++) { + *dest_pos++ = gray[*src_pos++]; + } + } + TakeOver(pMask); + delete pMask; + break; + } + case FXDIB_Rgb: { + CFX_DIBitmap* pMask = new CFX_DIBitmap; + if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) { + delete pMask; + return FALSE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* src_pos = m_pBuffer + row * m_Pitch; + uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch(); + for (int col = 0; col < m_Width; col++) { + *dest_pos++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos); + src_pos += 3; + } + } + TakeOver(pMask); + delete pMask; + break; + } + case FXDIB_Rgb32: { + CFX_DIBitmap* pMask = new CFX_DIBitmap; + if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) { + delete pMask; + return FALSE; + } + for (int row = 0; row < m_Height; row++) { + uint8_t* src_pos = m_pBuffer + row * m_Pitch; + uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch(); + for (int col = 0; col < m_Width; col++) { + *dest_pos++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos); + src_pos += 4; + } + } + TakeOver(pMask); + delete pMask; + break; + } + default: + return FALSE; + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::MultiplyAlpha(int alpha) { + if (!m_pBuffer) { + return FALSE; + } + switch (GetFormat()) { + case FXDIB_1bppMask: + if (!ConvertFormat(FXDIB_8bppMask)) { + return FALSE; + } + MultiplyAlpha(alpha); + break; + case FXDIB_8bppMask: { + for (int row = 0; row < m_Height; row++) { + uint8_t* scan_line = m_pBuffer + row * m_Pitch; + for (int col = 0; col < m_Width; col++) { + scan_line[col] = scan_line[col] * alpha / 255; + } + } + break; + } + case FXDIB_Argb: { + for (int row = 0; row < m_Height; row++) { + uint8_t* scan_line = m_pBuffer + row * m_Pitch + 3; + for (int col = 0; col < m_Width; col++) { + *scan_line = (*scan_line) * alpha / 255; + scan_line += 4; + } + } + break; + } + default: + if (HasAlpha()) { + m_pAlphaMask->MultiplyAlpha(alpha); + } else if (IsCmykImage()) { + if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) { + return FALSE; + } + m_pAlphaMask->MultiplyAlpha(alpha); + } else { + if (!ConvertFormat(FXDIB_Argb)) { + return FALSE; + } + MultiplyAlpha(alpha); + } + break; + } + return TRUE; +} +FX_DWORD CFX_DIBitmap::GetPixel(int x, int y) const { + if (!m_pBuffer) { + return 0; + } + uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8; + switch (GetFormat()) { + case FXDIB_1bppMask: { + if ((*pos) & (1 << (7 - x % 8))) { + return 0xff000000; + } + return 0; + } + case FXDIB_1bppRgb: { + if ((*pos) & (1 << (7 - x % 8))) { + return m_pPalette ? m_pPalette[1] : 0xffffffff; + } + return m_pPalette ? m_pPalette[0] : 0xff000000; + } + case FXDIB_8bppMask: + return (*pos) << 24; + case FXDIB_8bppRgb: + return m_pPalette ? m_pPalette[*pos] : (0xff000000 | ((*pos) * 0x10101)); + case FXDIB_Rgb: + case FXDIB_Rgba: + case FXDIB_Rgb32: + return FXARGB_GETDIB(pos) | 0xff000000; + case FXDIB_Argb: + return FXARGB_GETDIB(pos); + default: + break; + } + return 0; +} +void CFX_DIBitmap::SetPixel(int x, int y, FX_DWORD color) { + if (!m_pBuffer) { + return; + } + if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) { + return; + } + uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8; + switch (GetFormat()) { + case FXDIB_1bppMask: + if (color >> 24) { + *pos |= 1 << (7 - x % 8); + } else { + *pos &= ~(1 << (7 - x % 8)); + } + break; + case FXDIB_1bppRgb: + if (m_pPalette) { + if (color == m_pPalette[1]) { + *pos |= 1 << (7 - x % 8); + } else { + *pos &= ~(1 << (7 - x % 8)); + } + } else { + if (color == 0xffffffff) { + *pos |= 1 << (7 - x % 8); + } else { + *pos &= ~(1 << (7 - x % 8)); + } + } + break; + case FXDIB_8bppMask: + *pos = (uint8_t)(color >> 24); + break; + case FXDIB_8bppRgb: { + if (m_pPalette) { + for (int i = 0; i < 256; i++) { + if (m_pPalette[i] == color) { + *pos = (uint8_t)i; + return; + } + } + *pos = 0; + } else { + *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color)); + } + break; + } + case FXDIB_Rgb: + case FXDIB_Rgb32: { + int alpha = FXARGB_A(color); + pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255; + pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255; + pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255; + break; + } + case FXDIB_Rgba: { + pos[0] = FXARGB_B(color); + pos[1] = FXARGB_G(color); + pos[2] = FXARGB_R(color); + break; + } + case FXDIB_Argb: + FXARGB_SETDIB(pos, color); + break; + default: + break; + } +} +void CFX_DIBitmap::DownSampleScanline(int line, + uint8_t* dest_scan, + int dest_bpp, + int dest_width, + FX_BOOL bFlipX, + int clip_left, + int clip_width) const { + if (!m_pBuffer) { + return; + } + int src_Bpp = m_bpp / 8; + uint8_t* scanline = m_pBuffer + line * m_Pitch; + if (src_Bpp == 0) { + for (int i = 0; i < clip_width; i++) { + FX_DWORD dest_x = clip_left + i; + FX_DWORD src_x = dest_x * m_Width / dest_width; + if (bFlipX) { + src_x = m_Width - src_x - 1; + } + src_x %= m_Width; + dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0; + } + } else if (src_Bpp == 1) { + for (int i = 0; i < clip_width; i++) { + FX_DWORD dest_x = clip_left + i; + FX_DWORD src_x = dest_x * m_Width / dest_width; + if (bFlipX) { + src_x = m_Width - src_x - 1; + } + src_x %= m_Width; + int dest_pos = i; + if (m_pPalette) { + if (!IsCmykImage()) { + dest_pos *= 3; + FX_ARGB argb = m_pPalette[scanline[src_x]]; + dest_scan[dest_pos] = FXARGB_B(argb); + dest_scan[dest_pos + 1] = FXARGB_G(argb); + dest_scan[dest_pos + 2] = FXARGB_R(argb); + } else { + dest_pos *= 4; + FX_CMYK cmyk = m_pPalette[scanline[src_x]]; + dest_scan[dest_pos] = FXSYS_GetCValue(cmyk); + dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk); + dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk); + dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk); + } + } else { + dest_scan[dest_pos] = scanline[src_x]; + } + } + } else { + for (int i = 0; i < clip_width; i++) { + FX_DWORD dest_x = clip_left + i; + FX_DWORD src_x = + bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp + : (dest_x * m_Width / dest_width) * src_Bpp; + src_x %= m_Width * src_Bpp; + int dest_pos = i * src_Bpp; + for (int b = 0; b < src_Bpp; b++) { + dest_scan[dest_pos + b] = scanline[src_x + b]; + } + } + } +} +FX_BOOL CFX_DIBitmap::ConvertColorScale(FX_DWORD forecolor, + FX_DWORD backcolor) { + ASSERT(!IsAlphaMask()); + if (!m_pBuffer || IsAlphaMask()) { + return FALSE; + } + int fc, fm, fy, fk, bc, bm, by, bk; + int fr, fg, fb, br, bg, bb; + FX_BOOL isCmykImage = IsCmykImage(); + if (isCmykImage) { + fc = FXSYS_GetCValue(forecolor); + fm = FXSYS_GetMValue(forecolor); + fy = FXSYS_GetYValue(forecolor); + fk = FXSYS_GetKValue(forecolor); + bc = FXSYS_GetCValue(backcolor); + bm = FXSYS_GetMValue(backcolor); + by = FXSYS_GetYValue(backcolor); + bk = FXSYS_GetKValue(backcolor); + } else { + fr = FXSYS_GetRValue(forecolor); + fg = FXSYS_GetGValue(forecolor); + fb = FXSYS_GetBValue(forecolor); + br = FXSYS_GetRValue(backcolor); + bg = FXSYS_GetGValue(backcolor); + bb = FXSYS_GetBValue(backcolor); + } + if (m_bpp <= 8) { + if (isCmykImage) { + if (forecolor == 0xff && backcolor == 0 && !m_pPalette) { + return TRUE; + } + } else if (forecolor == 0 && backcolor == 0xffffff && !m_pPalette) { + return TRUE; + } + if (!m_pPalette) { + BuildPalette(); + } + int size = 1 << m_bpp; + if (isCmykImage) { + for (int i = 0; i < size; i++) { + uint8_t b, g, r; + AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette[i]), + FXSYS_GetMValue(m_pPalette[i]), + FXSYS_GetYValue(m_pPalette[i]), + FXSYS_GetKValue(m_pPalette[i]), r, g, b); + int gray = 255 - FXRGB2GRAY(r, g, b); + m_pPalette[i] = CmykEncode( + bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255, + by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255); + } + } else { + for (int i = 0; i < size; i++) { + int gray = FXRGB2GRAY(FXARGB_R(m_pPalette[i]), FXARGB_G(m_pPalette[i]), + FXARGB_B(m_pPalette[i])); + m_pPalette[i] = FXARGB_MAKE(0xff, br + (fr - br) * gray / 255, + bg + (fg - bg) * gray / 255, + bb + (fb - bb) * gray / 255); + } + } + return TRUE; + } + if (isCmykImage) { + if (forecolor == 0xff && backcolor == 0x00) { + for (int row = 0; row < m_Height; row++) { + uint8_t* scanline = m_pBuffer + row * m_Pitch; + for (int col = 0; col < m_Width; col++) { + uint8_t b, g, r; + AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3], + r, g, b); + *scanline++ = 0; + *scanline++ = 0; + *scanline++ = 0; + *scanline++ = 255 - FXRGB2GRAY(r, g, b); + } + } + return TRUE; + } + } else if (forecolor == 0 && backcolor == 0xffffff) { + for (int row = 0; row < m_Height; row++) { + uint8_t* scanline = m_pBuffer + row * m_Pitch; + int gap = m_bpp / 8 - 2; + for (int col = 0; col < m_Width; col++) { + int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]); + *scanline++ = gray; + *scanline++ = gray; + *scanline = gray; + scanline += gap; + } + } + return TRUE; + } + if (isCmykImage) { + for (int row = 0; row < m_Height; row++) { + uint8_t* scanline = m_pBuffer + row * m_Pitch; + for (int col = 0; col < m_Width; col++) { + uint8_t b, g, r; + AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3], + r, g, b); + int gray = 255 - FXRGB2GRAY(r, g, b); + *scanline++ = bc + (fc - bc) * gray / 255; + *scanline++ = bm + (fm - bm) * gray / 255; + *scanline++ = by + (fy - by) * gray / 255; + *scanline++ = bk + (fk - bk) * gray / 255; + } + } + } else { + for (int row = 0; row < m_Height; row++) { + uint8_t* scanline = m_pBuffer + row * m_Pitch; + int gap = m_bpp / 8 - 2; + for (int col = 0; col < m_Width; col++) { + int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]); + *scanline++ = bb + (fb - bb) * gray / 255; + *scanline++ = bg + (fg - bg) * gray / 255; + *scanline = br + (fr - br) * gray / 255; + scanline += gap; + } + } + } + return TRUE; +} +FX_BOOL CFX_DIBitmap::DitherFS(const FX_DWORD* pPalette, + int pal_size, + const FX_RECT* pRect) { + if (!m_pBuffer) { + return FALSE; + } + if (m_bpp != 8 && m_pPalette && m_AlphaFlag != 0) { + return FALSE; + } + if (m_Width < 4 && m_Height < 4) { + return FALSE; + } + FX_RECT rect(0, 0, m_Width, m_Height); + if (pRect) { + rect.Intersect(*pRect); + } + uint8_t translate[256]; + for (int i = 0; i < 256; i++) { + int err2 = 65536; + for (int j = 0; j < pal_size; j++) { + uint8_t entry = (uint8_t)pPalette[j]; + int err = (int)entry - i; + if (err * err < err2) { + err2 = err * err; + translate[i] = entry; + } + } + } + for (int row = rect.top; row < rect.bottom; row++) { + uint8_t* scan = m_pBuffer + row * m_Pitch; + uint8_t* next_scan = m_pBuffer + (row + 1) * m_Pitch; + for (int col = rect.left; col < rect.right; col++) { + int src_pixel = scan[col]; + int dest_pixel = translate[src_pixel]; + scan[col] = (uint8_t)dest_pixel; + int error = -dest_pixel + src_pixel; + if (col < rect.right - 1) { + int src = scan[col + 1]; + src += error * 7 / 16; + if (src > 255) { + scan[col + 1] = 255; + } else if (src < 0) { + scan[col + 1] = 0; + } else { + scan[col + 1] = src; + } + } + if (col < rect.right - 1 && row < rect.bottom - 1) { + int src = next_scan[col + 1]; + src += error * 1 / 16; + if (src > 255) { + next_scan[col + 1] = 255; + } else if (src < 0) { + next_scan[col + 1] = 0; + } else { + next_scan[col + 1] = src; + } + } + if (row < rect.bottom - 1) { + int src = next_scan[col]; + src += error * 5 / 16; + if (src > 255) { + next_scan[col] = 255; + } else if (src < 0) { + next_scan[col] = 0; + } else { + next_scan[col] = src; + } + } + if (col > rect.left && row < rect.bottom - 1) { + int src = next_scan[col - 1]; + src += error * 3 / 16; + if (src > 255) { + next_scan[col - 1] = 255; + } else if (src < 0) { + next_scan[col - 1] = 0; + } else { + next_scan[col - 1] = src; + } + } + } + } + return TRUE; +} +CFX_DIBitmap* CFX_DIBSource::FlipImage(FX_BOOL bXFlip, FX_BOOL bYFlip) const { + CFX_DIBitmap* pFlipped = new CFX_DIBitmap; + if (!pFlipped->Create(m_Width, m_Height, GetFormat())) { + delete pFlipped; + return NULL; + } + pFlipped->CopyPalette(m_pPalette); + uint8_t* pDestBuffer = pFlipped->GetBuffer(); + int Bpp = m_bpp / 8; + for (int row = 0; row < m_Height; row++) { + const uint8_t* src_scan = GetScanline(row); + uint8_t* dest_scan = + pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row); + if (!bXFlip) { + FXSYS_memcpy(dest_scan, src_scan, m_Pitch); + continue; + } + if (m_bpp == 1) { + FXSYS_memset(dest_scan, 0, m_Pitch); + for (int col = 0; col < m_Width; col++) + if (src_scan[col / 8] & (1 << (7 - col % 8))) { + int dest_col = m_Width - col - 1; + dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8)); + } + } else { + dest_scan += (m_Width - 1) * Bpp; + if (Bpp == 1) { + for (int col = 0; col < m_Width; col++) { + *dest_scan = *src_scan; + dest_scan--; + src_scan++; + } + } else if (Bpp == 3) { + for (int col = 0; col < m_Width; col++) { + dest_scan[0] = src_scan[0]; + dest_scan[1] = src_scan[1]; + dest_scan[2] = src_scan[2]; + dest_scan -= 3; + src_scan += 3; + } + } else { + ASSERT(Bpp == 4); + for (int col = 0; col < m_Width; col++) { + *(FX_DWORD*)dest_scan = *(FX_DWORD*)src_scan; + dest_scan -= 4; + src_scan += 4; + } + } + } + } + if (m_pAlphaMask) { + pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer(); + FX_DWORD dest_pitch = pFlipped->m_pAlphaMask->GetPitch(); + for (int row = 0; row < m_Height; row++) { + const uint8_t* src_scan = m_pAlphaMask->GetScanline(row); + uint8_t* dest_scan = + pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row); + if (!bXFlip) { + FXSYS_memcpy(dest_scan, src_scan, dest_pitch); + continue; + } + dest_scan += (m_Width - 1); + for (int col = 0; col < m_Width; col++) { + *dest_scan = *src_scan; + dest_scan--; + src_scan++; + } + } + } + return pFlipped; +} +CFX_DIBExtractor::CFX_DIBExtractor(const CFX_DIBSource* pSrc) { + m_pBitmap = NULL; + if (pSrc->GetBuffer()) { + m_pBitmap = new CFX_DIBitmap; + if (!m_pBitmap->Create(pSrc->GetWidth(), pSrc->GetHeight(), + pSrc->GetFormat(), pSrc->GetBuffer())) { + delete m_pBitmap; + m_pBitmap = NULL; + return; + } + m_pBitmap->CopyPalette(pSrc->GetPalette()); + m_pBitmap->CopyAlphaMask(pSrc->m_pAlphaMask); + } else { + m_pBitmap = pSrc->Clone(); + } +} +CFX_DIBExtractor::~CFX_DIBExtractor() { + delete m_pBitmap; +} +CFX_FilteredDIB::CFX_FilteredDIB() { + m_pScanline = NULL; + m_pSrc = NULL; +} +CFX_FilteredDIB::~CFX_FilteredDIB() { + if (m_bAutoDropSrc) { + delete m_pSrc; + } + FX_Free(m_pScanline); +} +void CFX_FilteredDIB::LoadSrc(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc) { + m_pSrc = pSrc; + m_bAutoDropSrc = bAutoDropSrc; + m_Width = pSrc->GetWidth(); + m_Height = pSrc->GetHeight(); + FXDIB_Format format = GetDestFormat(); + m_bpp = (uint8_t)format; + m_AlphaFlag = (uint8_t)(format >> 8); + m_Pitch = (m_Width * (format & 0xff) + 31) / 32 * 4; + m_pPalette = GetDestPalette(); + m_pScanline = FX_Alloc(uint8_t, m_Pitch); +} +const uint8_t* CFX_FilteredDIB::GetScanline(int line) const { + TranslateScanline(m_pScanline, m_pSrc->GetScanline(line)); + return m_pScanline; +} +void CFX_FilteredDIB::DownSampleScanline(int line, + uint8_t* dest_scan, + int dest_bpp, + int dest_width, + FX_BOOL bFlipX, + int clip_left, + int clip_width) const { + m_pSrc->DownSampleScanline(line, dest_scan, dest_bpp, dest_width, bFlipX, + clip_left, clip_width); + TranslateDownSamples(dest_scan, dest_scan, clip_width, dest_bpp); +} +CFX_ImageRenderer::CFX_ImageRenderer() { + m_Status = 0; + m_pTransformer = NULL; + m_bRgbByteOrder = FALSE; + m_BlendType = FXDIB_BLEND_NORMAL; +} +CFX_ImageRenderer::~CFX_ImageRenderer() { + delete m_pTransformer; +} +FX_BOOL CFX_ImageRenderer::Start(CFX_DIBitmap* pDevice, + const CFX_ClipRgn* pClipRgn, + const CFX_DIBSource* pSource, + int bitmap_alpha, + FX_DWORD mask_color, + const CFX_Matrix* pMatrix, + FX_DWORD dib_flags, + FX_BOOL bRgbByteOrder, + int alpha_flag, + void* pIccTransform, + int blend_type) { + m_Matrix = *pMatrix; + CFX_FloatRect image_rect_f = m_Matrix.GetUnitRect(); + FX_RECT image_rect = image_rect_f.GetOutterRect(); + m_ClipBox = pClipRgn ? pClipRgn->GetBox() : FX_RECT(0, 0, pDevice->GetWidth(), + pDevice->GetHeight()); + m_ClipBox.Intersect(image_rect); + if (m_ClipBox.IsEmpty()) { + return FALSE; + } + m_pDevice = pDevice; + m_pClipRgn = pClipRgn; + m_MaskColor = mask_color; + m_BitmapAlpha = bitmap_alpha; + m_Matrix = *pMatrix; + m_Flags = dib_flags; + m_AlphaFlag = alpha_flag; + m_pIccTransform = pIccTransform; + m_bRgbByteOrder = bRgbByteOrder; + m_BlendType = blend_type; + FX_BOOL ret = TRUE; + if ((FXSYS_fabs(m_Matrix.b) >= 0.5f || m_Matrix.a == 0) || + (FXSYS_fabs(m_Matrix.c) >= 0.5f || m_Matrix.d == 0)) { + if (FXSYS_fabs(m_Matrix.a) < FXSYS_fabs(m_Matrix.b) / 20 && + FXSYS_fabs(m_Matrix.d) < FXSYS_fabs(m_Matrix.c) / 20 && + FXSYS_fabs(m_Matrix.a) < 0.5f && FXSYS_fabs(m_Matrix.d) < 0.5f) { + int dest_width = image_rect.Width(); + int dest_height = image_rect.Height(); + FX_RECT bitmap_clip = m_ClipBox; + bitmap_clip.Offset(-image_rect.left, -image_rect.top); + bitmap_clip = FXDIB_SwapClipBox(bitmap_clip, dest_width, dest_height, + m_Matrix.c > 0, m_Matrix.b < 0); + m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox, + TRUE, m_Matrix.c > 0, m_Matrix.b < 0, m_bRgbByteOrder, + alpha_flag, pIccTransform, m_BlendType); + if (!m_Stretcher.Start(&m_Composer, pSource, dest_height, dest_width, + bitmap_clip, dib_flags)) { + return FALSE; + } + m_Status = 1; + return TRUE; + } + m_Status = 2; + m_pTransformer = new CFX_ImageTransformer; + m_pTransformer->Start(pSource, &m_Matrix, dib_flags, &m_ClipBox); + return TRUE; + } + int dest_width = image_rect.Width(); + if (m_Matrix.a < 0) { + dest_width = -dest_width; + } + int dest_height = image_rect.Height(); + if (m_Matrix.d > 0) { + dest_height = -dest_height; + } + if (dest_width == 0 || dest_height == 0) { + return FALSE; + } + FX_RECT bitmap_clip = m_ClipBox; + bitmap_clip.Offset(-image_rect.left, -image_rect.top); + m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox, + FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag, + pIccTransform, m_BlendType); + m_Status = 1; + ret = m_Stretcher.Start(&m_Composer, pSource, dest_width, dest_height, + bitmap_clip, dib_flags); + return ret; +} +FX_BOOL CFX_ImageRenderer::Continue(IFX_Pause* pPause) { + if (m_Status == 1) { + return m_Stretcher.Continue(pPause); + } + if (m_Status == 2) { + if (m_pTransformer->Continue(pPause)) { + return TRUE; + } + CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach(); + if (!pBitmap) { + return FALSE; + } + if (!pBitmap->GetBuffer()) { + delete pBitmap; + return FALSE; + } + if (pBitmap->IsAlphaMask()) { + if (m_BitmapAlpha != 255) { + if (m_AlphaFlag >> 8) { + m_AlphaFlag = + (((uint8_t)((m_AlphaFlag & 0xff) * m_BitmapAlpha / 255)) | + ((m_AlphaFlag >> 8) << 8)); + } else { + m_MaskColor = FXARGB_MUL_ALPHA(m_MaskColor, m_BitmapAlpha); + } + } + m_pDevice->CompositeMask(m_pTransformer->m_ResultLeft, + m_pTransformer->m_ResultTop, pBitmap->GetWidth(), + pBitmap->GetHeight(), pBitmap, m_MaskColor, 0, 0, + m_BlendType, m_pClipRgn, m_bRgbByteOrder, + m_AlphaFlag, m_pIccTransform); + } else { + if (m_BitmapAlpha != 255) { + pBitmap->MultiplyAlpha(m_BitmapAlpha); + } + m_pDevice->CompositeBitmap( + m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop, + pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, 0, 0, m_BlendType, + m_pClipRgn, m_bRgbByteOrder, m_pIccTransform); + } + delete pBitmap; + return FALSE; + } + return FALSE; +} +CFX_BitmapStorer::CFX_BitmapStorer() { + m_pBitmap = NULL; +} +CFX_BitmapStorer::~CFX_BitmapStorer() { + delete m_pBitmap; +} +CFX_DIBitmap* CFX_BitmapStorer::Detach() { + CFX_DIBitmap* pBitmap = m_pBitmap; + m_pBitmap = NULL; + return pBitmap; +} +void CFX_BitmapStorer::Replace(CFX_DIBitmap* pBitmap) { + delete m_pBitmap; + m_pBitmap = pBitmap; +} +void CFX_BitmapStorer::ComposeScanline(int line, + const uint8_t* scanline, + const uint8_t* scan_extra_alpha) { + uint8_t* dest_buf = (uint8_t*)m_pBitmap->GetScanline(line); + uint8_t* dest_alpha_buf = + m_pBitmap->m_pAlphaMask + ? (uint8_t*)m_pBitmap->m_pAlphaMask->GetScanline(line) + : NULL; + if (dest_buf) { + FXSYS_memcpy(dest_buf, scanline, m_pBitmap->GetPitch()); + } + if (dest_alpha_buf) { + FXSYS_memcpy(dest_alpha_buf, scan_extra_alpha, + m_pBitmap->m_pAlphaMask->GetPitch()); + } +} +FX_BOOL CFX_BitmapStorer::SetInfo(int width, + int height, + FXDIB_Format src_format, + FX_DWORD* pSrcPalette) { + m_pBitmap = new CFX_DIBitmap; + if (!m_pBitmap->Create(width, height, src_format)) { + delete m_pBitmap; + m_pBitmap = NULL; + return FALSE; + } + if (pSrcPalette) { + m_pBitmap->CopyPalette(pSrcPalette); + } + return TRUE; +} diff --git a/core/fxge/dib/fx_dib_transform.cpp b/core/fxge/dib/fx_dib_transform.cpp new file mode 100644 index 0000000000..dc6fb93c75 --- /dev/null +++ b/core/fxge/dib/fx_dib_transform.cpp @@ -0,0 +1,948 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxge/dib/dib_int.h" + +#include "core/include/fxge/fx_dib.h" + +namespace { + +uint8_t bilinear_interpol(const uint8_t* buf, + int row_offset_l, + int row_offset_r, + int src_col_l, + int src_col_r, + int res_x, + int res_y, + int bpp, + int c_offset) { + int i_resx = 255 - res_x; + int col_bpp_l = src_col_l * bpp; + int col_bpp_r = src_col_r * bpp; + const uint8_t* buf_u = buf + row_offset_l + c_offset; + const uint8_t* buf_d = buf + row_offset_r + c_offset; + const uint8_t* src_pos0 = buf_u + col_bpp_l; + const uint8_t* src_pos1 = buf_u + col_bpp_r; + const uint8_t* src_pos2 = buf_d + col_bpp_l; + const uint8_t* src_pos3 = buf_d + col_bpp_r; + uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8; + uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8; + return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8; +} + +uint8_t bicubic_interpol(const uint8_t* buf, + int pitch, + int pos_pixel[], + int u_w[], + int v_w[], + int res_x, + int res_y, + int bpp, + int c_offset) { + int s_result = 0; + for (int i = 0; i < 4; i++) { + int a_result = 0; + for (int j = 0; j < 4; j++) { + a_result += u_w[j] * (*(uint8_t*)(buf + pos_pixel[i + 4] * pitch + + pos_pixel[j] * bpp + c_offset)); + } + s_result += a_result * v_w[i]; + } + s_result >>= 16; + return (uint8_t)(s_result < 0 ? 0 : s_result > 255 ? 255 : s_result); +} + +void bicubic_get_pos_weight(int pos_pixel[], + int u_w[], + int v_w[], + int src_col_l, + int src_row_l, + int res_x, + int res_y, + int stretch_width, + int stretch_height) { + pos_pixel[0] = src_col_l - 1; + pos_pixel[1] = src_col_l; + pos_pixel[2] = src_col_l + 1; + pos_pixel[3] = src_col_l + 2; + pos_pixel[4] = src_row_l - 1; + pos_pixel[5] = src_row_l; + pos_pixel[6] = src_row_l + 1; + pos_pixel[7] = src_row_l + 2; + for (int i = 0; i < 4; i++) { + if (pos_pixel[i] < 0) { + pos_pixel[i] = 0; + } + if (pos_pixel[i] >= stretch_width) { + pos_pixel[i] = stretch_width - 1; + } + if (pos_pixel[i + 4] < 0) { + pos_pixel[i + 4] = 0; + } + if (pos_pixel[i + 4] >= stretch_height) { + pos_pixel[i + 4] = stretch_height - 1; + } + } + u_w[0] = SDP_Table[256 + res_x]; + u_w[1] = SDP_Table[res_x]; + u_w[2] = SDP_Table[256 - res_x]; + u_w[3] = SDP_Table[512 - res_x]; + v_w[0] = SDP_Table[256 + res_y]; + v_w[1] = SDP_Table[res_y]; + v_w[2] = SDP_Table[256 - res_y]; + v_w[3] = SDP_Table[512 - res_y]; +} + +FXDIB_Format GetTransformedFormat(const CFX_DIBSource* pDrc) { + FXDIB_Format format = pDrc->GetFormat(); + if (pDrc->IsAlphaMask()) { + format = FXDIB_8bppMask; + } else if (format >= 1025) { + format = FXDIB_Cmyka; + } else if (format <= 32 || format == FXDIB_Argb) { + format = FXDIB_Argb; + } else { + format = FXDIB_Rgba; + } + return format; +} + +} // namespace + +const int16_t SDP_Table[513] = { + 256, 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, 255, 255, 255, + 254, 254, 254, 254, 253, 253, 253, 252, 252, 252, 251, 251, 251, 250, 250, + 249, 249, 249, 248, 248, 247, 247, 246, 246, 245, 244, 244, 243, 243, 242, + 242, 241, 240, 240, 239, 238, 238, 237, 236, 236, 235, 234, 233, 233, 232, + 231, 230, 230, 229, 228, 227, 226, 226, 225, 224, 223, 222, 221, 220, 219, + 218, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, + 204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, 192, 191, 190, 189, + 188, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 173, 172, 171, + 170, 169, 167, 166, 165, 164, 162, 161, 160, 159, 157, 156, 155, 154, 152, + 151, 150, 149, 147, 146, 145, 143, 142, 141, 140, 138, 137, 136, 134, 133, + 132, 130, 129, 128, 126, 125, 124, 122, 121, 120, 119, 117, 116, 115, 113, + 112, 111, 109, 108, 107, 105, 104, 103, 101, 100, 99, 97, 96, 95, 93, + 92, 91, 89, 88, 87, 85, 84, 83, 81, 80, 79, 77, 76, 75, 73, + 72, 71, 69, 68, 67, 66, 64, 63, 62, 60, 59, 58, 57, 55, 54, + 53, 52, 50, 49, 48, 47, 45, 44, 43, 42, 40, 39, 38, 37, 36, + 34, 33, 32, 31, 30, 28, 27, 26, 25, 24, 23, 21, 20, 19, 18, + 17, 16, 15, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0, 0, -1, -2, -3, -4, -5, -6, -7, -7, -8, -9, -10, -11, + -12, -12, -13, -14, -15, -15, -16, -17, -17, -18, -19, -19, -20, -21, -21, + -22, -22, -23, -24, -24, -25, -25, -26, -26, -27, -27, -27, -28, -28, -29, + -29, -30, -30, -30, -31, -31, -31, -32, -32, -32, -33, -33, -33, -33, -34, + -34, -34, -34, -35, -35, -35, -35, -35, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -35, -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -33, -33, + -33, -33, -33, -32, -32, -32, -32, -31, -31, -31, -31, -30, -30, -30, -30, + -29, -29, -29, -29, -28, -28, -28, -27, -27, -27, -27, -26, -26, -26, -25, + -25, -25, -24, -24, -24, -23, -23, -23, -22, -22, -22, -22, -21, -21, -21, + -20, -20, -20, -19, -19, -19, -18, -18, -18, -17, -17, -17, -16, -16, -16, + -15, -15, -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -11, -11, -11, + -10, -10, -10, -9, -9, -9, -9, -8, -8, -8, -7, -7, -7, -7, -6, + -6, -6, -6, -5, -5, -5, -5, -4, -4, -4, -4, -3, -3, -3, -3, + -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; + +class CFX_BilinearMatrix : public CPDF_FixedMatrix { + public: + CFX_BilinearMatrix(const CFX_Matrix& src, int bits) + : CPDF_FixedMatrix(src, bits) {} + inline void Transform(int x, + int y, + int& x1, + int& y1, + int& res_x, + int& res_y) { + x1 = a * x + c * y + e + base / 2; + y1 = b * x + d * y + f + base / 2; + res_x = x1 % base; + res_y = y1 % base; + if (res_x < 0 && res_x > -base) { + res_x = base + res_x; + } + if (res_y < 0 && res_x > -base) { + res_y = base + res_y; + } + x1 /= base; + y1 /= base; + } +}; +CFX_DIBitmap* CFX_DIBSource::SwapXY(FX_BOOL bXFlip, + FX_BOOL bYFlip, + const FX_RECT* pDestClip) const { + FX_RECT dest_clip(0, 0, m_Height, m_Width); + if (pDestClip) { + dest_clip.Intersect(*pDestClip); + } + if (dest_clip.IsEmpty()) { + return NULL; + } + CFX_DIBitmap* pTransBitmap = new CFX_DIBitmap; + int result_height = dest_clip.Height(), result_width = dest_clip.Width(); + if (!pTransBitmap->Create(result_width, result_height, GetFormat())) { + delete pTransBitmap; + return NULL; + } + pTransBitmap->CopyPalette(m_pPalette); + int dest_pitch = pTransBitmap->GetPitch(); + uint8_t* dest_buf = pTransBitmap->GetBuffer(); + int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left; + int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right; + int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top; + int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom; + if (GetBPP() == 1) { + FXSYS_memset(dest_buf, 0xff, dest_pitch * result_height); + for (int row = row_start; row < row_end; row++) { + const uint8_t* src_scan = GetScanline(row); + int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) - + dest_clip.left; + uint8_t* dest_scan = dest_buf; + if (bYFlip) { + dest_scan += (result_height - 1) * dest_pitch; + } + int dest_step = bYFlip ? -dest_pitch : dest_pitch; + for (int col = col_start; col < col_end; col++) { + if (!(src_scan[col / 8] & (1 << (7 - col % 8)))) { + dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8)); + } + dest_scan += dest_step; + } + } + } else { + int nBytes = GetBPP() / 8; + int dest_step = bYFlip ? -dest_pitch : dest_pitch; + if (nBytes == 3) { + dest_step -= 2; + } + for (int row = row_start; row < row_end; row++) { + int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) - + dest_clip.left; + uint8_t* dest_scan = dest_buf + dest_col * nBytes; + if (bYFlip) { + dest_scan += (result_height - 1) * dest_pitch; + } + if (nBytes == 4) { + FX_DWORD* src_scan = (FX_DWORD*)GetScanline(row) + col_start; + for (int col = col_start; col < col_end; col++) { + *(FX_DWORD*)dest_scan = *src_scan++; + dest_scan += dest_step; + } + } else { + const uint8_t* src_scan = GetScanline(row) + col_start * nBytes; + if (nBytes == 1) { + for (int col = col_start; col < col_end; col++) { + *dest_scan = *src_scan++; + dest_scan += dest_step; + } + } else { + for (int col = col_start; col < col_end; col++) { + *dest_scan++ = *src_scan++; + *dest_scan++ = *src_scan++; + *dest_scan = *src_scan++; + dest_scan += dest_step; + } + } + } + } + } + if (m_pAlphaMask) { + dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch(); + dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer(); + int dest_step = bYFlip ? -dest_pitch : dest_pitch; + for (int row = row_start; row < row_end; row++) { + int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) - + dest_clip.left; + uint8_t* dest_scan = dest_buf + dest_col; + if (bYFlip) { + dest_scan += (result_height - 1) * dest_pitch; + } + const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start; + for (int col = col_start; col < col_end; col++) { + *dest_scan = *src_scan++; + dest_scan += dest_step; + } + } + } + return pTransBitmap; +} +#define FIX16_005 0.05f +FX_RECT FXDIB_SwapClipBox(FX_RECT& clip, + int width, + int height, + FX_BOOL bFlipX, + FX_BOOL bFlipY) { + FX_RECT rect; + if (bFlipY) { + rect.left = height - clip.top; + rect.right = height - clip.bottom; + } else { + rect.left = clip.top; + rect.right = clip.bottom; + } + if (bFlipX) { + rect.top = width - clip.left; + rect.bottom = width - clip.right; + } else { + rect.top = clip.left; + rect.bottom = clip.right; + } + rect.Normalize(); + return rect; +} +CFX_DIBitmap* CFX_DIBSource::TransformTo(const CFX_Matrix* pDestMatrix, + int& result_left, + int& result_top, + FX_DWORD flags, + const FX_RECT* pDestClip) const { + CFX_ImageTransformer transformer; + transformer.Start(this, pDestMatrix, flags, pDestClip); + transformer.Continue(NULL); + result_left = transformer.m_ResultLeft; + result_top = transformer.m_ResultTop; + CFX_DIBitmap* pTransformed = transformer.m_Storer.Detach(); + return pTransformed; +} +CFX_DIBitmap* CFX_DIBSource::StretchTo(int dest_width, + int dest_height, + FX_DWORD flags, + const FX_RECT* pClip) const { + FX_RECT clip_rect(0, 0, FXSYS_abs(dest_width), FXSYS_abs(dest_height)); + if (pClip) { + clip_rect.Intersect(*pClip); + } + if (clip_rect.IsEmpty()) { + return NULL; + } + if (dest_width == m_Width && dest_height == m_Height) { + return Clone(&clip_rect); + } + CFX_ImageStretcher stretcher; + CFX_BitmapStorer storer; + if (stretcher.Start(&storer, this, dest_width, dest_height, clip_rect, + flags)) { + stretcher.Continue(NULL); + } + return storer.Detach(); +} +CFX_ImageTransformer::CFX_ImageTransformer() { + m_Status = 0; + m_pMatrix = NULL; +} +CFX_ImageTransformer::~CFX_ImageTransformer() {} +FX_BOOL CFX_ImageTransformer::Start(const CFX_DIBSource* pSrc, + const CFX_Matrix* pDestMatrix, + int flags, + const FX_RECT* pDestClip) { + m_pMatrix = (CFX_Matrix*)pDestMatrix; + CFX_FloatRect unit_rect = pDestMatrix->GetUnitRect(); + FX_RECT result_rect = unit_rect.GetClosestRect(); + FX_RECT result_clip = result_rect; + if (pDestClip) { + result_clip.Intersect(*pDestClip); + } + if (result_clip.IsEmpty()) { + return FALSE; + } + m_ResultLeft = result_clip.left; + m_ResultTop = result_clip.top; + m_ResultWidth = result_clip.Width(); + m_ResultHeight = result_clip.Height(); + m_Flags = flags; + if (FXSYS_fabs(pDestMatrix->a) < FXSYS_fabs(pDestMatrix->b) / 20 && + FXSYS_fabs(pDestMatrix->d) < FXSYS_fabs(pDestMatrix->c) / 20 && + FXSYS_fabs(pDestMatrix->a) < 0.5f && FXSYS_fabs(pDestMatrix->d) < 0.5f) { + int dest_width = result_rect.Width(); + int dest_height = result_rect.Height(); + result_clip.Offset(-result_rect.left, -result_rect.top); + result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height, + pDestMatrix->c > 0, pDestMatrix->b < 0); + m_Stretcher.Start(&m_Storer, pSrc, dest_height, dest_width, result_clip, + flags); + m_Status = 1; + return TRUE; + } + if (FXSYS_fabs(pDestMatrix->b) < FIX16_005 && + FXSYS_fabs(pDestMatrix->c) < FIX16_005) { + int dest_width = pDestMatrix->a > 0 ? (int)FXSYS_ceil(pDestMatrix->a) + : (int)FXSYS_floor(pDestMatrix->a); + int dest_height = pDestMatrix->d > 0 ? (int)-FXSYS_ceil(pDestMatrix->d) + : (int)-FXSYS_floor(pDestMatrix->d); + result_clip.Offset(-result_rect.left, -result_rect.top); + m_Stretcher.Start(&m_Storer, pSrc, dest_width, dest_height, result_clip, + flags); + m_Status = 2; + return TRUE; + } + int stretch_width = + (int)FXSYS_ceil(FXSYS_sqrt2(pDestMatrix->a, pDestMatrix->b)); + int stretch_height = + (int)FXSYS_ceil(FXSYS_sqrt2(pDestMatrix->c, pDestMatrix->d)); + CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, + (FX_FLOAT)(stretch_height)); + stretch2dest.Concat( + pDestMatrix->a / stretch_width, pDestMatrix->b / stretch_width, + pDestMatrix->c / stretch_height, pDestMatrix->d / stretch_height, + pDestMatrix->e, pDestMatrix->f); + m_dest2stretch.SetReverse(stretch2dest); + CFX_FloatRect clip_rect_f(result_clip); + clip_rect_f.Transform(&m_dest2stretch); + m_StretchClip = clip_rect_f.GetOutterRect(); + m_StretchClip.Intersect(0, 0, stretch_width, stretch_height); + m_Stretcher.Start(&m_Storer, pSrc, stretch_width, stretch_height, + m_StretchClip, flags); + m_Status = 3; + return TRUE; +} + +FX_BOOL CFX_ImageTransformer::Continue(IFX_Pause* pPause) { + if (m_Status == 1) { + if (m_Stretcher.Continue(pPause)) { + return TRUE; + } + if (m_Storer.GetBitmap()) { + m_Storer.Replace( + m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0)); + } + return FALSE; + } + if (m_Status == 2) { + return m_Stretcher.Continue(pPause); + } + if (m_Status != 3) { + return FALSE; + } + if (m_Stretcher.Continue(pPause)) { + return TRUE; + } + int stretch_width = m_StretchClip.Width(); + int stretch_height = m_StretchClip.Height(); + if (!m_Storer.GetBitmap()) { + return FALSE; + } + const uint8_t* stretch_buf = m_Storer.GetBitmap()->GetBuffer(); + const uint8_t* stretch_buf_mask = NULL; + if (m_Storer.GetBitmap()->m_pAlphaMask) { + stretch_buf_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetBuffer(); + } + int stretch_pitch = m_Storer.GetBitmap()->GetPitch(); + CFX_DIBitmap* pTransformed = new CFX_DIBitmap; + FXDIB_Format transformF = GetTransformedFormat(m_Stretcher.m_pSource); + if (!pTransformed->Create(m_ResultWidth, m_ResultHeight, transformF)) { + delete pTransformed; + return FALSE; + } + pTransformed->Clear(0); + if (pTransformed->m_pAlphaMask) { + pTransformed->m_pAlphaMask->Clear(0); + } + CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_ResultLeft), + (FX_FLOAT)(m_ResultTop)); + result2stretch.Concat(m_dest2stretch); + result2stretch.TranslateI(-m_StretchClip.left, -m_StretchClip.top); + if (!stretch_buf_mask && pTransformed->m_pAlphaMask) { + pTransformed->m_pAlphaMask->Clear(0xff000000); + } else if (pTransformed->m_pAlphaMask) { + int stretch_pitch_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetPitch(); + if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos_mask = + (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 && + src_row_l <= stretch_height) { + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + int src_col_r = src_col_l + 1; + int src_row_r = src_row_l + 1; + if (src_col_r == stretch_width) { + src_col_r--; + } + if (src_row_r == stretch_height) { + src_row_r--; + } + int row_offset_l = src_row_l * stretch_pitch_mask; + int row_offset_r = src_row_r * stretch_pitch_mask; + *dest_pos_mask = + bilinear_interpol(stretch_buf_mask, row_offset_l, row_offset_r, + src_col_l, src_col_r, res_x, res_y, 1, 0); + } + dest_pos_mask++; + } + } + } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos_mask = + (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 && + src_row_l <= stretch_height) { + int pos_pixel[8]; + int u_w[4], v_w[4]; + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l, + res_x, res_y, stretch_width, stretch_height); + *dest_pos_mask = + bicubic_interpol(stretch_buf_mask, stretch_pitch_mask, + pos_pixel, u_w, v_w, res_x, res_y, 1, 0); + } + dest_pos_mask++; + } + } + } else { + CPDF_FixedMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos_mask = + (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col, src_row; + result2stretch_fix.Transform(col, row, src_col, src_row); + if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 && + src_row <= stretch_height) { + if (src_col == stretch_width) { + src_col--; + } + if (src_row == stretch_height) { + src_row--; + } + *dest_pos_mask = + stretch_buf_mask[src_row * stretch_pitch_mask + src_col]; + } + dest_pos_mask++; + } + } + } + } + if (m_Storer.GetBitmap()->IsAlphaMask()) { + if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 && + src_row_l <= stretch_height) { + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + int src_col_r = src_col_l + 1; + int src_row_r = src_row_l + 1; + if (src_col_r == stretch_width) { + src_col_r--; + } + if (src_row_r == stretch_height) { + src_row_r--; + } + int row_offset_l = src_row_l * stretch_pitch; + int row_offset_r = src_row_r * stretch_pitch; + *dest_scan = + bilinear_interpol(stretch_buf, row_offset_l, row_offset_r, + src_col_l, src_col_r, res_x, res_y, 1, 0); + } + dest_scan++; + } + } + } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 && + src_row_l <= stretch_height) { + int pos_pixel[8]; + int u_w[4], v_w[4]; + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l, + res_x, res_y, stretch_width, stretch_height); + *dest_scan = bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, + u_w, v_w, res_x, res_y, 1, 0); + } + dest_scan++; + } + } + } else { + CPDF_FixedMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col, src_row; + result2stretch_fix.Transform(col, row, src_col, src_row); + if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 && + src_row <= stretch_height) { + if (src_col == stretch_width) { + src_col--; + } + if (src_row == stretch_height) { + src_row--; + } + const uint8_t* src_pixel = + stretch_buf + stretch_pitch * src_row + src_col; + *dest_scan = *src_pixel; + } + dest_scan++; + } + } + } + } else { + int Bpp = m_Storer.GetBitmap()->GetBPP() / 8; + int destBpp = pTransformed->GetBPP() / 8; + if (Bpp == 1) { + FX_DWORD argb[256]; + FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette(); + if (pPal) { + for (int i = 0; i < 256; i++) { + argb[i] = pPal[i]; + } + } else { + if (m_Storer.GetBitmap()->IsCmykImage()) { + for (int i = 0; i < 256; i++) { + argb[i] = 255 - i; + } + } else { + for (int i = 0; i < 256; i++) { + argb[i] = 0xff000000 | (i * 0x010101); + } + } + } + if (!(m_Flags & FXDIB_DOWNSAMPLE) && + !(m_Flags & FXDIB_BICUBIC_INTERPOL)) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && + src_row_l >= 0 && src_row_l <= stretch_height) { + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + int src_col_r = src_col_l + 1; + int src_row_r = src_row_l + 1; + if (src_col_r == stretch_width) { + src_col_r--; + } + if (src_row_r == stretch_height) { + src_row_r--; + } + int row_offset_l = src_row_l * stretch_pitch; + int row_offset_r = src_row_r * stretch_pitch; + FX_DWORD r_bgra_cmyk = argb[bilinear_interpol( + stretch_buf, row_offset_l, row_offset_r, src_col_l, src_col_r, + res_x, res_y, 1, 0)]; + if (transformF == FXDIB_Rgba) { + dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24); + dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16); + dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8); + } else { + *(FX_DWORD*)dest_pos = r_bgra_cmyk; + } + } + dest_pos += destBpp; + } + } + } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && + src_row_l >= 0 && src_row_l <= stretch_height) { + int pos_pixel[8]; + int u_w[4], v_w[4]; + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l, + res_x, res_y, stretch_width, + stretch_height); + FX_DWORD r_bgra_cmyk = + argb[bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, + u_w, v_w, res_x, res_y, 1, 0)]; + if (transformF == FXDIB_Rgba) { + dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24); + dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16); + dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8); + } else { + *(FX_DWORD*)dest_pos = r_bgra_cmyk; + } + } + dest_pos += destBpp; + } + } + } else { + CPDF_FixedMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col, src_row; + result2stretch_fix.Transform(col, row, src_col, src_row); + if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 && + src_row <= stretch_height) { + if (src_col == stretch_width) { + src_col--; + } + if (src_row == stretch_height) { + src_row--; + } + FX_DWORD r_bgra_cmyk = + argb[stretch_buf[src_row * stretch_pitch + src_col]]; + if (transformF == FXDIB_Rgba) { + dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24); + dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16); + dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8); + } else { + *(FX_DWORD*)dest_pos = r_bgra_cmyk; + } + } + dest_pos += destBpp; + } + } + } + } else { + FX_BOOL bHasAlpha = m_Storer.GetBitmap()->HasAlpha(); + int destBpp = pTransformed->GetBPP() / 8; + if (!(m_Flags & FXDIB_DOWNSAMPLE) && + !(m_Flags & FXDIB_BICUBIC_INTERPOL)) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && + src_row_l >= 0 && src_row_l <= stretch_height) { + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + int src_col_r = src_col_l + 1; + int src_row_r = src_row_l + 1; + if (src_col_r == stretch_width) { + src_col_r--; + } + if (src_row_r == stretch_height) { + src_row_r--; + } + int row_offset_l = src_row_l * stretch_pitch; + int row_offset_r = src_row_r * stretch_pitch; + uint8_t r_pos_red_y_r = + bilinear_interpol(stretch_buf, row_offset_l, row_offset_r, + src_col_l, src_col_r, res_x, res_y, Bpp, 2); + uint8_t r_pos_green_m_r = + bilinear_interpol(stretch_buf, row_offset_l, row_offset_r, + src_col_l, src_col_r, res_x, res_y, Bpp, 1); + uint8_t r_pos_blue_c_r = + bilinear_interpol(stretch_buf, row_offset_l, row_offset_r, + src_col_l, src_col_r, res_x, res_y, Bpp, 0); + if (bHasAlpha) { + if (transformF != FXDIB_Argb) { + if (transformF == FXDIB_Rgba) { + dest_pos[0] = r_pos_blue_c_r; + dest_pos[1] = r_pos_green_m_r; + dest_pos[2] = r_pos_red_y_r; + } else { + r_pos_k_r = bilinear_interpol( + stretch_buf, row_offset_l, row_offset_r, src_col_l, + src_col_r, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = + FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r, + r_pos_red_y_r, r_pos_k_r)); + } + } else { + uint8_t r_pos_a_r = bilinear_interpol( + stretch_buf, row_offset_l, row_offset_r, src_col_l, + src_col_r, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = FXARGB_TODIB( + FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r, + r_pos_blue_c_r)); + } + } else { + r_pos_k_r = 0xff; + if (transformF == FXDIB_Cmyka) { + r_pos_k_r = bilinear_interpol( + stretch_buf, row_offset_l, row_offset_r, src_col_l, + src_col_r, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = + FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r, + r_pos_red_y_r, r_pos_k_r)); + } else { + *(FX_DWORD*)dest_pos = FXARGB_TODIB( + FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r, + r_pos_blue_c_r)); + } + } + } + dest_pos += destBpp; + } + } + } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) { + CFX_BilinearMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0; + result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x, + res_y); + if (src_col_l >= 0 && src_col_l <= stretch_width && + src_row_l >= 0 && src_row_l <= stretch_height) { + int pos_pixel[8]; + int u_w[4], v_w[4]; + if (src_col_l == stretch_width) { + src_col_l--; + } + if (src_row_l == stretch_height) { + src_row_l--; + } + bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l, + res_x, res_y, stretch_width, + stretch_height); + uint8_t r_pos_red_y_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w, + v_w, res_x, res_y, Bpp, 2); + uint8_t r_pos_green_m_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w, + v_w, res_x, res_y, Bpp, 1); + uint8_t r_pos_blue_c_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w, + v_w, res_x, res_y, Bpp, 0); + if (bHasAlpha) { + if (transformF != FXDIB_Argb) { + if (transformF == FXDIB_Rgba) { + dest_pos[0] = r_pos_blue_c_r; + dest_pos[1] = r_pos_green_m_r; + dest_pos[2] = r_pos_red_y_r; + } else { + r_pos_k_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, + u_w, v_w, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = + FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r, + r_pos_red_y_r, r_pos_k_r)); + } + } else { + uint8_t r_pos_a_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, + u_w, v_w, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = FXARGB_TODIB( + FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r, + r_pos_blue_c_r)); + } + } else { + r_pos_k_r = 0xff; + if (transformF == FXDIB_Cmyka) { + r_pos_k_r = + bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, + u_w, v_w, res_x, res_y, Bpp, 3); + *(FX_DWORD*)dest_pos = + FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r, + r_pos_red_y_r, r_pos_k_r)); + } else { + *(FX_DWORD*)dest_pos = FXARGB_TODIB( + FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r, + r_pos_blue_c_r)); + } + } + } + dest_pos += destBpp; + } + } + } else { + CPDF_FixedMatrix result2stretch_fix(result2stretch, 8); + for (int row = 0; row < m_ResultHeight; row++) { + uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row); + for (int col = 0; col < m_ResultWidth; col++) { + int src_col, src_row; + result2stretch_fix.Transform(col, row, src_col, src_row); + if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 && + src_row <= stretch_height) { + if (src_col == stretch_width) { + src_col--; + } + if (src_row == stretch_height) { + src_row--; + } + const uint8_t* src_pos = + stretch_buf + src_row * stretch_pitch + src_col * Bpp; + if (bHasAlpha) { + if (transformF != FXDIB_Argb) { + if (transformF == FXDIB_Rgba) { + dest_pos[0] = src_pos[0]; + dest_pos[1] = src_pos[1]; + dest_pos[2] = src_pos[2]; + } else { + *(FX_DWORD*)dest_pos = FXCMYK_TODIB(CmykEncode( + src_pos[0], src_pos[1], src_pos[2], src_pos[3])); + } + } else { + *(FX_DWORD*)dest_pos = FXARGB_TODIB(FXARGB_MAKE( + src_pos[3], src_pos[2], src_pos[1], src_pos[0])); + } + } else { + if (transformF == FXDIB_Cmyka) { + *(FX_DWORD*)dest_pos = FXCMYK_TODIB(CmykEncode( + src_pos[0], src_pos[1], src_pos[2], src_pos[3])); + } else { + *(FX_DWORD*)dest_pos = FXARGB_TODIB( + FXARGB_MAKE(0xff, src_pos[2], src_pos[1], src_pos[0])); + } + } + } + dest_pos += destBpp; + } + } + } + } + } + m_Storer.Replace(pTransformed); + return FALSE; +} |