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_imagestretcher.h"
14 #include "core/fxge/fx_dib.h"
15 #include "third_party/base/numerics/safe_conversions.h"
16 #include "third_party/base/ptr_util.h"
17
18 namespace {
19
20 constexpr int kBase = 256;
21 constexpr float kFix16 = 0.05f;
22 constexpr uint8_t kOpaqueAlpha = 0xff;
23
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)24 uint8_t bilinear_interpol(const uint8_t* buf,
25 int row_offset_l,
26 int row_offset_r,
27 int src_col_l,
28 int src_col_r,
29 int res_x,
30 int res_y,
31 int bpp,
32 int c_offset) {
33 int i_resx = 255 - res_x;
34 int col_bpp_l = src_col_l * bpp;
35 int col_bpp_r = src_col_r * bpp;
36 const uint8_t* buf_u = buf + row_offset_l + c_offset;
37 const uint8_t* buf_d = buf + row_offset_r + c_offset;
38 const uint8_t* src_pos0 = buf_u + col_bpp_l;
39 const uint8_t* src_pos1 = buf_u + col_bpp_r;
40 const uint8_t* src_pos2 = buf_d + col_bpp_l;
41 const uint8_t* src_pos3 = buf_d + col_bpp_r;
42 uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8;
43 uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8;
44 return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8;
45 }
46
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)47 uint8_t bicubic_interpol(const uint8_t* buf,
48 uint32_t pitch,
49 const int pos_pixel[],
50 const int u_w[],
51 const int v_w[],
52 int res_x,
53 int res_y,
54 int bpp,
55 int c_offset) {
56 int s_result = 0;
57 for (int i = 0; i < 4; i++) {
58 int a_result = 0;
59 for (int j = 0; j < 4; j++) {
60 uint8_t val =
61 *(buf + pos_pixel[i + 4] * pitch + pos_pixel[j] * bpp + c_offset);
62 a_result += u_w[j] * val;
63 }
64 s_result += a_result * v_w[i];
65 }
66 s_result >>= 16;
67 return static_cast<uint8_t>(pdfium::clamp(s_result, 0, 255));
68 }
69
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)70 void bicubic_get_pos_weight(int pos_pixel[],
71 int u_w[],
72 int v_w[],
73 int src_col_l,
74 int src_row_l,
75 int res_x,
76 int res_y,
77 int stretch_width,
78 int stretch_height) {
79 pos_pixel[0] = src_col_l - 1;
80 pos_pixel[1] = src_col_l;
81 pos_pixel[2] = src_col_l + 1;
82 pos_pixel[3] = src_col_l + 2;
83 pos_pixel[4] = src_row_l - 1;
84 pos_pixel[5] = src_row_l;
85 pos_pixel[6] = src_row_l + 1;
86 pos_pixel[7] = src_row_l + 2;
87 for (int i = 0; i < 4; i++) {
88 pos_pixel[i] = pdfium::clamp(pos_pixel[i], 0, stretch_width - 1);
89 pos_pixel[i + 4] = pdfium::clamp(pos_pixel[i + 4], 0, stretch_height - 1);
90 }
91 u_w[0] = SDP_Table[256 + res_x];
92 u_w[1] = SDP_Table[res_x];
93 u_w[2] = SDP_Table[256 - res_x];
94 u_w[3] = SDP_Table[512 - res_x];
95 v_w[0] = SDP_Table[256 + res_y];
96 v_w[1] = SDP_Table[res_y];
97 v_w[2] = SDP_Table[256 - res_y];
98 v_w[3] = SDP_Table[512 - res_y];
99 }
100
GetTransformedFormat(const RetainPtr<CFX_DIBSource> & pDrc)101 FXDIB_Format GetTransformedFormat(const RetainPtr<CFX_DIBSource>& pDrc) {
102 if (pDrc->IsAlphaMask())
103 return FXDIB_8bppMask;
104
105 FXDIB_Format format = pDrc->GetFormat();
106 if (format >= 1025)
107 return FXDIB_Cmyka;
108 if (format <= 32 || format == FXDIB_Argb)
109 return FXDIB_Argb;
110 return FXDIB_Rgba;
111 }
112
NeedAlpha(bool bHasAlpha,FXDIB_Format format)113 bool NeedAlpha(bool bHasAlpha, FXDIB_Format format) {
114 return bHasAlpha || format == FXDIB_Cmyka;
115 }
116
WriteMonoResult(uint32_t r_bgra_cmyk,FXDIB_Format format,uint8_t * dest)117 void WriteMonoResult(uint32_t r_bgra_cmyk, FXDIB_Format format, uint8_t* dest) {
118 if (format == FXDIB_Rgba) {
119 dest[0] = static_cast<uint8_t>(r_bgra_cmyk >> 24);
120 dest[1] = static_cast<uint8_t>(r_bgra_cmyk >> 16);
121 dest[2] = static_cast<uint8_t>(r_bgra_cmyk >> 8);
122 } else {
123 *reinterpret_cast<uint32_t*>(dest) = r_bgra_cmyk;
124 }
125 }
126
WriteColorResult(std::function<uint8_t (int offset)> func,bool bHasAlpha,FXDIB_Format format,uint8_t * dest)127 void WriteColorResult(std::function<uint8_t(int offset)> func,
128 bool bHasAlpha,
129 FXDIB_Format format,
130 uint8_t* dest) {
131 uint8_t blue_c = func(0);
132 uint8_t green_m = func(1);
133 uint8_t red_y = func(2);
134 uint8_t alpha_k = NeedAlpha(bHasAlpha, format) ? func(3) : kOpaqueAlpha;
135
136 uint32_t* dest32 = reinterpret_cast<uint32_t*>(dest);
137 if (bHasAlpha) {
138 if (format == FXDIB_Argb) {
139 *dest32 = FXARGB_TODIB(FXARGB_MAKE(alpha_k, red_y, green_m, blue_c));
140 } else if (format == FXDIB_Rgba) {
141 dest[0] = blue_c;
142 dest[1] = green_m;
143 dest[2] = red_y;
144 } else {
145 *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, alpha_k));
146 }
147 return;
148 }
149
150 if (format == FXDIB_Cmyka) {
151 *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, alpha_k));
152 } else {
153 ASSERT(alpha_k == kOpaqueAlpha);
154 *dest32 = FXARGB_TODIB(FXARGB_MAKE(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_round(src.a * kBase)),
162 b(FXSYS_round(src.b * kBase)),
163 c(FXSYS_round(src.c * kBase)),
164 d(FXSYS_round(src.d * kBase)),
165 e(FXSYS_round(src.e * kBase)),
166 f(FXSYS_round(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 : 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>(fmodf(val.first, kBase));
198 *res_y = static_cast<int>(fmodf(val.second, kBase));
199 if (*res_x < 0 && *res_x > -kBase)
200 *res_x = kBase + *res_x;
201 if (*res_y < 0 && *res_x > -kBase)
202 *res_y = kBase + *res_y;
203 }
204 };
205
206 } // namespace
207
CFX_ImageTransformer(const RetainPtr<CFX_DIBSource> & pSrc,const CFX_Matrix * pMatrix,int flags,const FX_RECT * pClip)208 CFX_ImageTransformer::CFX_ImageTransformer(const RetainPtr<CFX_DIBSource>& pSrc,
209 const CFX_Matrix* pMatrix,
210 int flags,
211 const FX_RECT* pClip)
212 : m_pSrc(pSrc),
213 m_pMatrix(pMatrix),
214 m_pClip(pClip),
215 m_Flags(flags),
216 m_Status(0) {
217 FX_RECT result_rect = m_pMatrix->GetUnitRect().GetClosestRect();
218 FX_RECT result_clip = result_rect;
219 if (m_pClip)
220 result_clip.Intersect(*m_pClip);
221
222 if (result_clip.IsEmpty())
223 return;
224
225 m_result = result_clip;
226 if (fabs(m_pMatrix->a) < fabs(m_pMatrix->b) / 20 &&
227 fabs(m_pMatrix->d) < fabs(m_pMatrix->c) / 20 &&
228 fabs(m_pMatrix->a) < 0.5f && fabs(m_pMatrix->d) < 0.5f) {
229 int dest_width = result_rect.Width();
230 int dest_height = result_rect.Height();
231 result_clip.Offset(-result_rect.left, -result_rect.top);
232 result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
233 m_pMatrix->c > 0, m_pMatrix->b < 0);
234 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
235 &m_Storer, m_pSrc, dest_height, dest_width, result_clip, m_Flags);
236 m_Stretcher->Start();
237 m_Status = 1;
238 return;
239 }
240 if (fabs(m_pMatrix->b) < kFix16 && fabs(m_pMatrix->c) < kFix16) {
241 int dest_width = static_cast<int>(m_pMatrix->a > 0 ? ceil(m_pMatrix->a)
242 : floor(m_pMatrix->a));
243 int dest_height = static_cast<int>(m_pMatrix->d > 0 ? -ceil(m_pMatrix->d)
244 : -floor(m_pMatrix->d));
245 result_clip.Offset(-result_rect.left, -result_rect.top);
246 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
247 &m_Storer, m_pSrc, dest_width, dest_height, result_clip, m_Flags);
248 m_Stretcher->Start();
249 m_Status = 2;
250 return;
251 }
252 int stretch_width =
253 static_cast<int>(ceil(FXSYS_sqrt2(m_pMatrix->a, m_pMatrix->b)));
254 int stretch_height =
255 static_cast<int>(ceil(FXSYS_sqrt2(m_pMatrix->c, m_pMatrix->d)));
256 CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, stretch_height);
257 stretch2dest.Concat(
258 CFX_Matrix(m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
259 m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
260 m_pMatrix->e, m_pMatrix->f));
261 m_dest2stretch = stretch2dest.GetInverse();
262
263 m_StretchClip =
264 m_dest2stretch.TransformRect(CFX_FloatRect(result_clip)).GetOuterRect();
265 m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
266 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
267 &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip, m_Flags);
268 m_Stretcher->Start();
269 m_Status = 3;
270 }
271
~CFX_ImageTransformer()272 CFX_ImageTransformer::~CFX_ImageTransformer() {}
273
Continue(IFX_PauseIndicator * pPause)274 bool CFX_ImageTransformer::Continue(IFX_PauseIndicator* pPause) {
275 if (m_Status == 1) {
276 if (m_Stretcher->Continue(pPause))
277 return true;
278
279 if (m_Storer.GetBitmap()) {
280 m_Storer.Replace(
281 m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
282 }
283 return false;
284 }
285
286 if (m_Status == 2)
287 return m_Stretcher->Continue(pPause);
288 if (m_Status != 3)
289 return false;
290 if (m_Stretcher->Continue(pPause))
291 return true;
292
293 if (!m_Storer.GetBitmap())
294 return false;
295
296 auto pTransformed = pdfium::MakeRetain<CFX_DIBitmap>();
297 FXDIB_Format format = GetTransformedFormat(m_Stretcher->source());
298 if (!pTransformed->Create(m_result.Width(), m_result.Height(), format))
299 return false;
300
301 const auto& pSrcMask = m_Storer.GetBitmap()->m_pAlphaMask;
302 const uint8_t* pSrcMaskBuf = pSrcMask ? pSrcMask->GetBuffer() : nullptr;
303
304 pTransformed->Clear(0);
305 auto& pDestMask = pTransformed->m_pAlphaMask;
306 if (pDestMask)
307 pDestMask->Clear(0);
308
309 CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, m_result.left,
310 m_result.top);
311 result2stretch.Concat(m_dest2stretch);
312 result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
313 if (!pSrcMaskBuf && pDestMask) {
314 pDestMask->Clear(0xff000000);
315 } else if (pDestMask) {
316 CalcData cdata = {
317 pDestMask.Get(), result2stretch, pSrcMaskBuf,
318 m_Storer.GetBitmap()->m_pAlphaMask->GetPitch(),
319 };
320 CalcMask(cdata);
321 }
322
323 CalcData cdata = {pTransformed.Get(), result2stretch,
324 m_Storer.GetBitmap()->GetBuffer(),
325 m_Storer.GetBitmap()->GetPitch()};
326 if (m_Storer.GetBitmap()->IsAlphaMask()) {
327 CalcAlpha(cdata);
328 } else {
329 int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
330 if (Bpp == 1)
331 CalcMono(cdata, format);
332 else
333 CalcColor(cdata, format, Bpp);
334 }
335 m_Storer.Replace(std::move(pTransformed));
336 return false;
337 }
338
DetachBitmap()339 RetainPtr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
340 return m_Storer.Detach();
341 }
342
CalcMask(const CalcData & cdata)343 void CFX_ImageTransformer::CalcMask(const CalcData& cdata) {
344 if (IsBilinear()) {
345 auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
346 *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
347 data.src_col_l, data.src_col_r, data.res_x,
348 data.res_y, 1, 0);
349 };
350 DoBilinearLoop(cdata, 1, func);
351 } else if (IsBiCubic()) {
352 auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
353 *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
354 data.v_w, data.res_x, data.res_y, 1, 0);
355 };
356 DoBicubicLoop(cdata, 1, func);
357 } else {
358 auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
359 *dest = cdata.buf[data.src_row * cdata.pitch + data.src_col];
360 };
361 DoDownSampleLoop(cdata, 1, func);
362 }
363 }
364
CalcAlpha(const CalcData & cdata)365 void CFX_ImageTransformer::CalcAlpha(const CalcData& cdata) {
366 if (IsBilinear()) {
367 auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
368 *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
369 data.src_col_l, data.src_col_r, data.res_x,
370 data.res_y, 1, 0);
371 };
372 DoBilinearLoop(cdata, 1, func);
373 } else if (IsBiCubic()) {
374 auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
375 *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
376 data.v_w, data.res_x, data.res_y, 1, 0);
377 };
378 DoBicubicLoop(cdata, 1, func);
379 } else {
380 auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
381 const uint8_t* src_pixel =
382 cdata.buf + cdata.pitch * data.src_row + data.src_col;
383 *dest = *src_pixel;
384 };
385 DoDownSampleLoop(cdata, 1, func);
386 }
387 }
388
CalcMono(const CalcData & cdata,FXDIB_Format format)389 void CFX_ImageTransformer::CalcMono(const CalcData& cdata,
390 FXDIB_Format format) {
391 uint32_t argb[256];
392 FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
393 if (pPal) {
394 for (size_t i = 0; i < FX_ArraySize(argb); i++)
395 argb[i] = pPal[i];
396 } else if (m_Storer.GetBitmap()->IsCmykImage()) {
397 for (size_t i = 0; i < FX_ArraySize(argb); i++)
398 argb[i] = 255 - i;
399 } else {
400 for (size_t i = 0; i < FX_ArraySize(argb); i++)
401 argb[i] = 0xff000000 | (i * 0x010101);
402 }
403 int destBpp = cdata.bitmap->GetBPP() / 8;
404 if (IsBilinear()) {
405 auto func = [&cdata, format, &argb](const BilinearData& data,
406 uint8_t* dest) {
407 uint8_t idx = bilinear_interpol(
408 cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
409 data.src_col_r, data.res_x, data.res_y, 1, 0);
410 uint32_t r_bgra_cmyk = argb[idx];
411 WriteMonoResult(r_bgra_cmyk, format, dest);
412 };
413 DoBilinearLoop(cdata, destBpp, func);
414 } else if (IsBiCubic()) {
415 auto func = [&cdata, format, &argb](const BicubicData& data,
416 uint8_t* dest) {
417 uint32_t r_bgra_cmyk = argb[bicubic_interpol(
418 cdata.buf, cdata.pitch, data.pos_pixel, data.u_w, data.v_w,
419 data.res_x, data.res_y, 1, 0)];
420 WriteMonoResult(r_bgra_cmyk, format, dest);
421 };
422 DoBicubicLoop(cdata, destBpp, func);
423 } else {
424 auto func = [&cdata, format, &argb](const DownSampleData& data,
425 uint8_t* dest) {
426 uint32_t r_bgra_cmyk =
427 argb[cdata.buf[data.src_row * cdata.pitch + data.src_col]];
428 WriteMonoResult(r_bgra_cmyk, format, dest);
429 };
430 DoDownSampleLoop(cdata, destBpp, func);
431 }
432 }
433
CalcColor(const CalcData & cdata,FXDIB_Format format,int Bpp)434 void CFX_ImageTransformer::CalcColor(const CalcData& cdata,
435 FXDIB_Format format,
436 int Bpp) {
437 bool bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
438 int destBpp = cdata.bitmap->GetBPP() / 8;
439 if (IsBilinear()) {
440 auto func = [&cdata, format, Bpp, bHasAlpha](const BilinearData& data,
441 uint8_t* dest) {
442 auto bilinear_interpol_func = [&cdata, &data, Bpp](int offset) {
443 return bilinear_interpol(
444 cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
445 data.src_col_r, data.res_x, data.res_y, Bpp, offset);
446 };
447 WriteColorResult(bilinear_interpol_func, bHasAlpha, format, dest);
448 };
449 DoBilinearLoop(cdata, destBpp, func);
450 } else if (IsBiCubic()) {
451 auto func = [&cdata, format, Bpp, bHasAlpha](const BicubicData& data,
452 uint8_t* dest) {
453 auto bicubic_interpol_func = [&cdata, &data, Bpp](int offset) {
454 return bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel,
455 data.u_w, data.v_w, data.res_x, data.res_y, Bpp,
456 offset);
457 };
458 WriteColorResult(bicubic_interpol_func, bHasAlpha, format, dest);
459 };
460 DoBicubicLoop(cdata, destBpp, func);
461 } else {
462 auto func = [&cdata, format, bHasAlpha, Bpp](const DownSampleData& data,
463 uint8_t* dest) {
464 const uint8_t* src_pos =
465 cdata.buf + data.src_row * cdata.pitch + data.src_col * Bpp;
466 auto sample_func = [src_pos](int offset) { return src_pos[offset]; };
467 WriteColorResult(sample_func, bHasAlpha, format, dest);
468 };
469 DoDownSampleLoop(cdata, destBpp, func);
470 }
471 }
472
AdjustCoords(int * col,int * row) const473 void CFX_ImageTransformer::AdjustCoords(int* col, int* row) const {
474 int& src_col = *col;
475 int& src_row = *row;
476 if (src_col == stretch_width())
477 src_col--;
478 if (src_row == stretch_height())
479 src_row--;
480 }
481
DoBilinearLoop(const CalcData & cdata,int increment,std::function<void (const BilinearData &,uint8_t *)> func)482 void CFX_ImageTransformer::DoBilinearLoop(
483 const CalcData& cdata,
484 int increment,
485 std::function<void(const BilinearData&, uint8_t*)> func) {
486 CFX_BilinearMatrix matrix_fix(cdata.matrix);
487 for (int row = 0; row < m_result.Height(); row++) {
488 uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
489 for (int col = 0; col < m_result.Width(); col++) {
490 BilinearData d;
491 d.res_x = 0;
492 d.res_y = 0;
493 d.src_col_l = 0;
494 d.src_row_l = 0;
495 matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
496 &d.res_y);
497 if (InStretchBounds(d.src_col_l, d.src_row_l)) {
498 AdjustCoords(&d.src_col_l, &d.src_row_l);
499 d.src_col_r = d.src_col_l + 1;
500 d.src_row_r = d.src_row_l + 1;
501 AdjustCoords(&d.src_col_r, &d.src_row_r);
502 d.row_offset_l = d.src_row_l * cdata.pitch;
503 d.row_offset_r = d.src_row_r * cdata.pitch;
504 func(d, dest);
505 }
506 dest += increment;
507 }
508 }
509 }
510
DoBicubicLoop(const CalcData & cdata,int increment,std::function<void (const BicubicData &,uint8_t *)> func)511 void CFX_ImageTransformer::DoBicubicLoop(
512 const CalcData& cdata,
513 int increment,
514 std::function<void(const BicubicData&, uint8_t*)> func) {
515 CFX_BilinearMatrix matrix_fix(cdata.matrix);
516 for (int row = 0; row < m_result.Height(); row++) {
517 uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
518 for (int col = 0; col < m_result.Width(); col++) {
519 BicubicData d;
520 d.res_x = 0;
521 d.res_y = 0;
522 d.src_col_l = 0;
523 d.src_row_l = 0;
524 matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
525 &d.res_y);
526 if (InStretchBounds(d.src_col_l, d.src_row_l)) {
527 AdjustCoords(&d.src_col_l, &d.src_row_l);
528 bicubic_get_pos_weight(d.pos_pixel, d.u_w, d.v_w, d.src_col_l,
529 d.src_row_l, d.res_x, d.res_y, stretch_width(),
530 stretch_height());
531 func(d, dest);
532 }
533 dest += increment;
534 }
535 }
536 }
537
DoDownSampleLoop(const CalcData & cdata,int increment,std::function<void (const DownSampleData &,uint8_t *)> func)538 void CFX_ImageTransformer::DoDownSampleLoop(
539 const CalcData& cdata,
540 int increment,
541 std::function<void(const DownSampleData&, uint8_t*)> func) {
542 CPDF_FixedMatrix matrix_fix(cdata.matrix);
543 for (int row = 0; row < m_result.Height(); row++) {
544 uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
545 for (int col = 0; col < m_result.Width(); col++) {
546 DownSampleData d;
547 d.src_col = 0;
548 d.src_row = 0;
549 matrix_fix.Transform(col, row, &d.src_col, &d.src_row);
550 if (InStretchBounds(d.src_col, d.src_row)) {
551 AdjustCoords(&d.src_col, &d.src_row);
552 func(d, dest);
553 }
554 dest += increment;
555 }
556 }
557 }
558