1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/dib/cfx_imagetransformer.h"
8
9 #include <cmath>
10 #include <memory>
11 #include <utility>
12
13 #include "core/fxge/dib/cfx_dibitmap.h"
14 #include "core/fxge/dib/cfx_imagestretcher.h"
15 #include "core/fxge/fx_dib.h"
16 #include "third_party/base/compiler_specific.h"
17 #include "third_party/base/numerics/safe_conversions.h"
18 #include "third_party/base/ptr_util.h"
19 #include "third_party/base/stl_util.h"
20
21 namespace {
22
23 constexpr int kBase = 256;
24 constexpr float kFix16 = 0.05f;
25 constexpr uint8_t kOpaqueAlpha = 0xff;
26
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)27 uint8_t bilinear_interpol(const uint8_t* buf,
28 int row_offset_l,
29 int row_offset_r,
30 int src_col_l,
31 int src_col_r,
32 int res_x,
33 int res_y,
34 int bpp,
35 int c_offset) {
36 int i_resx = 255 - res_x;
37 int col_bpp_l = src_col_l * bpp;
38 int col_bpp_r = src_col_r * bpp;
39 const uint8_t* buf_u = buf + row_offset_l + c_offset;
40 const uint8_t* buf_d = buf + row_offset_r + c_offset;
41 const uint8_t* src_pos0 = buf_u + col_bpp_l;
42 const uint8_t* src_pos1 = buf_u + col_bpp_r;
43 const uint8_t* src_pos2 = buf_d + col_bpp_l;
44 const uint8_t* src_pos3 = buf_d + col_bpp_r;
45 uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8;
46 uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8;
47 return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8;
48 }
49
bicubic_interpol(const uint8_t * buf,uint32_t pitch,const int pos_pixel[],const int u_w[],const int v_w[],int res_x,int res_y,int bpp,int c_offset)50 uint8_t bicubic_interpol(const uint8_t* buf,
51 uint32_t pitch,
52 const int pos_pixel[],
53 const int u_w[],
54 const int v_w[],
55 int res_x,
56 int res_y,
57 int bpp,
58 int c_offset) {
59 int s_result = 0;
60 for (int i = 0; i < 4; i++) {
61 int a_result = 0;
62 for (int j = 0; j < 4; j++) {
63 uint8_t val =
64 *(buf + pos_pixel[i + 4] * pitch + pos_pixel[j] * bpp + c_offset);
65 a_result += u_w[j] * val;
66 }
67 s_result += a_result * v_w[i];
68 }
69 s_result >>= 16;
70 return static_cast<uint8_t>(pdfium::clamp(s_result, 0, 255));
71 }
72
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)73 void bicubic_get_pos_weight(int pos_pixel[],
74 int u_w[],
75 int v_w[],
76 int src_col_l,
77 int src_row_l,
78 int res_x,
79 int res_y,
80 int stretch_width,
81 int stretch_height) {
82 pos_pixel[0] = src_col_l - 1;
83 pos_pixel[1] = src_col_l;
84 pos_pixel[2] = src_col_l + 1;
85 pos_pixel[3] = src_col_l + 2;
86 pos_pixel[4] = src_row_l - 1;
87 pos_pixel[5] = src_row_l;
88 pos_pixel[6] = src_row_l + 1;
89 pos_pixel[7] = src_row_l + 2;
90 for (int i = 0; i < 4; i++) {
91 pos_pixel[i] = pdfium::clamp(pos_pixel[i], 0, stretch_width - 1);
92 pos_pixel[i + 4] = pdfium::clamp(pos_pixel[i + 4], 0, stretch_height - 1);
93 }
94 u_w[0] = SDP_Table[256 + res_x];
95 u_w[1] = SDP_Table[res_x];
96 u_w[2] = SDP_Table[256 - res_x];
97 u_w[3] = SDP_Table[512 - res_x];
98 v_w[0] = SDP_Table[256 + res_y];
99 v_w[1] = SDP_Table[res_y];
100 v_w[2] = SDP_Table[256 - res_y];
101 v_w[3] = SDP_Table[512 - res_y];
102 }
103
GetTransformedFormat(const RetainPtr<CFX_DIBBase> & pDrc)104 FXDIB_Format GetTransformedFormat(const RetainPtr<CFX_DIBBase>& pDrc) {
105 if (pDrc->IsAlphaMask())
106 return FXDIB_8bppMask;
107
108 FXDIB_Format format = pDrc->GetFormat();
109 if (format >= 1025)
110 return FXDIB_Cmyka;
111 if (format <= 32 || format == FXDIB_Argb)
112 return FXDIB_Argb;
113 return FXDIB_Rgba;
114 }
115
WriteMonoResult(uint32_t r_bgra_cmyk,FXDIB_Format format,uint8_t * dest)116 void WriteMonoResult(uint32_t r_bgra_cmyk, FXDIB_Format format, uint8_t* dest) {
117 if (format == FXDIB_Rgba) {
118 dest[0] = static_cast<uint8_t>(r_bgra_cmyk >> 24);
119 dest[1] = static_cast<uint8_t>(r_bgra_cmyk >> 16);
120 dest[2] = static_cast<uint8_t>(r_bgra_cmyk >> 8);
121 } else {
122 *reinterpret_cast<uint32_t*>(dest) = r_bgra_cmyk;
123 }
124 }
125
126 // Let the compiler deduce the type for |func|, which cheaper than specifying it
127 // with std::function.
128 template <typename F>
WriteColorResult(const F & func,bool bHasAlpha,FXDIB_Format format,uint8_t * dest)129 void WriteColorResult(const F& func,
130 bool bHasAlpha,
131 FXDIB_Format format,
132 uint8_t* dest) {
133 uint8_t blue_c = func(0);
134 uint8_t green_m = func(1);
135 uint8_t red_y = func(2);
136
137 uint32_t* dest32 = reinterpret_cast<uint32_t*>(dest);
138 if (bHasAlpha) {
139 if (format == FXDIB_Argb) {
140 *dest32 = FXARGB_TODIB(ArgbEncode(func(3), red_y, green_m, blue_c));
141 } else if (format == FXDIB_Rgba) {
142 dest[0] = blue_c;
143 dest[1] = green_m;
144 dest[2] = red_y;
145 } else {
146 *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, func(3)));
147 }
148 return;
149 }
150
151 if (format == FXDIB_Cmyka) {
152 *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, func(3)));
153 } else {
154 *dest32 = FXARGB_TODIB(ArgbEncode(kOpaqueAlpha, red_y, green_m, blue_c));
155 }
156 }
157
158 class CPDF_FixedMatrix {
159 public:
CPDF_FixedMatrix(const CFX_Matrix & src)160 explicit CPDF_FixedMatrix(const CFX_Matrix& src)
161 : a(FXSYS_roundf(src.a * kBase)),
162 b(FXSYS_roundf(src.b * kBase)),
163 c(FXSYS_roundf(src.c * kBase)),
164 d(FXSYS_roundf(src.d * kBase)),
165 e(FXSYS_roundf(src.e * kBase)),
166 f(FXSYS_roundf(src.f * kBase)) {}
167
Transform(int x,int y,int * x1,int * y1) const168 void Transform(int x, int y, int* x1, int* y1) const {
169 std::pair<float, float> val = TransformInternal(x, y);
170 *x1 = pdfium::base::saturated_cast<int>(val.first / kBase);
171 *y1 = pdfium::base::saturated_cast<int>(val.second / kBase);
172 }
173
174 protected:
TransformInternal(float x,float y) const175 std::pair<float, float> TransformInternal(float x, float y) const {
176 return std::make_pair(a * x + c * y + e + kBase / 2,
177 b * x + d * y + f + kBase / 2);
178 }
179
180 const int a;
181 const int b;
182 const int c;
183 const int d;
184 const int e;
185 const int f;
186 };
187
188 class CFX_BilinearMatrix final : public CPDF_FixedMatrix {
189 public:
CFX_BilinearMatrix(const CFX_Matrix & src)190 explicit CFX_BilinearMatrix(const CFX_Matrix& src) : CPDF_FixedMatrix(src) {}
191
Transform(int x,int y,int * x1,int * y1,int * res_x,int * res_y) const192 void Transform(int x, int y, int* x1, int* y1, int* res_x, int* res_y) const {
193 std::pair<float, float> val = TransformInternal(x, y);
194 *x1 = pdfium::base::saturated_cast<int>(val.first / kBase);
195 *y1 = pdfium::base::saturated_cast<int>(val.second / kBase);
196
197 *res_x = static_cast<int>(val.first) % kBase;
198 *res_y = static_cast<int>(val.second) % kBase;
199 if (*res_x < 0 && *res_x > -kBase)
200 *res_x = kBase + *res_x;
201 if (*res_y < 0 && *res_y > -kBase)
202 *res_y = kBase + *res_y;
203 }
204 };
205
InStretchBounds(const FX_RECT & clip_rect,int col,int row)206 bool InStretchBounds(const FX_RECT& clip_rect, int col, int row) {
207 return col >= 0 && col <= clip_rect.Width() && row >= 0 &&
208 row <= clip_rect.Height();
209 }
210
AdjustCoords(const FX_RECT & clip_rect,int * col,int * row)211 void AdjustCoords(const FX_RECT& clip_rect, int* col, int* row) {
212 int& src_col = *col;
213 int& src_row = *row;
214 if (src_col == clip_rect.Width())
215 src_col--;
216 if (src_row == clip_rect.Height())
217 src_row--;
218 }
219
220 // Let the compiler deduce the type for |func|, which cheaper than specifying it
221 // with std::function.
222 template <typename F>
DoBilinearLoop(const CFX_ImageTransformer::CalcData & cdata,const FX_RECT & result_rect,const FX_RECT & clip_rect,int increment,const F & func)223 void DoBilinearLoop(const CFX_ImageTransformer::CalcData& cdata,
224 const FX_RECT& result_rect,
225 const FX_RECT& clip_rect,
226 int increment,
227 const F& func) {
228 CFX_BilinearMatrix matrix_fix(cdata.matrix);
229 for (int row = 0; row < result_rect.Height(); row++) {
230 uint8_t* dest = cdata.bitmap->GetWritableScanline(row);
231 for (int col = 0; col < result_rect.Width(); col++) {
232 CFX_ImageTransformer::BilinearData d;
233 d.res_x = 0;
234 d.res_y = 0;
235 d.src_col_l = 0;
236 d.src_row_l = 0;
237 matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
238 &d.res_y);
239 if (LIKELY(InStretchBounds(clip_rect, d.src_col_l, d.src_row_l))) {
240 AdjustCoords(clip_rect, &d.src_col_l, &d.src_row_l);
241 d.src_col_r = d.src_col_l + 1;
242 d.src_row_r = d.src_row_l + 1;
243 AdjustCoords(clip_rect, &d.src_col_r, &d.src_row_r);
244 d.row_offset_l = d.src_row_l * cdata.pitch;
245 d.row_offset_r = d.src_row_r * cdata.pitch;
246 func(d, dest);
247 }
248 dest += increment;
249 }
250 }
251 }
252
253 // Let the compiler deduce the type for |func|, which cheaper than specifying it
254 // with std::function.
255 template <typename F>
DoBicubicLoop(const CFX_ImageTransformer::CalcData & cdata,const FX_RECT & result_rect,const FX_RECT & clip_rect,int increment,const F & func)256 void DoBicubicLoop(const CFX_ImageTransformer::CalcData& cdata,
257 const FX_RECT& result_rect,
258 const FX_RECT& clip_rect,
259 int increment,
260 const F& func) {
261 CFX_BilinearMatrix matrix_fix(cdata.matrix);
262 for (int row = 0; row < result_rect.Height(); row++) {
263 uint8_t* dest = cdata.bitmap->GetWritableScanline(row);
264 for (int col = 0; col < result_rect.Width(); col++) {
265 CFX_ImageTransformer::BicubicData d;
266 d.res_x = 0;
267 d.res_y = 0;
268 d.src_col_l = 0;
269 d.src_row_l = 0;
270 matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
271 &d.res_y);
272 if (LIKELY(InStretchBounds(clip_rect, d.src_col_l, d.src_row_l))) {
273 AdjustCoords(clip_rect, &d.src_col_l, &d.src_row_l);
274 bicubic_get_pos_weight(d.pos_pixel, d.u_w, d.v_w, d.src_col_l,
275 d.src_row_l, d.res_x, d.res_y, clip_rect.Width(),
276 clip_rect.Height());
277 func(d, dest);
278 }
279 dest += increment;
280 }
281 }
282 }
283
284 // Let the compiler deduce the type for |func|, which cheaper than specifying it
285 // with std::function.
286 template <typename F>
DoDownSampleLoop(const CFX_ImageTransformer::CalcData & cdata,const FX_RECT & result_rect,const FX_RECT & clip_rect,int increment,const F & func)287 void DoDownSampleLoop(const CFX_ImageTransformer::CalcData& cdata,
288 const FX_RECT& result_rect,
289 const FX_RECT& clip_rect,
290 int increment,
291 const F& func) {
292 CPDF_FixedMatrix matrix_fix(cdata.matrix);
293 for (int row = 0; row < result_rect.Height(); row++) {
294 uint8_t* dest = cdata.bitmap->GetWritableScanline(row);
295 for (int col = 0; col < result_rect.Width(); col++) {
296 CFX_ImageTransformer::DownSampleData d;
297 d.src_col = 0;
298 d.src_row = 0;
299 matrix_fix.Transform(col, row, &d.src_col, &d.src_row);
300 if (LIKELY(InStretchBounds(clip_rect, d.src_col, d.src_row))) {
301 AdjustCoords(clip_rect, &d.src_col, &d.src_row);
302 func(d, dest);
303 }
304 dest += increment;
305 }
306 }
307 }
308
309 } // namespace
310
CFX_ImageTransformer(const RetainPtr<CFX_DIBBase> & pSrc,const CFX_Matrix & matrix,const FXDIB_ResampleOptions & options,const FX_RECT * pClip)311 CFX_ImageTransformer::CFX_ImageTransformer(const RetainPtr<CFX_DIBBase>& pSrc,
312 const CFX_Matrix& matrix,
313 const FXDIB_ResampleOptions& options,
314 const FX_RECT* pClip)
315 : m_pSrc(pSrc), m_matrix(matrix), m_ResampleOptions(options) {
316 FX_RECT result_rect = m_matrix.GetUnitRect().GetClosestRect();
317 FX_RECT result_clip = result_rect;
318 if (pClip)
319 result_clip.Intersect(*pClip);
320
321 if (result_clip.IsEmpty())
322 return;
323
324 m_result = result_clip;
325 if (fabs(m_matrix.a) < fabs(m_matrix.b) / 20 &&
326 fabs(m_matrix.d) < fabs(m_matrix.c) / 20 && fabs(m_matrix.a) < 0.5f &&
327 fabs(m_matrix.d) < 0.5f) {
328 int dest_width = result_rect.Width();
329 int dest_height = result_rect.Height();
330 result_clip.Offset(-result_rect.left, -result_rect.top);
331 result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
332 m_matrix.c > 0, m_matrix.b < 0);
333 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
334 &m_Storer, m_pSrc, dest_height, dest_width, result_clip,
335 m_ResampleOptions);
336 m_Stretcher->Start();
337 m_type = kRotate;
338 return;
339 }
340 if (fabs(m_matrix.b) < kFix16 && fabs(m_matrix.c) < kFix16) {
341 int dest_width =
342 static_cast<int>(m_matrix.a > 0 ? ceil(m_matrix.a) : floor(m_matrix.a));
343 int dest_height = static_cast<int>(m_matrix.d > 0 ? -ceil(m_matrix.d)
344 : -floor(m_matrix.d));
345 result_clip.Offset(-result_rect.left, -result_rect.top);
346 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
347 &m_Storer, m_pSrc, dest_width, dest_height, result_clip,
348 m_ResampleOptions);
349 m_Stretcher->Start();
350 m_type = kNormal;
351 return;
352 }
353
354 int stretch_width =
355 static_cast<int>(ceil(FXSYS_sqrt2(m_matrix.a, m_matrix.b)));
356 int stretch_height =
357 static_cast<int>(ceil(FXSYS_sqrt2(m_matrix.c, m_matrix.d)));
358 CFX_Matrix stretch_to_dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, stretch_height);
359 stretch_to_dest.Concat(
360 CFX_Matrix(m_matrix.a / stretch_width, m_matrix.b / stretch_width,
361 m_matrix.c / stretch_height, m_matrix.d / stretch_height,
362 m_matrix.e, m_matrix.f));
363 CFX_Matrix dest_to_strech = stretch_to_dest.GetInverse();
364
365 FX_RECT stretch_clip =
366 dest_to_strech.TransformRect(CFX_FloatRect(result_clip)).GetOuterRect();
367 if (!stretch_clip.Valid())
368 return;
369
370 stretch_clip.Intersect(0, 0, stretch_width, stretch_height);
371 if (!stretch_clip.Valid())
372 return;
373
374 m_dest2stretch = dest_to_strech;
375 m_StretchClip = stretch_clip;
376 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
377 &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip,
378 m_ResampleOptions);
379 m_Stretcher->Start();
380 m_type = kOther;
381 }
382
383 CFX_ImageTransformer::~CFX_ImageTransformer() = default;
384
Continue(PauseIndicatorIface * pPause)385 bool CFX_ImageTransformer::Continue(PauseIndicatorIface* pPause) {
386 if (m_type == kNone)
387 return false;
388
389 if (m_Stretcher->Continue(pPause))
390 return true;
391
392 switch (m_type) {
393 case kNormal:
394 break;
395 case kRotate:
396 ContinueRotate(pPause);
397 break;
398 case kOther:
399 ContinueOther(pPause);
400 break;
401 default:
402 NOTREACHED();
403 break;
404 }
405 return false;
406 }
407
ContinueRotate(PauseIndicatorIface * pPause)408 void CFX_ImageTransformer::ContinueRotate(PauseIndicatorIface* pPause) {
409 if (m_Storer.GetBitmap()) {
410 m_Storer.Replace(
411 m_Storer.GetBitmap()->SwapXY(m_matrix.c > 0, m_matrix.b < 0));
412 }
413 }
414
ContinueOther(PauseIndicatorIface * pPause)415 void CFX_ImageTransformer::ContinueOther(PauseIndicatorIface* pPause) {
416 if (!m_Storer.GetBitmap())
417 return;
418
419 auto pTransformed = pdfium::MakeRetain<CFX_DIBitmap>();
420 FXDIB_Format format = GetTransformedFormat(m_Stretcher->source());
421 if (!pTransformed->Create(m_result.Width(), m_result.Height(), format))
422 return;
423
424 const auto& pSrcMask = m_Storer.GetBitmap()->m_pAlphaMask;
425 const uint8_t* pSrcMaskBuf = pSrcMask ? pSrcMask->GetBuffer() : nullptr;
426
427 pTransformed->Clear(0);
428 auto& pDestMask = pTransformed->m_pAlphaMask;
429 if (pDestMask)
430 pDestMask->Clear(0);
431
432 CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, m_result.left,
433 m_result.top);
434 result2stretch.Concat(m_dest2stretch);
435 result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
436 if (!pSrcMaskBuf && pDestMask) {
437 pDestMask->Clear(0xff000000);
438 } else if (pDestMask) {
439 CalcData cdata = {
440 pDestMask.Get(),
441 result2stretch,
442 pSrcMaskBuf,
443 m_Storer.GetBitmap()->m_pAlphaMask->GetPitch(),
444 };
445 CalcMask(cdata);
446 }
447
448 CalcData cdata = {pTransformed.Get(), result2stretch,
449 m_Storer.GetBitmap()->GetBuffer(),
450 m_Storer.GetBitmap()->GetPitch()};
451 if (m_Storer.GetBitmap()->IsAlphaMask()) {
452 CalcAlpha(cdata);
453 } else {
454 int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
455 if (Bpp == 1)
456 CalcMono(cdata, format);
457 else
458 CalcColor(cdata, format, Bpp);
459 }
460 m_Storer.Replace(std::move(pTransformed));
461 }
462
DetachBitmap()463 RetainPtr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
464 return m_Storer.Detach();
465 }
466
CalcMask(const CalcData & cdata)467 void CFX_ImageTransformer::CalcMask(const CalcData& cdata) {
468 if (IsBilinear()) {
469 auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
470 *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
471 data.src_col_l, data.src_col_r, data.res_x,
472 data.res_y, 1, 0);
473 };
474 DoBilinearLoop(cdata, m_result, m_StretchClip, 1, func);
475 } else if (IsBiCubic()) {
476 auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
477 *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
478 data.v_w, data.res_x, data.res_y, 1, 0);
479 };
480 DoBicubicLoop(cdata, m_result, m_StretchClip, 1, func);
481 } else {
482 auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
483 *dest = cdata.buf[data.src_row * cdata.pitch + data.src_col];
484 };
485 DoDownSampleLoop(cdata, m_result, m_StretchClip, 1, func);
486 }
487 }
488
CalcAlpha(const CalcData & cdata)489 void CFX_ImageTransformer::CalcAlpha(const CalcData& cdata) {
490 if (IsBilinear()) {
491 auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
492 *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
493 data.src_col_l, data.src_col_r, data.res_x,
494 data.res_y, 1, 0);
495 };
496 DoBilinearLoop(cdata, m_result, m_StretchClip, 1, func);
497 } else if (IsBiCubic()) {
498 auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
499 *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
500 data.v_w, data.res_x, data.res_y, 1, 0);
501 };
502 DoBicubicLoop(cdata, m_result, m_StretchClip, 1, func);
503 } else {
504 auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
505 const uint8_t* src_pixel =
506 cdata.buf + cdata.pitch * data.src_row + data.src_col;
507 *dest = *src_pixel;
508 };
509 DoDownSampleLoop(cdata, m_result, m_StretchClip, 1, func);
510 }
511 }
512
CalcMono(const CalcData & cdata,FXDIB_Format format)513 void CFX_ImageTransformer::CalcMono(const CalcData& cdata,
514 FXDIB_Format format) {
515 uint32_t argb[256];
516 FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
517 if (pPal) {
518 for (size_t i = 0; i < FX_ArraySize(argb); i++)
519 argb[i] = pPal[i];
520 } else if (m_Storer.GetBitmap()->IsCmykImage()) {
521 for (size_t i = 0; i < FX_ArraySize(argb); i++)
522 argb[i] = 255 - i;
523 } else {
524 for (size_t i = 0; i < FX_ArraySize(argb); i++)
525 argb[i] = 0xff000000 | (i * 0x010101);
526 }
527 int destBpp = cdata.bitmap->GetBPP() / 8;
528 if (IsBilinear()) {
529 auto func = [&cdata, format, &argb](const BilinearData& data,
530 uint8_t* dest) {
531 uint8_t idx = bilinear_interpol(
532 cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
533 data.src_col_r, data.res_x, data.res_y, 1, 0);
534 uint32_t r_bgra_cmyk = argb[idx];
535 WriteMonoResult(r_bgra_cmyk, format, dest);
536 };
537 DoBilinearLoop(cdata, m_result, m_StretchClip, destBpp, func);
538 } else if (IsBiCubic()) {
539 auto func = [&cdata, format, &argb](const BicubicData& data,
540 uint8_t* dest) {
541 uint32_t r_bgra_cmyk = argb[bicubic_interpol(
542 cdata.buf, cdata.pitch, data.pos_pixel, data.u_w, data.v_w,
543 data.res_x, data.res_y, 1, 0)];
544 WriteMonoResult(r_bgra_cmyk, format, dest);
545 };
546 DoBicubicLoop(cdata, m_result, m_StretchClip, destBpp, func);
547 } else {
548 auto func = [&cdata, format, &argb](const DownSampleData& data,
549 uint8_t* dest) {
550 uint32_t r_bgra_cmyk =
551 argb[cdata.buf[data.src_row * cdata.pitch + data.src_col]];
552 WriteMonoResult(r_bgra_cmyk, format, dest);
553 };
554 DoDownSampleLoop(cdata, m_result, m_StretchClip, destBpp, func);
555 }
556 }
557
CalcColor(const CalcData & cdata,FXDIB_Format format,int Bpp)558 void CFX_ImageTransformer::CalcColor(const CalcData& cdata,
559 FXDIB_Format format,
560 int Bpp) {
561 bool bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
562 int destBpp = cdata.bitmap->GetBPP() / 8;
563 if (IsBilinear()) {
564 auto func = [&cdata, format, Bpp, bHasAlpha](const BilinearData& data,
565 uint8_t* dest) {
566 auto bilinear_interpol_func = [&cdata, &data, Bpp](int offset) {
567 return bilinear_interpol(
568 cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
569 data.src_col_r, data.res_x, data.res_y, Bpp, offset);
570 };
571 WriteColorResult(bilinear_interpol_func, bHasAlpha, format, dest);
572 };
573 DoBilinearLoop(cdata, m_result, m_StretchClip, destBpp, func);
574 } else if (IsBiCubic()) {
575 auto func = [&cdata, format, Bpp, bHasAlpha](const BicubicData& data,
576 uint8_t* dest) {
577 auto bicubic_interpol_func = [&cdata, &data, Bpp](int offset) {
578 return bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel,
579 data.u_w, data.v_w, data.res_x, data.res_y, Bpp,
580 offset);
581 };
582 WriteColorResult(bicubic_interpol_func, bHasAlpha, format, dest);
583 };
584 DoBicubicLoop(cdata, m_result, m_StretchClip, destBpp, func);
585 } else {
586 auto func = [&cdata, format, bHasAlpha, Bpp](const DownSampleData& data,
587 uint8_t* dest) {
588 const uint8_t* src_pos =
589 cdata.buf + data.src_row * cdata.pitch + data.src_col * Bpp;
590 auto sample_func = [src_pos](int offset) { return src_pos[offset]; };
591 WriteColorResult(sample_func, bHasAlpha, format, dest);
592 };
593 DoDownSampleLoop(cdata, m_result, m_StretchClip, destBpp, func);
594 }
595 }
596
IsBilinear() const597 bool CFX_ImageTransformer::IsBilinear() const {
598 return !IsBiCubic();
599 }
600
IsBiCubic() const601 bool CFX_ImageTransformer::IsBiCubic() const {
602 return m_ResampleOptions.bInterpolateBicubic;
603 }
604