Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
fpdf_transformpage.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
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 "public/fpdf_transformpage.h"
8
9#include <memory>
10#include <sstream>
11
12#include "constants/page_object.h"
13#include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h"
14#include "core/fpdfapi/page/cpdf_clippath.h"
15#include "core/fpdfapi/page/cpdf_page.h"
16#include "core/fpdfapi/page/cpdf_pageobject.h"
17#include "core/fpdfapi/page/cpdf_path.h"
18#include "core/fpdfapi/parser/cpdf_array.h"
19#include "core/fpdfapi/parser/cpdf_dictionary.h"
20#include "core/fpdfapi/parser/cpdf_document.h"
21#include "core/fpdfapi/parser/cpdf_number.h"
22#include "core/fpdfapi/parser/cpdf_reference.h"
23#include "core/fpdfapi/parser/cpdf_stream.h"
24#include "core/fxcrt/fx_string_wrappers.h"
25#include "core/fxcrt/stl_util.h"
26#include "core/fxge/cfx_fillrenderoptions.h"
27#include "core/fxge/cfx_path.h"
28#include "fpdfsdk/cpdfsdk_helpers.h"
29#include "third_party/base/containers/span.h"
30#include "third_party/base/numerics/safe_conversions.h"
31
32namespace {
33
34void SetBoundingBox(CPDF_Page* page,
35 const ByteString& key,
36 const CFX_FloatRect& rect) {
37 if (!page)
38 return;
39
40 page->GetMutableDict()->SetRectFor(key, rect);
42}
43
44bool GetBoundingBox(const CPDF_Page* page,
45 const ByteString& key,
46 float* left,
47 float* bottom,
48 float* right,
49 float* top) {
50 if (!page || !left || !bottom || !right || !top)
51 return false;
52
53 RetainPtr<const CPDF_Array> pArray = page->GetDict()->GetArrayFor(key);
54 if (!pArray)
55 return false;
56
57 *left = pArray->GetFloatAt(0);
58 *bottom = pArray->GetFloatAt(1);
59 *right = pArray->GetFloatAt(2);
60 *top = pArray->GetFloatAt(3);
61 return true;
62}
63
64RetainPtr<CPDF_Object> GetPageContent(CPDF_Dictionary* pPageDict) {
66}
67
68void OutputPath(fxcrt::ostringstream& buf, CPDF_Path path) {
69 const CFX_Path* pPath = path.GetObject();
70 if (!pPath)
71 return;
72
73 pdfium::span<const CFX_Path::Point> points = pPath->GetPoints();
74 if (path.IsRect()) {
75 CFX_PointF diff = points[2].m_Point - points[0].m_Point;
76 buf << points[0].m_Point.x << " " << points[0].m_Point.y << " " << diff.x
77 << " " << diff.y << " re\n";
78 return;
79 }
80
81 for (size_t i = 0; i < points.size(); ++i) {
82 buf << points[i].m_Point.x << " " << points[i].m_Point.y;
83 CFX_Path::Point::Type point_type = points[i].m_Type;
84 if (point_type == CFX_Path::Point::Type::kMove) {
85 buf << " m\n";
86 } else if (point_type == CFX_Path::Point::Type::kBezier) {
87 buf << " " << points[i + 1].m_Point.x << " " << points[i + 1].m_Point.y
88 << " " << points[i + 2].m_Point.x << " " << points[i + 2].m_Point.y;
89 buf << " c";
90 if (points[i + 2].m_CloseFigure)
91 buf << " h";
92 buf << "\n";
93
94 i += 2;
95 } else if (point_type == CFX_Path::Point::Type::kLine) {
96 buf << " l";
97 if (points[i].m_CloseFigure)
98 buf << " h";
99 buf << "\n";
100 }
101 }
102}
103
104} // namespace
105
107 float left,
108 float bottom,
109 float right,
110 float top) {
111 SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kMediaBox,
112 CFX_FloatRect(left, bottom, right, top));
113}
114
116 float left,
117 float bottom,
118 float right,
119 float top) {
120 SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kCropBox,
121 CFX_FloatRect(left, bottom, right, top));
122}
123
125 float left,
126 float bottom,
127 float right,
128 float top) {
129 SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kBleedBox,
130 CFX_FloatRect(left, bottom, right, top));
131}
132
134 float left,
135 float bottom,
136 float right,
137 float top) {
138 SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kTrimBox,
139 CFX_FloatRect(left, bottom, right, top));
140}
141
143 float left,
144 float bottom,
145 float right,
146 float top) {
147 SetBoundingBox(CPDFPageFromFPDFPage(page), pdfium::page_object::kArtBox,
148 CFX_FloatRect(left, bottom, right, top));
149}
150
152 float* left,
153 float* bottom,
154 float* right,
155 float* top) {
156 return GetBoundingBox(CPDFPageFromFPDFPage(page),
157 pdfium::page_object::kMediaBox, left, bottom, right,
158 top);
159}
160
162 float* left,
163 float* bottom,
164 float* right,
165 float* top) {
166 return GetBoundingBox(CPDFPageFromFPDFPage(page),
167 pdfium::page_object::kCropBox, left, bottom, right,
168 top);
169}
170
172 float* left,
173 float* bottom,
174 float* right,
175 float* top) {
176 return GetBoundingBox(CPDFPageFromFPDFPage(page),
177 pdfium::page_object::kBleedBox, left, bottom, right,
178 top);
179}
180
182 float* left,
183 float* bottom,
184 float* right,
185 float* top) {
186 return GetBoundingBox(CPDFPageFromFPDFPage(page),
187 pdfium::page_object::kTrimBox, left, bottom, right,
188 top);
189}
190
192 float* left,
193 float* bottom,
194 float* right,
195 float* top) {
196 return GetBoundingBox(CPDFPageFromFPDFPage(page),
197 pdfium::page_object::kArtBox, left, bottom, right, top);
198}
199
202 const FS_MATRIX* matrix,
203 const FS_RECTF* clipRect) {
204 if (!matrix && !clipRect)
205 return false;
206
207 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
208 if (!pPage)
209 return false;
210
211 RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
212 RetainPtr<CPDF_Object> pContentObj = GetPageContent(pPageDict.Get());
213 if (!pContentObj)
214 return false;
215
216 CPDF_Document* pDoc = pPage->GetDocument();
217 if (!pDoc)
218 return false;
219
220 fxcrt::ostringstream text_buf;
221 text_buf << "q ";
222
223 if (clipRect) {
225 rect.Normalize();
226 WriteRect(text_buf, rect) << " re W* n ";
227 }
228 if (matrix)
229 WriteMatrix(text_buf, CFXMatrixFromFSMatrix(*matrix)) << " cm ";
230
231 auto pStream = pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
232 pStream->SetDataFromStringstream(&text_buf);
233
234 auto pEndStream =
235 pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
236 pEndStream->SetData(ByteStringView(" Q").raw_span());
237
238 RetainPtr<CPDF_Array> pContentArray = ToArray(pContentObj);
239 if (pContentArray) {
240 pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
241 pContentArray->AppendNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
242 } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
243 pContentArray = pDoc->NewIndirect<CPDF_Array>();
244 pContentArray->AppendNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
245 pContentArray->AppendNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
246 pContentArray->AppendNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
247 pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
248 pContentArray->GetObjNum());
249 }
250
251 // Need to transform the patterns as well.
252 RetainPtr<const CPDF_Dictionary> pRes =
253 pPageDict->GetDictFor(pdfium::page_object::kResources);
254 if (!pRes)
255 return true;
256
257 RetainPtr<const CPDF_Dictionary> pPatternDict = pRes->GetDictFor("Pattern");
258 if (!pPatternDict)
259 return true;
260
261 CPDF_DictionaryLocker locker(pPatternDict);
262 for (const auto& it : locker) {
263 RetainPtr<CPDF_Object> pObj = it.second;
264 if (pObj->IsReference())
265 pObj = pObj->GetMutableDirect();
266
267 RetainPtr<CPDF_Dictionary> pDict;
268 if (pObj->IsDictionary())
269 pDict.Reset(pObj->AsMutableDictionary());
270 else if (CPDF_Stream* pObjStream = pObj->AsMutableStream())
271 pDict = pObjStream->GetMutableDict();
272 else
273 continue;
274
275 if (matrix) {
276 CFX_Matrix m = CFXMatrixFromFSMatrix(*matrix);
277 pDict->SetMatrixFor("Matrix", pDict->GetMatrixFor("Matrix") * m);
278 }
279 }
280
281 return true;
282}
283
285FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object,
286 double a,
287 double b,
288 double c,
289 double d,
290 double e,
291 double f) {
293 if (!pPageObj)
294 return;
295
296 CFX_Matrix matrix((float)a, (float)b, (float)c, (float)d, (float)e, (float)f);
297
298 // Special treatment to shading object, because the ClipPath for shading
299 // object is already transformed.
300 if (!pPageObj->IsShading())
301 pPageObj->TransformClipPath(matrix);
302 pPageObj->TransformGeneralState(matrix);
303}
304
305FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV
306FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object) {
308 if (!pPageObj)
309 return nullptr;
310
312}
313
315 CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
316 if (!pClipPath || !pClipPath->HasRef())
317 return -1;
318
319 return pdfium::base::checked_cast<int>(pClipPath->GetPathCount());
320}
321
323FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index) {
324 CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
325 if (!pClipPath || !pClipPath->HasRef())
326 return -1;
327
328 if (path_index < 0 ||
329 static_cast<size_t>(path_index) >= pClipPath->GetPathCount()) {
330 return -1;
331 }
332
333 return fxcrt::CollectionSize<int>(pClipPath->GetPath(path_index).GetPoints());
334}
335
336FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV
337FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path,
338 int path_index,
339 int segment_index) {
340 CPDF_ClipPath* pClipPath = CPDFClipPathFromFPDFClipPath(clip_path);
341 if (!pClipPath || !pClipPath->HasRef())
342 return nullptr;
343
344 if (path_index < 0 ||
345 static_cast<size_t>(path_index) >= pClipPath->GetPathCount()) {
346 return nullptr;
347 }
348
349 pdfium::span<const CFX_Path::Point> points =
350 pClipPath->GetPath(path_index).GetPoints();
351 if (!fxcrt::IndexInBounds(points, segment_index))
352 return nullptr;
353
354 return FPDFPathSegmentFromFXPathPoint(&points[segment_index]);
355}
356
358 float bottom,
359 float right,
360 float top) {
361 CPDF_Path Path;
362 Path.AppendRect(left, bottom, right, top);
363
364 auto pNewClipPath = std::make_unique<CPDF_ClipPath>();
365 pNewClipPath->AppendPath(Path, CFX_FillRenderOptions::FillType::kEvenOdd);
366
367 // Caller takes ownership.
368 return FPDFClipPathFromCPDFClipPath(pNewClipPath.release());
369}
370
371FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) {
372 // Take ownership back from caller and destroy.
373 std::unique_ptr<CPDF_ClipPath>(CPDFClipPathFromFPDFClipPath(clipPath));
374}
375
377 FPDF_CLIPPATH clipPath) {
378 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
379 if (!pPage)
380 return;
381
382 RetainPtr<CPDF_Dictionary> pPageDict = pPage->GetMutableDict();
383 RetainPtr<CPDF_Object> pContentObj = GetPageContent(pPageDict.Get());
384 if (!pContentObj)
385 return;
386
387 fxcrt::ostringstream strClip;
389 for (size_t i = 0; i < pClipPath->GetPathCount(); ++i) {
390 CPDF_Path path = pClipPath->GetPath(i);
391 if (path.GetPoints().empty()) {
392 // Empty clipping (totally clipped out)
393 strClip << "0 0 m W n ";
394 } else {
395 OutputPath(strClip, path);
396 if (pClipPath->GetClipType(i) ==
398 strClip << "W n\n";
399 } else {
400 strClip << "W* n\n";
401 }
402 }
403 }
404 CPDF_Document* pDoc = pPage->GetDocument();
405 if (!pDoc)
406 return;
407
408 auto pStream = pDoc->NewIndirect<CPDF_Stream>(pDoc->New<CPDF_Dictionary>());
409 pStream->SetDataFromStringstream(&strClip);
410
411 RetainPtr<CPDF_Array> pArray = ToArray(pContentObj);
412 if (pArray) {
413 pArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
414 } else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
415 auto pContentArray = pDoc->NewIndirect<CPDF_Array>();
416 pContentArray->AppendNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
417 pContentArray->AppendNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
418 pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
419 pContentArray->GetObjNum());
420 }
421}
constexpr CFX_FloatRect(float l, float b, float r, float t)
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
bool HasRef() const
RetainPtr< CPDF_Object > GetMutableDirectObjectFor(const ByteString &key)
void TransformClipPath(const CFX_Matrix &matrix)
void TransformGeneralState(const CFX_Matrix &matrix)
CPDF_ClipPath & mutable_clip_path()
virtual bool IsShading() const
CPDF_Document * GetDocument() const override
Definition cpdf_page.cpp:51
void UpdateDimensions()
void AppendRect(float left, float bottom, float right, float top)
Definition cpdf_path.cpp:53
const CFX_Path * GetObject() const
Definition cpdf_path.h:42
bool IsRect() const
Definition cpdf_path.cpp:37
CPDF_ClipPath * CPDFClipPathFromFPDFClipPath(FPDF_CLIPPATH path)
CFX_FloatRect CFXFloatRectFromFSRectF(const FS_RECTF &rect)
FPDF_CLIPPATH FPDFClipPathFromCPDFClipPath(CPDF_ClipPath *path)
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
CPDF_PageObject * CPDFPageObjectFromFPDFPageObject(FPDF_PAGEOBJECT page_object)
CFX_Matrix CFXMatrixFromFSMatrix(const FS_MATRIX &matrix)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetArtBox(FPDF_PAGE page, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetTrimBox(FPDF_PAGE page, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetBleedBox(FPDF_PAGE page, float left, float bottom, float right, float top)
FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPaths(FPDF_CLIPPATH clip_path)
FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDFPageObj_GetClipPath(FPDF_PAGEOBJECT page_object)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetMediaBox(FPDF_PAGE page, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetCropBox(FPDF_PAGE page, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_TransFormWithClip(FPDF_PAGE page, const FS_MATRIX *matrix, const FS_RECTF *clipRect)
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFPage_GetBleedBox(FPDF_PAGE page, float *left, float *bottom, float *right, float *top)
FPDF_EXPORT void FPDF_CALLCONV FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, double a, double b, double c, double d, double e, double f)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetMediaBox(FPDF_PAGE page, float left, float bottom, float right, float top)
FPDF_EXPORT FPDF_PATHSEGMENT FPDF_CALLCONV FPDFClipPath_GetPathSegment(FPDF_CLIPPATH clip_path, int path_index, int segment_index)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetCropBox(FPDF_PAGE page, float left, float bottom, float right, float top)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetTrimBox(FPDF_PAGE page, float left, float bottom, float right, float top)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_SetArtBox(FPDF_PAGE page, float left, float bottom, float right, float top)
FPDF_EXPORT FPDF_CLIPPATH FPDF_CALLCONV FPDF_CreateClipPath(float left, float bottom, float right, float top)
FPDF_EXPORT int FPDF_CALLCONV FPDFClipPath_CountPathSegments(FPDF_CLIPPATH clip_path, int path_index)
FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath)
FPDF_EXPORT void FPDF_CALLCONV FPDFPage_InsertClipPath(FPDF_PAGE page, FPDF_CLIPPATH clipPath)
#define FPDF_CALLCONV
Definition fpdfview.h:227
#define FPDF_EXPORT
Definition fpdfview.h:221
const char kArtBox[]
const char kMediaBox[]
const char kBleedBox[]
const char kContents[]
const char kCropBox[]
const char kTrimBox[]