7#include "core/fxge/dib/cfx_imagetransformer.h"
16#include "core/fxcrt/check.h"
17#include "core/fxcrt/compiler_specific.h"
18#include "core/fxcrt/fx_system.h"
19#include "core/fxcrt/notreached.h"
20#include "core/fxcrt/numerics/safe_conversions.h"
21#include "core/fxcrt/stl_util.h"
22#include "core/fxge/dib/cfx_dibitmap.h"
23#include "core/fxge/dib/cfx_imagestretcher.h"
24#include "core/fxge/dib/fx_dib.h"
28constexpr int kBase = 256;
29constexpr float kFix16 = 0.05f;
30constexpr uint8_t kOpaqueAlpha = 0xff;
32uint8_t BilinearInterpolate(
const uint8_t* buf,
36 const int i_resx = 255 - data
.res_x;
37 const int col_bpp_l = data
.src_col_l * bytes_per_pixel;
38 const int col_bpp_r = data
.src_col_r * bytes_per_pixel;
42 const uint8_t* src_pos0 = buf_u + col_bpp_l;
43 const uint8_t* src_pos1 = buf_u + col_bpp_r;
44 const uint8_t* src_pos2 = buf_d + col_bpp_l;
45 const uint8_t* src_pos3 = buf_d + col_bpp_r;
46 uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * data
.res_x) >> 8;
47 uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * data
.res_x) >> 8;
48 return (r_pos_0 * (255 - data
.res_y) + r_pos_1 * data
.res_y) >> 8;
52class CFX_BilinearMatrix {
54 explicit CFX_BilinearMatrix(
const CFX_Matrix& src)
62 void Transform(
int x,
int y,
int* x1,
int* y1,
int* res_x,
int* res_y)
const {
63 CFX_PointF val = TransformInternal(CFX_PointF(x, y));
64 *x1 =
pdfium::saturated_cast<
int>(val.x / kBase);
65 *y1 =
pdfium::saturated_cast<
int>(val.y / kBase);
66 *res_x =
static_cast<
int>(val.x) % kBase;
67 *res_y =
static_cast<
int>(val.y) % kBase;
68 if (*res_x < 0 && *res_x > -kBase)
69 *res_x = kBase + *res_x;
70 if (*res_y < 0 && *res_y > -kBase)
71 *res_y = kBase + *res_y;
76 return CFX_PointF(a * pt.x + c * pt.y + e + kBase / 2,
77 b * pt.x + d * pt.y + f + kBase / 2);
88bool InStretchBounds(
const FX_RECT& clip_rect,
int col,
int row) {
89 return col >= 0 && col <= clip_rect
.Width() && row >= 0 &&
93void AdjustCoords(
const FX_RECT& clip_rect,
int* col,
int* row) {
110 CFX_BilinearMatrix matrix_fix(calc_data
.matrix);
111 for (
int row = 0; row < result_rect
.Height(); row++) {
112 uint8_t* dest = calc_data
.bitmap->GetWritableScanline(row).data();
113 for (
int col = 0; col < result_rect
.Width(); col++) {
143 FX_RECT result_clip = result_rect;
150 m_result
= result_clip;
151 if (fabs(m_matrix
.a) < fabs(m_matrix
.b) / 20 &&
152 fabs(m_matrix
.d) < fabs(m_matrix
.c) / 20 && fabs(m_matrix
.a) < 0.5f &&
153 fabs(m_matrix
.d) < 0.5f) {
154 int dest_width = result_rect
.Width();
158 m_matrix
.c > 0
, m_matrix
.b < 0
);
159 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
160 &m_Storer, m_pSrc, dest_height, dest_width, result_clip,
162 m_Stretcher->Start();
163 m_type = StretchType::kRotate;
166 if (fabs(m_matrix
.b) < kFix16 && fabs(m_matrix
.c) < kFix16) {
168 static_cast<
int>(m_matrix
.a > 0 ? ceil(m_matrix
.a) : floor(m_matrix
.a));
169 int dest_height =
static_cast<
int>(m_matrix
.d > 0 ? -ceil(m_matrix
.d)
170 : -floor(m_matrix
.d));
172 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
173 &m_Storer, m_pSrc, dest_width, dest_height, result_clip,
175 m_Stretcher->Start();
176 m_type = StretchType::kNormal;
180 int stretch_width =
static_cast<
int>(ceil(hypotf(m_matrix
.a, m_matrix
.b)));
181 if (stretch_width == 0) {
185 int stretch_height =
static_cast<
int>(ceil(hypotf(m_matrix
.c, m_matrix
.d)));
186 if (stretch_height == 0) {
193 m_matrix
.c / stretch_height
, m_matrix
.d / stretch_height
,
206 m_dest2stretch
= dest_to_strech;
207 m_StretchClip
= stretch_clip;
208 m_Stretcher = std::make_unique<CFX_ImageStretcher>(
209 &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip,
211 m_Stretcher->Start();
212 m_type = StretchType::kOther;
218 if (m_type == StretchType::kNone) {
222 if (m_Stretcher->Continue(pPause))
226 case StretchType::kNone:
229 case StretchType::kNormal:
231 case StretchType::kRotate:
232 ContinueRotate(pPause);
234 case StretchType::kOther:
235 ContinueOther(pPause);
241 if (m_Storer.GetBitmap()) {
243 m_Storer.GetBitmap()->SwapXY(m_matrix.c > 0, m_matrix.b < 0));
248 if (!m_Storer.GetBitmap())
251 auto pTransformed =
pdfium::MakeRetain<CFX_DIBitmap>();
254 FXDIB_Format dest_format = m_Stretcher->source()->IsMaskFormat()
255 ? FXDIB_Format::k8bppMask
256 : FXDIB_Format::kBgra;
266 CalcData calc_data = {pTransformed.Get(), result2stretch,
267 m_Storer.GetBitmap()->GetBuffer().data(),
268 m_Storer.GetBitmap()->GetPitch()};
269 if (m_Storer.GetBitmap()->IsMaskFormat()) {
270 CalcAlpha(calc_data);
272 const int src_bytes_per_pixel = m_Storer.GetBitmap()->GetBPP() / 8;
273 if (src_bytes_per_pixel == 1) {
276 CalcColor(calc_data, dest_format, src_bytes_per_pixel);
279 m_Storer.Replace(std::move(pTransformed));
283 return m_Storer.Detach();
287 auto func = [&calc_data](
const BilinearData& data, uint8_t* dest) {
288 *dest = BilinearInterpolate(calc_data
.buf, data, 1, 0);
290 DoBilinearLoop(calc_data, m_result, m_StretchClip, 1, func);
294 std::array<uint32_t, 256> argb;
295 if (m_Storer.GetBitmap()->HasPalette()) {
296 pdfium::span<
const uint32_t> palette =
297 m_Storer.GetBitmap()->GetPaletteSpan();
298 fxcrt::Copy(palette.first(argb.size()), argb);
300 for (uint32_t i = 0; i < argb.size(); ++i) {
305 auto func = [&calc_data, &argb](
const BilinearData& data, uint8_t* dest) {
306 uint8_t idx = BilinearInterpolate(calc_data
.buf, data, 1, 0);
307 *
reinterpret_cast<uint32_t*>(dest) = argb[idx];
309 DoBilinearLoop(calc_data, m_result, m_StretchClip, dest_bytes_per_pixel,
315 int src_bytes_per_pixel) {
316 DCHECK(dest_format == FXDIB_Format::k8bppMask ||
317 dest_format == FXDIB_Format::kBgra);
319 if (!m_Storer.GetBitmap()->IsAlphaFormat()) {
320 auto func = [&calc_data, src_bytes_per_pixel](
const BilinearData& data,
323 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 0);
325 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 1);
327 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 2);
328 *
reinterpret_cast<uint32_t*>(dest) =
ArgbEncode(kOpaqueAlpha
, r
, g
, b
);
330 DoBilinearLoop(calc_data, m_result, m_StretchClip, dest_bytes_per_pixel,
336 auto func = [&calc_data, src_bytes_per_pixel](
const BilinearData& data,
339 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 0);
341 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 1);
343 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 2);
345 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 3);
348 DoBilinearLoop(calc_data, m_result, m_StretchClip, dest_bytes_per_pixel,
353 auto func = [&calc_data, src_bytes_per_pixel](
const BilinearData& data,
356 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 0);
358 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 1);
360 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 2);
362 BilinearInterpolate(calc_data
.buf, data, src_bytes_per_pixel, 3);
365 DoBilinearLoop(calc_data, m_result, m_StretchClip, dest_bytes_per_pixel,
FX_RECT GetClosestRect() const
CFX_FloatRect(const FX_RECT &rect)
FX_RECT GetOuterRect() const
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_FloatRect TransformRect(const CFX_FloatRect &rect) const
void Translate(int32_t x, int32_t y)
CFX_FloatRect GetUnitRect() const
CFX_Matrix GetInverse() const
constexpr CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void Concat(const CFX_Matrix &right)
CFX_Matrix(const CFX_Matrix &other)=default
CFX_PTemplate< float > CFX_PointF
constexpr FX_CMYK CmykEncode(uint32_t c, uint32_t m, uint32_t y, uint32_t k)
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
#define FXCMYK_TODIB(cmyk)
int FXSYS_roundf(float f)
#define NOTREACHED_NORETURN()
void Offset(int dx, int dy)
FX_RECT & operator=(const FX_RECT &that)=default
void Intersect(int l, int t, int r, int b)
FX_RECT SwappedClipBox(int width, int height, bool bFlipX, bool bFlipY) const
void Intersect(const FX_RECT &src)