1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/dib/dib_int.h"
8
9 #include <memory>
10 #include <utility>
11
12 #include "core/fxge/fx_dib.h"
13 #include "third_party/base/ptr_util.h"
14
15 namespace {
16
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)17 uint8_t bilinear_interpol(const uint8_t* buf,
18 int row_offset_l,
19 int row_offset_r,
20 int src_col_l,
21 int src_col_r,
22 int res_x,
23 int res_y,
24 int bpp,
25 int c_offset) {
26 int i_resx = 255 - res_x;
27 int col_bpp_l = src_col_l * bpp;
28 int col_bpp_r = src_col_r * bpp;
29 const uint8_t* buf_u = buf + row_offset_l + c_offset;
30 const uint8_t* buf_d = buf + row_offset_r + c_offset;
31 const uint8_t* src_pos0 = buf_u + col_bpp_l;
32 const uint8_t* src_pos1 = buf_u + col_bpp_r;
33 const uint8_t* src_pos2 = buf_d + col_bpp_l;
34 const uint8_t* src_pos3 = buf_d + col_bpp_r;
35 uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8;
36 uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8;
37 return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8;
38 }
39
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)40 uint8_t bicubic_interpol(const uint8_t* buf,
41 int pitch,
42 int pos_pixel[],
43 int u_w[],
44 int v_w[],
45 int res_x,
46 int res_y,
47 int bpp,
48 int c_offset) {
49 int s_result = 0;
50 for (int i = 0; i < 4; i++) {
51 int a_result = 0;
52 for (int j = 0; j < 4; j++) {
53 a_result += u_w[j] * (*(uint8_t*)(buf + pos_pixel[i + 4] * pitch +
54 pos_pixel[j] * bpp + c_offset));
55 }
56 s_result += a_result * v_w[i];
57 }
58 s_result >>= 16;
59 return (uint8_t)(s_result < 0 ? 0 : s_result > 255 ? 255 : s_result);
60 }
61
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)62 void bicubic_get_pos_weight(int pos_pixel[],
63 int u_w[],
64 int v_w[],
65 int src_col_l,
66 int src_row_l,
67 int res_x,
68 int res_y,
69 int stretch_width,
70 int stretch_height) {
71 pos_pixel[0] = src_col_l - 1;
72 pos_pixel[1] = src_col_l;
73 pos_pixel[2] = src_col_l + 1;
74 pos_pixel[3] = src_col_l + 2;
75 pos_pixel[4] = src_row_l - 1;
76 pos_pixel[5] = src_row_l;
77 pos_pixel[6] = src_row_l + 1;
78 pos_pixel[7] = src_row_l + 2;
79 for (int i = 0; i < 4; i++) {
80 if (pos_pixel[i] < 0) {
81 pos_pixel[i] = 0;
82 }
83 if (pos_pixel[i] >= stretch_width) {
84 pos_pixel[i] = stretch_width - 1;
85 }
86 if (pos_pixel[i + 4] < 0) {
87 pos_pixel[i + 4] = 0;
88 }
89 if (pos_pixel[i + 4] >= stretch_height) {
90 pos_pixel[i + 4] = stretch_height - 1;
91 }
92 }
93 u_w[0] = SDP_Table[256 + res_x];
94 u_w[1] = SDP_Table[res_x];
95 u_w[2] = SDP_Table[256 - res_x];
96 u_w[3] = SDP_Table[512 - res_x];
97 v_w[0] = SDP_Table[256 + res_y];
98 v_w[1] = SDP_Table[res_y];
99 v_w[2] = SDP_Table[256 - res_y];
100 v_w[3] = SDP_Table[512 - res_y];
101 }
102
GetTransformedFormat(const CFX_DIBSource * pDrc)103 FXDIB_Format GetTransformedFormat(const CFX_DIBSource* pDrc) {
104 FXDIB_Format format = pDrc->GetFormat();
105 if (pDrc->IsAlphaMask()) {
106 format = FXDIB_8bppMask;
107 } else if (format >= 1025) {
108 format = FXDIB_Cmyka;
109 } else if (format <= 32 || format == FXDIB_Argb) {
110 format = FXDIB_Argb;
111 } else {
112 format = FXDIB_Rgba;
113 }
114 return format;
115 }
116
117 } // namespace
118
119 const int16_t SDP_Table[513] = {
120 256, 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, 255, 255, 255,
121 254, 254, 254, 254, 253, 253, 253, 252, 252, 252, 251, 251, 251, 250, 250,
122 249, 249, 249, 248, 248, 247, 247, 246, 246, 245, 244, 244, 243, 243, 242,
123 242, 241, 240, 240, 239, 238, 238, 237, 236, 236, 235, 234, 233, 233, 232,
124 231, 230, 230, 229, 228, 227, 226, 226, 225, 224, 223, 222, 221, 220, 219,
125 218, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205,
126 204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, 192, 191, 190, 189,
127 188, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 173, 172, 171,
128 170, 169, 167, 166, 165, 164, 162, 161, 160, 159, 157, 156, 155, 154, 152,
129 151, 150, 149, 147, 146, 145, 143, 142, 141, 140, 138, 137, 136, 134, 133,
130 132, 130, 129, 128, 126, 125, 124, 122, 121, 120, 119, 117, 116, 115, 113,
131 112, 111, 109, 108, 107, 105, 104, 103, 101, 100, 99, 97, 96, 95, 93,
132 92, 91, 89, 88, 87, 85, 84, 83, 81, 80, 79, 77, 76, 75, 73,
133 72, 71, 69, 68, 67, 66, 64, 63, 62, 60, 59, 58, 57, 55, 54,
134 53, 52, 50, 49, 48, 47, 45, 44, 43, 42, 40, 39, 38, 37, 36,
135 34, 33, 32, 31, 30, 28, 27, 26, 25, 24, 23, 21, 20, 19, 18,
136 17, 16, 15, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
137 1, 0, 0, -1, -2, -3, -4, -5, -6, -7, -7, -8, -9, -10, -11,
138 -12, -12, -13, -14, -15, -15, -16, -17, -17, -18, -19, -19, -20, -21, -21,
139 -22, -22, -23, -24, -24, -25, -25, -26, -26, -27, -27, -27, -28, -28, -29,
140 -29, -30, -30, -30, -31, -31, -31, -32, -32, -32, -33, -33, -33, -33, -34,
141 -34, -34, -34, -35, -35, -35, -35, -35, -36, -36, -36, -36, -36, -36, -36,
142 -36, -36, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
143 -37, -37, -37, -37, -37, -37, -37, -37, -36, -36, -36, -36, -36, -36, -36,
144 -36, -36, -35, -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -33, -33,
145 -33, -33, -33, -32, -32, -32, -32, -31, -31, -31, -31, -30, -30, -30, -30,
146 -29, -29, -29, -29, -28, -28, -28, -27, -27, -27, -27, -26, -26, -26, -25,
147 -25, -25, -24, -24, -24, -23, -23, -23, -22, -22, -22, -22, -21, -21, -21,
148 -20, -20, -20, -19, -19, -19, -18, -18, -18, -17, -17, -17, -16, -16, -16,
149 -15, -15, -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -11, -11, -11,
150 -10, -10, -10, -9, -9, -9, -9, -8, -8, -8, -7, -7, -7, -7, -6,
151 -6, -6, -6, -5, -5, -5, -5, -4, -4, -4, -4, -3, -3, -3, -3,
152 -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0,
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
154 0, 0, 0,
155 };
156
157 class CFX_BilinearMatrix : public CPDF_FixedMatrix {
158 public:
CFX_BilinearMatrix(const CFX_Matrix & src,int bits)159 CFX_BilinearMatrix(const CFX_Matrix& src, int bits)
160 : CPDF_FixedMatrix(src, bits) {}
Transform(int x,int y,int & x1,int & y1,int & res_x,int & res_y)161 inline void Transform(int x,
162 int y,
163 int& x1,
164 int& y1,
165 int& res_x,
166 int& res_y) {
167 x1 = a * x + c * y + e + base / 2;
168 y1 = b * x + d * y + f + base / 2;
169 res_x = x1 % base;
170 res_y = y1 % base;
171 if (res_x < 0 && res_x > -base) {
172 res_x = base + res_x;
173 }
174 if (res_y < 0 && res_x > -base) {
175 res_y = base + res_y;
176 }
177 x1 /= base;
178 y1 /= base;
179 }
180 };
181
SwapXY(bool bXFlip,bool bYFlip,const FX_RECT * pDestClip) const182 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::SwapXY(
183 bool bXFlip,
184 bool bYFlip,
185 const FX_RECT* pDestClip) const {
186 FX_RECT dest_clip(0, 0, m_Height, m_Width);
187 if (pDestClip)
188 dest_clip.Intersect(*pDestClip);
189 if (dest_clip.IsEmpty())
190 return nullptr;
191
192 auto pTransBitmap = pdfium::MakeUnique<CFX_DIBitmap>();
193 int result_height = dest_clip.Height();
194 int result_width = dest_clip.Width();
195 if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
196 return nullptr;
197
198 pTransBitmap->SetPalette(m_pPalette.get());
199 int dest_pitch = pTransBitmap->GetPitch();
200 uint8_t* dest_buf = pTransBitmap->GetBuffer();
201 int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
202 int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
203 int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
204 int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
205 if (GetBPP() == 1) {
206 FXSYS_memset(dest_buf, 0xff, dest_pitch * result_height);
207 for (int row = row_start; row < row_end; row++) {
208 const uint8_t* src_scan = GetScanline(row);
209 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
210 dest_clip.left;
211 uint8_t* dest_scan = dest_buf;
212 if (bYFlip) {
213 dest_scan += (result_height - 1) * dest_pitch;
214 }
215 int dest_step = bYFlip ? -dest_pitch : dest_pitch;
216 for (int col = col_start; col < col_end; col++) {
217 if (!(src_scan[col / 8] & (1 << (7 - col % 8)))) {
218 dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
219 }
220 dest_scan += dest_step;
221 }
222 }
223 } else {
224 int nBytes = GetBPP() / 8;
225 int dest_step = bYFlip ? -dest_pitch : dest_pitch;
226 if (nBytes == 3) {
227 dest_step -= 2;
228 }
229 for (int row = row_start; row < row_end; row++) {
230 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
231 dest_clip.left;
232 uint8_t* dest_scan = dest_buf + dest_col * nBytes;
233 if (bYFlip) {
234 dest_scan += (result_height - 1) * dest_pitch;
235 }
236 if (nBytes == 4) {
237 uint32_t* src_scan = (uint32_t*)GetScanline(row) + col_start;
238 for (int col = col_start; col < col_end; col++) {
239 *(uint32_t*)dest_scan = *src_scan++;
240 dest_scan += dest_step;
241 }
242 } else {
243 const uint8_t* src_scan = GetScanline(row) + col_start * nBytes;
244 if (nBytes == 1) {
245 for (int col = col_start; col < col_end; col++) {
246 *dest_scan = *src_scan++;
247 dest_scan += dest_step;
248 }
249 } else {
250 for (int col = col_start; col < col_end; col++) {
251 *dest_scan++ = *src_scan++;
252 *dest_scan++ = *src_scan++;
253 *dest_scan = *src_scan++;
254 dest_scan += dest_step;
255 }
256 }
257 }
258 }
259 }
260 if (m_pAlphaMask) {
261 dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch();
262 dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer();
263 int dest_step = bYFlip ? -dest_pitch : dest_pitch;
264 for (int row = row_start; row < row_end; row++) {
265 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
266 dest_clip.left;
267 uint8_t* dest_scan = dest_buf + dest_col;
268 if (bYFlip) {
269 dest_scan += (result_height - 1) * dest_pitch;
270 }
271 const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start;
272 for (int col = col_start; col < col_end; col++) {
273 *dest_scan = *src_scan++;
274 dest_scan += dest_step;
275 }
276 }
277 }
278 return pTransBitmap;
279 }
280
281 #define FIX16_005 0.05f
FXDIB_SwapClipBox(FX_RECT & clip,int width,int height,bool bFlipX,bool bFlipY)282 FX_RECT FXDIB_SwapClipBox(FX_RECT& clip,
283 int width,
284 int height,
285 bool bFlipX,
286 bool bFlipY) {
287 FX_RECT rect;
288 if (bFlipY) {
289 rect.left = height - clip.top;
290 rect.right = height - clip.bottom;
291 } else {
292 rect.left = clip.top;
293 rect.right = clip.bottom;
294 }
295 if (bFlipX) {
296 rect.top = width - clip.left;
297 rect.bottom = width - clip.right;
298 } else {
299 rect.top = clip.left;
300 rect.bottom = clip.right;
301 }
302 rect.Normalize();
303 return rect;
304 }
305
TransformTo(const CFX_Matrix * pDestMatrix,int & result_left,int & result_top,uint32_t flags,const FX_RECT * pDestClip) const306 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::TransformTo(
307 const CFX_Matrix* pDestMatrix,
308 int& result_left,
309 int& result_top,
310 uint32_t flags,
311 const FX_RECT* pDestClip) const {
312 CFX_ImageTransformer transformer(this, pDestMatrix, flags, pDestClip);
313 transformer.Start();
314 transformer.Continue(nullptr);
315 result_left = transformer.result().left;
316 result_top = transformer.result().top;
317 return transformer.DetachBitmap();
318 }
319
StretchTo(int dest_width,int dest_height,uint32_t flags,const FX_RECT * pClip) const320 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::StretchTo(
321 int dest_width,
322 int dest_height,
323 uint32_t flags,
324 const FX_RECT* pClip) const {
325 FX_RECT clip_rect(0, 0, FXSYS_abs(dest_width), FXSYS_abs(dest_height));
326 if (pClip)
327 clip_rect.Intersect(*pClip);
328
329 if (clip_rect.IsEmpty())
330 return nullptr;
331
332 if (dest_width == m_Width && dest_height == m_Height)
333 return Clone(&clip_rect);
334
335 CFX_BitmapStorer storer;
336 CFX_ImageStretcher stretcher(&storer, this, dest_width, dest_height,
337 clip_rect, flags);
338 if (stretcher.Start())
339 stretcher.Continue(nullptr);
340
341 return storer.Detach();
342 }
343
CFX_ImageTransformer(const CFX_DIBSource * pSrc,const CFX_Matrix * pMatrix,int flags,const FX_RECT * pClip)344 CFX_ImageTransformer::CFX_ImageTransformer(const CFX_DIBSource* pSrc,
345 const CFX_Matrix* pMatrix,
346 int flags,
347 const FX_RECT* pClip)
348 : m_pSrc(pSrc),
349 m_pMatrix(pMatrix),
350 m_pClip(pClip),
351 m_Flags(flags),
352 m_Status(0) {}
353
~CFX_ImageTransformer()354 CFX_ImageTransformer::~CFX_ImageTransformer() {}
355
Start()356 bool CFX_ImageTransformer::Start() {
357 CFX_FloatRect unit_rect = m_pMatrix->GetUnitRect();
358 FX_RECT result_rect = unit_rect.GetClosestRect();
359 FX_RECT result_clip = result_rect;
360 if (m_pClip)
361 result_clip.Intersect(*m_pClip);
362
363 if (result_clip.IsEmpty())
364 return false;
365
366 m_result = result_clip;
367 if (FXSYS_fabs(m_pMatrix->a) < FXSYS_fabs(m_pMatrix->b) / 20 &&
368 FXSYS_fabs(m_pMatrix->d) < FXSYS_fabs(m_pMatrix->c) / 20 &&
369 FXSYS_fabs(m_pMatrix->a) < 0.5f && FXSYS_fabs(m_pMatrix->d) < 0.5f) {
370 int dest_width = result_rect.Width();
371 int dest_height = result_rect.Height();
372 result_clip.Offset(-result_rect.left, -result_rect.top);
373 result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
374 m_pMatrix->c > 0, m_pMatrix->b < 0);
375 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
376 &m_Storer, m_pSrc, dest_height, dest_width, result_clip, m_Flags);
377 m_Stretcher->Start();
378 m_Status = 1;
379 return true;
380 }
381 if (FXSYS_fabs(m_pMatrix->b) < FIX16_005 &&
382 FXSYS_fabs(m_pMatrix->c) < FIX16_005) {
383 int dest_width = m_pMatrix->a > 0 ? (int)FXSYS_ceil(m_pMatrix->a)
384 : (int)FXSYS_floor(m_pMatrix->a);
385 int dest_height = m_pMatrix->d > 0 ? (int)-FXSYS_ceil(m_pMatrix->d)
386 : (int)-FXSYS_floor(m_pMatrix->d);
387 result_clip.Offset(-result_rect.left, -result_rect.top);
388 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
389 &m_Storer, m_pSrc, dest_width, dest_height, result_clip, m_Flags);
390 m_Stretcher->Start();
391 m_Status = 2;
392 return true;
393 }
394 int stretch_width = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->a, m_pMatrix->b));
395 int stretch_height = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->c, m_pMatrix->d));
396 CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
397 (FX_FLOAT)(stretch_height));
398 stretch2dest.Concat(
399 CFX_Matrix(m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
400 m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
401 m_pMatrix->e, m_pMatrix->f));
402 m_dest2stretch.SetReverse(stretch2dest);
403
404 CFX_FloatRect clip_rect_f(result_clip);
405 m_dest2stretch.TransformRect(clip_rect_f);
406 m_StretchClip = clip_rect_f.GetOuterRect();
407 m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
408 m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
409 &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip, m_Flags);
410 m_Stretcher->Start();
411 m_Status = 3;
412 return true;
413 }
414
Continue(IFX_Pause * pPause)415 bool CFX_ImageTransformer::Continue(IFX_Pause* pPause) {
416 if (m_Status == 1) {
417 if (m_Stretcher->Continue(pPause))
418 return true;
419
420 if (m_Storer.GetBitmap()) {
421 m_Storer.Replace(
422 m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
423 }
424 return false;
425 }
426
427 if (m_Status == 2)
428 return m_Stretcher->Continue(pPause);
429
430 if (m_Status != 3)
431 return false;
432
433 if (m_Stretcher->Continue(pPause))
434 return true;
435
436 int stretch_width = m_StretchClip.Width();
437 int stretch_height = m_StretchClip.Height();
438 if (!m_Storer.GetBitmap())
439 return false;
440
441 const uint8_t* stretch_buf = m_Storer.GetBitmap()->GetBuffer();
442 const uint8_t* stretch_buf_mask = nullptr;
443 if (m_Storer.GetBitmap()->m_pAlphaMask)
444 stretch_buf_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetBuffer();
445
446 int stretch_pitch = m_Storer.GetBitmap()->GetPitch();
447 std::unique_ptr<CFX_DIBitmap> pTransformed(new CFX_DIBitmap);
448 FXDIB_Format transformF = GetTransformedFormat(m_Stretcher->source());
449 if (!pTransformed->Create(m_result.Width(), m_result.Height(), transformF))
450 return false;
451
452 pTransformed->Clear(0);
453 if (pTransformed->m_pAlphaMask)
454 pTransformed->m_pAlphaMask->Clear(0);
455
456 CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_result.left),
457 (FX_FLOAT)(m_result.top));
458 result2stretch.Concat(m_dest2stretch);
459 result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
460 if (!stretch_buf_mask && pTransformed->m_pAlphaMask) {
461 pTransformed->m_pAlphaMask->Clear(0xff000000);
462 } else if (pTransformed->m_pAlphaMask) {
463 int stretch_pitch_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetPitch();
464 if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
465 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
466 for (int row = 0; row < m_result.Height(); row++) {
467 uint8_t* dest_pos_mask =
468 (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
469 for (int col = 0; col < m_result.Width(); col++) {
470 int src_col_l, src_row_l, res_x, res_y;
471 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
472 res_y);
473 if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
474 src_row_l <= stretch_height) {
475 if (src_col_l == stretch_width) {
476 src_col_l--;
477 }
478 if (src_row_l == stretch_height) {
479 src_row_l--;
480 }
481 int src_col_r = src_col_l + 1;
482 int src_row_r = src_row_l + 1;
483 if (src_col_r == stretch_width) {
484 src_col_r--;
485 }
486 if (src_row_r == stretch_height) {
487 src_row_r--;
488 }
489 int row_offset_l = src_row_l * stretch_pitch_mask;
490 int row_offset_r = src_row_r * stretch_pitch_mask;
491 *dest_pos_mask =
492 bilinear_interpol(stretch_buf_mask, row_offset_l, row_offset_r,
493 src_col_l, src_col_r, res_x, res_y, 1, 0);
494 }
495 dest_pos_mask++;
496 }
497 }
498 } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
499 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
500 for (int row = 0; row < m_result.Height(); row++) {
501 uint8_t* dest_pos_mask =
502 (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
503 for (int col = 0; col < m_result.Width(); col++) {
504 int src_col_l, src_row_l, res_x, res_y;
505 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
506 res_y);
507 if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
508 src_row_l <= stretch_height) {
509 int pos_pixel[8];
510 int u_w[4], v_w[4];
511 if (src_col_l == stretch_width) {
512 src_col_l--;
513 }
514 if (src_row_l == stretch_height) {
515 src_row_l--;
516 }
517 bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
518 res_x, res_y, stretch_width, stretch_height);
519 *dest_pos_mask =
520 bicubic_interpol(stretch_buf_mask, stretch_pitch_mask,
521 pos_pixel, u_w, v_w, res_x, res_y, 1, 0);
522 }
523 dest_pos_mask++;
524 }
525 }
526 } else {
527 CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
528 for (int row = 0; row < m_result.Height(); row++) {
529 uint8_t* dest_pos_mask =
530 (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
531 for (int col = 0; col < m_result.Width(); col++) {
532 int src_col, src_row;
533 result2stretch_fix.Transform(col, row, src_col, src_row);
534 if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
535 src_row <= stretch_height) {
536 if (src_col == stretch_width) {
537 src_col--;
538 }
539 if (src_row == stretch_height) {
540 src_row--;
541 }
542 *dest_pos_mask =
543 stretch_buf_mask[src_row * stretch_pitch_mask + src_col];
544 }
545 dest_pos_mask++;
546 }
547 }
548 }
549 }
550 if (m_Storer.GetBitmap()->IsAlphaMask()) {
551 if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
552 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
553 for (int row = 0; row < m_result.Height(); row++) {
554 uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
555 for (int col = 0; col < m_result.Width(); col++) {
556 int src_col_l, src_row_l, res_x, res_y;
557 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
558 res_y);
559 if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
560 src_row_l <= stretch_height) {
561 if (src_col_l == stretch_width) {
562 src_col_l--;
563 }
564 if (src_row_l == stretch_height) {
565 src_row_l--;
566 }
567 int src_col_r = src_col_l + 1;
568 int src_row_r = src_row_l + 1;
569 if (src_col_r == stretch_width) {
570 src_col_r--;
571 }
572 if (src_row_r == stretch_height) {
573 src_row_r--;
574 }
575 int row_offset_l = src_row_l * stretch_pitch;
576 int row_offset_r = src_row_r * stretch_pitch;
577 *dest_scan =
578 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
579 src_col_l, src_col_r, res_x, res_y, 1, 0);
580 }
581 dest_scan++;
582 }
583 }
584 } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
585 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
586 for (int row = 0; row < m_result.Height(); row++) {
587 uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
588 for (int col = 0; col < m_result.Width(); col++) {
589 int src_col_l, src_row_l, res_x, res_y;
590 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
591 res_y);
592 if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
593 src_row_l <= stretch_height) {
594 int pos_pixel[8];
595 int u_w[4], v_w[4];
596 if (src_col_l == stretch_width) {
597 src_col_l--;
598 }
599 if (src_row_l == stretch_height) {
600 src_row_l--;
601 }
602 bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
603 res_x, res_y, stretch_width, stretch_height);
604 *dest_scan = bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
605 u_w, v_w, res_x, res_y, 1, 0);
606 }
607 dest_scan++;
608 }
609 }
610 } else {
611 CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
612 for (int row = 0; row < m_result.Height(); row++) {
613 uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
614 for (int col = 0; col < m_result.Width(); col++) {
615 int src_col, src_row;
616 result2stretch_fix.Transform(col, row, src_col, src_row);
617 if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
618 src_row <= stretch_height) {
619 if (src_col == stretch_width) {
620 src_col--;
621 }
622 if (src_row == stretch_height) {
623 src_row--;
624 }
625 const uint8_t* src_pixel =
626 stretch_buf + stretch_pitch * src_row + src_col;
627 *dest_scan = *src_pixel;
628 }
629 dest_scan++;
630 }
631 }
632 }
633 } else {
634 int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
635 if (Bpp == 1) {
636 uint32_t argb[256];
637 FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
638 if (pPal) {
639 for (int i = 0; i < 256; i++) {
640 argb[i] = pPal[i];
641 }
642 } else {
643 if (m_Storer.GetBitmap()->IsCmykImage()) {
644 for (int i = 0; i < 256; i++) {
645 argb[i] = 255 - i;
646 }
647 } else {
648 for (int i = 0; i < 256; i++) {
649 argb[i] = 0xff000000 | (i * 0x010101);
650 }
651 }
652 }
653 int destBpp = pTransformed->GetBPP() / 8;
654 if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
655 !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
656 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
657 for (int row = 0; row < m_result.Height(); row++) {
658 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
659 for (int col = 0; col < m_result.Width(); col++) {
660 int src_col_l, src_row_l, res_x, res_y;
661 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
662 res_y);
663 if (src_col_l >= 0 && src_col_l <= stretch_width &&
664 src_row_l >= 0 && src_row_l <= stretch_height) {
665 if (src_col_l == stretch_width) {
666 src_col_l--;
667 }
668 if (src_row_l == stretch_height) {
669 src_row_l--;
670 }
671 int src_col_r = src_col_l + 1;
672 int src_row_r = src_row_l + 1;
673 if (src_col_r == stretch_width) {
674 src_col_r--;
675 }
676 if (src_row_r == stretch_height) {
677 src_row_r--;
678 }
679 int row_offset_l = src_row_l * stretch_pitch;
680 int row_offset_r = src_row_r * stretch_pitch;
681 uint32_t r_bgra_cmyk = argb[bilinear_interpol(
682 stretch_buf, row_offset_l, row_offset_r, src_col_l, src_col_r,
683 res_x, res_y, 1, 0)];
684 if (transformF == FXDIB_Rgba) {
685 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
686 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
687 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
688 } else {
689 *(uint32_t*)dest_pos = r_bgra_cmyk;
690 }
691 }
692 dest_pos += destBpp;
693 }
694 }
695 } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
696 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
697 for (int row = 0; row < m_result.Height(); row++) {
698 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
699 for (int col = 0; col < m_result.Width(); col++) {
700 int src_col_l, src_row_l, res_x, res_y;
701 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
702 res_y);
703 if (src_col_l >= 0 && src_col_l <= stretch_width &&
704 src_row_l >= 0 && src_row_l <= stretch_height) {
705 int pos_pixel[8];
706 int u_w[4], v_w[4];
707 if (src_col_l == stretch_width) {
708 src_col_l--;
709 }
710 if (src_row_l == stretch_height) {
711 src_row_l--;
712 }
713 bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
714 res_x, res_y, stretch_width,
715 stretch_height);
716 uint32_t r_bgra_cmyk =
717 argb[bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
718 u_w, v_w, res_x, res_y, 1, 0)];
719 if (transformF == FXDIB_Rgba) {
720 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
721 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
722 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
723 } else {
724 *(uint32_t*)dest_pos = r_bgra_cmyk;
725 }
726 }
727 dest_pos += destBpp;
728 }
729 }
730 } else {
731 CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
732 for (int row = 0; row < m_result.Height(); row++) {
733 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
734 for (int col = 0; col < m_result.Width(); col++) {
735 int src_col, src_row;
736 result2stretch_fix.Transform(col, row, src_col, src_row);
737 if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
738 src_row <= stretch_height) {
739 if (src_col == stretch_width) {
740 src_col--;
741 }
742 if (src_row == stretch_height) {
743 src_row--;
744 }
745 uint32_t r_bgra_cmyk =
746 argb[stretch_buf[src_row * stretch_pitch + src_col]];
747 if (transformF == FXDIB_Rgba) {
748 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
749 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
750 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
751 } else {
752 *(uint32_t*)dest_pos = r_bgra_cmyk;
753 }
754 }
755 dest_pos += destBpp;
756 }
757 }
758 }
759 } else {
760 bool bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
761 int destBpp = pTransformed->GetBPP() / 8;
762 if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
763 !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
764 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
765 for (int row = 0; row < m_result.Height(); row++) {
766 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
767 for (int col = 0; col < m_result.Width(); col++) {
768 int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
769 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
770 res_y);
771 if (src_col_l >= 0 && src_col_l <= stretch_width &&
772 src_row_l >= 0 && src_row_l <= stretch_height) {
773 if (src_col_l == stretch_width) {
774 src_col_l--;
775 }
776 if (src_row_l == stretch_height) {
777 src_row_l--;
778 }
779 int src_col_r = src_col_l + 1;
780 int src_row_r = src_row_l + 1;
781 if (src_col_r == stretch_width) {
782 src_col_r--;
783 }
784 if (src_row_r == stretch_height) {
785 src_row_r--;
786 }
787 int row_offset_l = src_row_l * stretch_pitch;
788 int row_offset_r = src_row_r * stretch_pitch;
789 uint8_t r_pos_red_y_r =
790 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
791 src_col_l, src_col_r, res_x, res_y, Bpp, 2);
792 uint8_t r_pos_green_m_r =
793 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
794 src_col_l, src_col_r, res_x, res_y, Bpp, 1);
795 uint8_t r_pos_blue_c_r =
796 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
797 src_col_l, src_col_r, res_x, res_y, Bpp, 0);
798 if (bHasAlpha) {
799 if (transformF != FXDIB_Argb) {
800 if (transformF == FXDIB_Rgba) {
801 dest_pos[0] = r_pos_blue_c_r;
802 dest_pos[1] = r_pos_green_m_r;
803 dest_pos[2] = r_pos_red_y_r;
804 } else {
805 r_pos_k_r = bilinear_interpol(
806 stretch_buf, row_offset_l, row_offset_r, src_col_l,
807 src_col_r, res_x, res_y, Bpp, 3);
808 *(uint32_t*)dest_pos =
809 FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
810 r_pos_red_y_r, r_pos_k_r));
811 }
812 } else {
813 uint8_t r_pos_a_r = bilinear_interpol(
814 stretch_buf, row_offset_l, row_offset_r, src_col_l,
815 src_col_r, res_x, res_y, Bpp, 3);
816 *(uint32_t*)dest_pos = FXARGB_TODIB(
817 FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
818 r_pos_blue_c_r));
819 }
820 } else {
821 r_pos_k_r = 0xff;
822 if (transformF == FXDIB_Cmyka) {
823 r_pos_k_r = bilinear_interpol(
824 stretch_buf, row_offset_l, row_offset_r, src_col_l,
825 src_col_r, res_x, res_y, Bpp, 3);
826 *(uint32_t*)dest_pos =
827 FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
828 r_pos_red_y_r, r_pos_k_r));
829 } else {
830 *(uint32_t*)dest_pos = FXARGB_TODIB(
831 FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
832 r_pos_blue_c_r));
833 }
834 }
835 }
836 dest_pos += destBpp;
837 }
838 }
839 } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
840 CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
841 for (int row = 0; row < m_result.Height(); row++) {
842 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
843 for (int col = 0; col < m_result.Width(); col++) {
844 int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
845 result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
846 res_y);
847 if (src_col_l >= 0 && src_col_l <= stretch_width &&
848 src_row_l >= 0 && src_row_l <= stretch_height) {
849 int pos_pixel[8];
850 int u_w[4], v_w[4];
851 if (src_col_l == stretch_width) {
852 src_col_l--;
853 }
854 if (src_row_l == stretch_height) {
855 src_row_l--;
856 }
857 bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
858 res_x, res_y, stretch_width,
859 stretch_height);
860 uint8_t r_pos_red_y_r =
861 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
862 v_w, res_x, res_y, Bpp, 2);
863 uint8_t r_pos_green_m_r =
864 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
865 v_w, res_x, res_y, Bpp, 1);
866 uint8_t r_pos_blue_c_r =
867 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
868 v_w, res_x, res_y, Bpp, 0);
869 if (bHasAlpha) {
870 if (transformF != FXDIB_Argb) {
871 if (transformF == FXDIB_Rgba) {
872 dest_pos[0] = r_pos_blue_c_r;
873 dest_pos[1] = r_pos_green_m_r;
874 dest_pos[2] = r_pos_red_y_r;
875 } else {
876 r_pos_k_r =
877 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
878 u_w, v_w, res_x, res_y, Bpp, 3);
879 *(uint32_t*)dest_pos =
880 FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
881 r_pos_red_y_r, r_pos_k_r));
882 }
883 } else {
884 uint8_t r_pos_a_r =
885 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
886 u_w, v_w, res_x, res_y, Bpp, 3);
887 *(uint32_t*)dest_pos = FXARGB_TODIB(
888 FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
889 r_pos_blue_c_r));
890 }
891 } else {
892 r_pos_k_r = 0xff;
893 if (transformF == FXDIB_Cmyka) {
894 r_pos_k_r =
895 bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
896 u_w, v_w, res_x, res_y, Bpp, 3);
897 *(uint32_t*)dest_pos =
898 FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
899 r_pos_red_y_r, r_pos_k_r));
900 } else {
901 *(uint32_t*)dest_pos = FXARGB_TODIB(
902 FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
903 r_pos_blue_c_r));
904 }
905 }
906 }
907 dest_pos += destBpp;
908 }
909 }
910 } else {
911 CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
912 for (int row = 0; row < m_result.Height(); row++) {
913 uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
914 for (int col = 0; col < m_result.Width(); col++) {
915 int src_col, src_row;
916 result2stretch_fix.Transform(col, row, src_col, src_row);
917 if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
918 src_row <= stretch_height) {
919 if (src_col == stretch_width) {
920 src_col--;
921 }
922 if (src_row == stretch_height) {
923 src_row--;
924 }
925 const uint8_t* src_pos =
926 stretch_buf + src_row * stretch_pitch + src_col * Bpp;
927 if (bHasAlpha) {
928 if (transformF != FXDIB_Argb) {
929 if (transformF == FXDIB_Rgba) {
930 dest_pos[0] = src_pos[0];
931 dest_pos[1] = src_pos[1];
932 dest_pos[2] = src_pos[2];
933 } else {
934 *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
935 src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
936 }
937 } else {
938 *(uint32_t*)dest_pos = FXARGB_TODIB(FXARGB_MAKE(
939 src_pos[3], src_pos[2], src_pos[1], src_pos[0]));
940 }
941 } else {
942 if (transformF == FXDIB_Cmyka) {
943 *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
944 src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
945 } else {
946 *(uint32_t*)dest_pos = FXARGB_TODIB(
947 FXARGB_MAKE(0xff, src_pos[2], src_pos[1], src_pos[0]));
948 }
949 }
950 }
951 dest_pos += destBpp;
952 }
953 }
954 }
955 }
956 }
957 m_Storer.Replace(std::move(pTransformed));
958 return false;
959 }
960
DetachBitmap()961 std::unique_ptr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
962 return m_Storer.Detach();
963 }
964