OLD | NEW |
| (Empty) |
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 "public/fpdf_transformpage.h" | |
8 | |
9 #include "core/include/fpdfapi/cpdf_array.h" | |
10 #include "core/include/fpdfapi/cpdf_document.h" | |
11 #include "core/include/fpdfapi/cpdf_number.h" | |
12 #include "core/include/fpdfapi/cpdf_reference.h" | |
13 #include "fpdfsdk/include/fsdk_define.h" | |
14 | |
15 namespace { | |
16 | |
17 void SetBoundingBox(CPDF_Page* page, | |
18 const CFX_ByteStringC& key, | |
19 float left, | |
20 float bottom, | |
21 float right, | |
22 float top) { | |
23 CPDF_Dictionary* pPageDict = page->m_pFormDict; | |
24 CPDF_Array* pBoundingBoxArray = new CPDF_Array; | |
25 pBoundingBoxArray->Add(new CPDF_Number(left)); | |
26 pBoundingBoxArray->Add(new CPDF_Number(bottom)); | |
27 pBoundingBoxArray->Add(new CPDF_Number(right)); | |
28 pBoundingBoxArray->Add(new CPDF_Number(top)); | |
29 pPageDict->SetAt(key, pBoundingBoxArray); | |
30 } | |
31 | |
32 FPDF_BOOL GetBoundingBox(CPDF_Page* page, | |
33 const CFX_ByteStringC& key, | |
34 float* left, | |
35 float* bottom, | |
36 float* right, | |
37 float* top) { | |
38 CPDF_Dictionary* pPageDict = page->m_pFormDict; | |
39 CPDF_Array* pArray = pPageDict->GetArrayBy(key); | |
40 if (!pArray) | |
41 return FALSE; | |
42 | |
43 *left = pArray->GetFloatAt(0); | |
44 *bottom = pArray->GetFloatAt(1); | |
45 *right = pArray->GetFloatAt(2); | |
46 *top = pArray->GetFloatAt(3); | |
47 return TRUE; | |
48 } | |
49 | |
50 } // namespace | |
51 | |
52 DLLEXPORT void STDCALL FPDFPage_SetMediaBox(FPDF_PAGE page, | |
53 float left, | |
54 float bottom, | |
55 float right, | |
56 float top) { | |
57 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
58 if (!pPage) | |
59 return; | |
60 | |
61 SetBoundingBox(pPage, "MediaBox", left, bottom, right, top); | |
62 } | |
63 | |
64 DLLEXPORT void STDCALL FPDFPage_SetCropBox(FPDF_PAGE page, | |
65 float left, | |
66 float bottom, | |
67 float right, | |
68 float top) { | |
69 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
70 if (!pPage) | |
71 return; | |
72 | |
73 SetBoundingBox(pPage, "CropBox", left, bottom, right, top); | |
74 } | |
75 | |
76 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetMediaBox(FPDF_PAGE page, | |
77 float* left, | |
78 float* bottom, | |
79 float* right, | |
80 float* top) { | |
81 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
82 return pPage && GetBoundingBox(pPage, "MediaBox", left, bottom, right, top); | |
83 } | |
84 | |
85 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_GetCropBox(FPDF_PAGE page, | |
86 float* left, | |
87 float* bottom, | |
88 float* right, | |
89 float* top) { | |
90 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
91 return pPage && GetBoundingBox(pPage, "CropBox", left, bottom, right, top); | |
92 } | |
93 | |
94 DLLEXPORT FPDF_BOOL STDCALL FPDFPage_TransFormWithClip(FPDF_PAGE page, | |
95 FS_MATRIX* matrix, | |
96 FS_RECTF* clipRect) { | |
97 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
98 if (!pPage) | |
99 return FALSE; | |
100 | |
101 CFX_ByteTextBuf textBuf; | |
102 textBuf << "q "; | |
103 CFX_FloatRect rect(clipRect->left, clipRect->bottom, clipRect->right, | |
104 clipRect->top); | |
105 rect.Normalize(); | |
106 CFX_ByteString bsClipping; | |
107 bsClipping.Format("%f %f %f %f re W* n ", rect.left, rect.bottom, | |
108 rect.Width(), rect.Height()); | |
109 textBuf << bsClipping; | |
110 | |
111 CFX_ByteString bsMatix; | |
112 bsMatix.Format("%f %f %f %f %f %f cm ", matrix->a, matrix->b, matrix->c, | |
113 matrix->d, matrix->e, matrix->f); | |
114 textBuf << bsMatix; | |
115 | |
116 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; | |
117 CPDF_Object* pContentObj = | |
118 pPageDic ? pPageDic->GetElement("Contents") : nullptr; | |
119 if (!pContentObj) | |
120 pContentObj = pPageDic ? pPageDic->GetArrayBy("Contents") : nullptr; | |
121 if (!pContentObj) | |
122 return FALSE; | |
123 | |
124 CPDF_Dictionary* pDic = new CPDF_Dictionary; | |
125 CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic); | |
126 pStream->SetData(textBuf.GetBuffer(), textBuf.GetSize(), FALSE, FALSE); | |
127 CPDF_Document* pDoc = pPage->m_pDocument; | |
128 if (!pDoc) | |
129 return FALSE; | |
130 pDoc->AddIndirectObject(pStream); | |
131 | |
132 pDic = new CPDF_Dictionary; | |
133 CPDF_Stream* pEndStream = new CPDF_Stream(nullptr, 0, pDic); | |
134 pEndStream->SetData((const uint8_t*)" Q", 2, FALSE, FALSE); | |
135 pDoc->AddIndirectObject(pEndStream); | |
136 | |
137 CPDF_Array* pContentArray = nullptr; | |
138 if (CPDF_Array* pArray = ToArray(pContentObj)) { | |
139 pContentArray = pArray; | |
140 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
141 pContentArray->InsertAt(0, pRef); | |
142 pContentArray->AddReference(pDoc, pEndStream); | |
143 } else if (CPDF_Reference* pReference = ToReference(pContentObj)) { | |
144 CPDF_Object* pDirectObj = pReference->GetDirect(); | |
145 if (pDirectObj) { | |
146 if (CPDF_Array* pArray = pDirectObj->AsArray()) { | |
147 pContentArray = pArray; | |
148 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
149 pContentArray->InsertAt(0, pRef); | |
150 pContentArray->AddReference(pDoc, pEndStream); | |
151 } else if (pDirectObj->IsStream()) { | |
152 pContentArray = new CPDF_Array(); | |
153 pContentArray->AddReference(pDoc, pStream->GetObjNum()); | |
154 pContentArray->AddReference(pDoc, pDirectObj->GetObjNum()); | |
155 pContentArray->AddReference(pDoc, pEndStream); | |
156 pPageDic->SetAtReference("Contents", pDoc, | |
157 pDoc->AddIndirectObject(pContentArray)); | |
158 } | |
159 } | |
160 } | |
161 | |
162 // Need to transform the patterns as well. | |
163 CPDF_Dictionary* pRes = pPageDic->GetDictBy("Resources"); | |
164 if (pRes) { | |
165 CPDF_Dictionary* pPattenDict = pRes->GetDictBy("Pattern"); | |
166 if (pPattenDict) { | |
167 for (const auto& it : *pPattenDict) { | |
168 CPDF_Object* pObj = it.second; | |
169 if (pObj->IsReference()) | |
170 pObj = pObj->GetDirect(); | |
171 | |
172 CPDF_Dictionary* pDict = nullptr; | |
173 if (pObj->IsDictionary()) | |
174 pDict = pObj->AsDictionary(); | |
175 else if (CPDF_Stream* pStream = pObj->AsStream()) | |
176 pDict = pStream->GetDict(); | |
177 else | |
178 continue; | |
179 | |
180 CFX_Matrix m = pDict->GetMatrixBy("Matrix"); | |
181 CFX_Matrix t = *(CFX_Matrix*)matrix; | |
182 m.Concat(t); | |
183 pDict->SetAtMatrix("Matrix", m); | |
184 } | |
185 } | |
186 } | |
187 | |
188 return TRUE; | |
189 } | |
190 | |
191 DLLEXPORT void STDCALL | |
192 FPDFPageObj_TransformClipPath(FPDF_PAGEOBJECT page_object, | |
193 double a, | |
194 double b, | |
195 double c, | |
196 double d, | |
197 double e, | |
198 double f) { | |
199 CPDF_PageObject* pPageObj = (CPDF_PageObject*)page_object; | |
200 if (!pPageObj) | |
201 return; | |
202 CFX_Matrix matrix((FX_FLOAT)a, (FX_FLOAT)b, (FX_FLOAT)c, (FX_FLOAT)d, | |
203 (FX_FLOAT)e, (FX_FLOAT)f); | |
204 | |
205 // Special treatment to shading object, because the ClipPath for shading | |
206 // object is already transformed. | |
207 if (!pPageObj->IsShading()) | |
208 pPageObj->TransformClipPath(matrix); | |
209 pPageObj->TransformGeneralState(matrix); | |
210 } | |
211 | |
212 DLLEXPORT FPDF_CLIPPATH STDCALL FPDF_CreateClipPath(float left, | |
213 float bottom, | |
214 float right, | |
215 float top) { | |
216 CPDF_ClipPath* pNewClipPath = new CPDF_ClipPath(); | |
217 pNewClipPath->GetModify(); | |
218 CPDF_Path Path; | |
219 Path.GetModify(); | |
220 Path.AppendRect(left, bottom, right, top); | |
221 pNewClipPath->AppendPath(Path, FXFILL_ALTERNATE, FALSE); | |
222 return pNewClipPath; | |
223 } | |
224 | |
225 DLLEXPORT void STDCALL FPDF_DestroyClipPath(FPDF_CLIPPATH clipPath) { | |
226 delete (CPDF_ClipPath*)clipPath; | |
227 } | |
228 | |
229 void OutputPath(CFX_ByteTextBuf& buf, CPDF_Path path) { | |
230 const CFX_PathData* pPathData = path; | |
231 if (!pPathData) | |
232 return; | |
233 | |
234 FX_PATHPOINT* pPoints = pPathData->GetPoints(); | |
235 | |
236 if (path.IsRect()) { | |
237 buf << (pPoints[0].m_PointX) << " " << (pPoints[0].m_PointY) << " " | |
238 << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " " | |
239 << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re\n"; | |
240 return; | |
241 } | |
242 | |
243 CFX_ByteString temp; | |
244 for (int i = 0; i < pPathData->GetPointCount(); i++) { | |
245 buf << (pPoints[i].m_PointX) << " " << (pPoints[i].m_PointY); | |
246 int point_type = pPoints[i].m_Flag & FXPT_TYPE; | |
247 if (point_type == FXPT_MOVETO) { | |
248 buf << " m\n"; | |
249 } else if (point_type == FXPT_BEZIERTO) { | |
250 buf << " " << (pPoints[i + 1].m_PointX) << " " | |
251 << (pPoints[i + 1].m_PointY) << " " << (pPoints[i + 2].m_PointX) | |
252 << " " << (pPoints[i + 2].m_PointY); | |
253 if (pPoints[i + 2].m_Flag & FXPT_CLOSEFIGURE) | |
254 buf << " c h\n"; | |
255 else | |
256 buf << " c\n"; | |
257 i += 2; | |
258 } else if (point_type == FXPT_LINETO) { | |
259 if (pPoints[i].m_Flag & FXPT_CLOSEFIGURE) | |
260 buf << " l h\n"; | |
261 else | |
262 buf << " l\n"; | |
263 } | |
264 } | |
265 } | |
266 | |
267 DLLEXPORT void STDCALL FPDFPage_InsertClipPath(FPDF_PAGE page, | |
268 FPDF_CLIPPATH clipPath) { | |
269 CPDF_Page* pPage = CPDFPageFromFPDFPage(page); | |
270 if (!pPage) | |
271 return; | |
272 | |
273 CPDF_Dictionary* pPageDic = pPage->m_pFormDict; | |
274 CPDF_Object* pContentObj = | |
275 pPageDic ? pPageDic->GetElement("Contents") : nullptr; | |
276 if (!pContentObj) | |
277 pContentObj = pPageDic ? pPageDic->GetArrayBy("Contents") : nullptr; | |
278 if (!pContentObj) | |
279 return; | |
280 | |
281 CFX_ByteTextBuf strClip; | |
282 CPDF_ClipPath* pClipPath = (CPDF_ClipPath*)clipPath; | |
283 FX_DWORD i; | |
284 for (i = 0; i < pClipPath->GetPathCount(); i++) { | |
285 CPDF_Path path = pClipPath->GetPath(i); | |
286 int iClipType = pClipPath->GetClipType(i); | |
287 if (path.GetPointCount() == 0) { | |
288 // Empty clipping (totally clipped out) | |
289 strClip << "0 0 m W n "; | |
290 } else { | |
291 OutputPath(strClip, path); | |
292 if (iClipType == FXFILL_WINDING) | |
293 strClip << "W n\n"; | |
294 else | |
295 strClip << "W* n\n"; | |
296 } | |
297 } | |
298 CPDF_Dictionary* pDic = new CPDF_Dictionary; | |
299 CPDF_Stream* pStream = new CPDF_Stream(nullptr, 0, pDic); | |
300 pStream->SetData(strClip.GetBuffer(), strClip.GetSize(), FALSE, FALSE); | |
301 CPDF_Document* pDoc = pPage->m_pDocument; | |
302 if (!pDoc) | |
303 return; | |
304 pDoc->AddIndirectObject(pStream); | |
305 | |
306 CPDF_Array* pContentArray = nullptr; | |
307 if (CPDF_Array* pArray = ToArray(pContentObj)) { | |
308 pContentArray = pArray; | |
309 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
310 pContentArray->InsertAt(0, pRef); | |
311 } else if (CPDF_Reference* pReference = ToReference(pContentObj)) { | |
312 CPDF_Object* pDirectObj = pReference->GetDirect(); | |
313 if (pDirectObj) { | |
314 if (CPDF_Array* pArray = pDirectObj->AsArray()) { | |
315 pContentArray = pArray; | |
316 CPDF_Reference* pRef = new CPDF_Reference(pDoc, pStream->GetObjNum()); | |
317 pContentArray->InsertAt(0, pRef); | |
318 } else if (pDirectObj->IsStream()) { | |
319 pContentArray = new CPDF_Array(); | |
320 pContentArray->AddReference(pDoc, pStream->GetObjNum()); | |
321 pContentArray->AddReference(pDoc, pDirectObj->GetObjNum()); | |
322 pPageDic->SetAtReference("Contents", pDoc, | |
323 pDoc->AddIndirectObject(pContentArray)); | |
324 } | |
325 } | |
326 } | |
327 } | |
OLD | NEW |