Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: fpdfsdk/src/fpdf_flatten.cpp

Issue 1799773002: Move fpdfsdk/src up to fpdfsdk/. (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@master
Patch Set: Rebase to master Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « fpdfsdk/src/fpdf_ext.cpp ('k') | fpdfsdk/src/fpdf_progressive.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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_flatten.h"
8
9 #include <algorithm>
10
11 #include "core/include/fpdfapi/cpdf_array.h"
12 #include "core/include/fpdfapi/cpdf_document.h"
13 #include "core/include/fpdfapi/cpdf_number.h"
14 #include "fpdfsdk/include/fsdk_define.h"
15
16 typedef CFX_ArrayTemplate<CPDF_Dictionary*> CPDF_ObjectArray;
17 typedef CFX_ArrayTemplate<CFX_FloatRect> CPDF_RectArray;
18
19 enum FPDF_TYPE { MAX, MIN };
20 enum FPDF_VALUE { TOP, LEFT, RIGHT, BOTTOM };
21
22 FX_BOOL IsValiableRect(CFX_FloatRect rect, CFX_FloatRect rcPage) {
23 if (rect.left - rect.right > 0.000001f || rect.bottom - rect.top > 0.000001f)
24 return FALSE;
25
26 if (rect.left == 0.0f && rect.top == 0.0f && rect.right == 0.0f &&
27 rect.bottom == 0.0f)
28 return FALSE;
29
30 if (!rcPage.IsEmpty()) {
31 if (rect.left - rcPage.left < -10.000001f ||
32 rect.right - rcPage.right > 10.000001f ||
33 rect.top - rcPage.top > 10.000001f ||
34 rect.bottom - rcPage.bottom < -10.000001f)
35 return FALSE;
36 }
37
38 return TRUE;
39 }
40
41 void GetContentsRect(CPDF_Document* pDoc,
42 CPDF_Dictionary* pDict,
43 CPDF_RectArray* pRectArray) {
44 std::unique_ptr<CPDF_Page> pPDFPage(new CPDF_Page);
45 pPDFPage->Load(pDoc, pDict, FALSE);
46 pPDFPage->ParseContent(nullptr);
47
48 for (auto& pPageObject : *pPDFPage->GetPageObjectList()) {
49 if (!pPageObject)
50 continue;
51
52 CFX_FloatRect rc;
53 rc.left = pPageObject->m_Left;
54 rc.right = pPageObject->m_Right;
55 rc.bottom = pPageObject->m_Bottom;
56 rc.top = pPageObject->m_Top;
57 if (IsValiableRect(rc, pDict->GetRectBy("MediaBox")))
58 pRectArray->Add(rc);
59 }
60 }
61
62 void ParserStream(CPDF_Dictionary* pPageDic,
63 CPDF_Dictionary* pStream,
64 CPDF_RectArray* pRectArray,
65 CPDF_ObjectArray* pObjectArray) {
66 if (!pStream)
67 return;
68 CFX_FloatRect rect;
69 if (pStream->KeyExist("Rect"))
70 rect = pStream->GetRectBy("Rect");
71 else if (pStream->KeyExist("BBox"))
72 rect = pStream->GetRectBy("BBox");
73
74 if (IsValiableRect(rect, pPageDic->GetRectBy("MediaBox")))
75 pRectArray->Add(rect);
76
77 pObjectArray->Add(pStream);
78 }
79
80 int ParserAnnots(CPDF_Document* pSourceDoc,
81 CPDF_Dictionary* pPageDic,
82 CPDF_RectArray* pRectArray,
83 CPDF_ObjectArray* pObjectArray,
84 int nUsage) {
85 if (!pSourceDoc || !pPageDic)
86 return FLATTEN_FAIL;
87
88 GetContentsRect(pSourceDoc, pPageDic, pRectArray);
89 CPDF_Array* pAnnots = pPageDic->GetArrayBy("Annots");
90 if (!pAnnots)
91 return FLATTEN_NOTHINGTODO;
92
93 FX_DWORD dwSize = pAnnots->GetCount();
94 for (int i = 0; i < (int)dwSize; i++) {
95 CPDF_Dictionary* pAnnotDic = ToDictionary(pAnnots->GetElementValue(i));
96 if (!pAnnotDic)
97 continue;
98
99 CFX_ByteString sSubtype = pAnnotDic->GetStringBy("Subtype");
100 if (sSubtype == "Popup")
101 continue;
102
103 int nAnnotFlag = pAnnotDic->GetIntegerBy("F");
104 if (nAnnotFlag & ANNOTFLAG_HIDDEN)
105 continue;
106
107 if (nUsage == FLAT_NORMALDISPLAY) {
108 if (nAnnotFlag & ANNOTFLAG_INVISIBLE)
109 continue;
110
111 ParserStream(pPageDic, pAnnotDic, pRectArray, pObjectArray);
112 } else {
113 if (nAnnotFlag & ANNOTFLAG_PRINT)
114 ParserStream(pPageDic, pAnnotDic, pRectArray, pObjectArray);
115 }
116 }
117 return FLATTEN_SUCCESS;
118 }
119
120 FX_FLOAT GetMinMaxValue(CPDF_RectArray& array,
121 FPDF_TYPE type,
122 FPDF_VALUE value) {
123 int nRects = array.GetSize();
124 FX_FLOAT fRet = 0.0f;
125
126 if (nRects <= 0)
127 return 0.0f;
128
129 FX_FLOAT* pArray = new FX_FLOAT[nRects];
130 switch (value) {
131 case LEFT: {
132 for (int i = 0; i < nRects; i++)
133 pArray[i] = CFX_FloatRect(array.GetAt(i)).left;
134
135 break;
136 }
137 case TOP: {
138 for (int i = 0; i < nRects; i++)
139 pArray[i] = CFX_FloatRect(array.GetAt(i)).top;
140
141 break;
142 }
143 case RIGHT: {
144 for (int i = 0; i < nRects; i++)
145 pArray[i] = CFX_FloatRect(array.GetAt(i)).right;
146
147 break;
148 }
149 case BOTTOM: {
150 for (int i = 0; i < nRects; i++)
151 pArray[i] = CFX_FloatRect(array.GetAt(i)).bottom;
152
153 break;
154 }
155 default:
156 break;
157 }
158 fRet = pArray[0];
159 if (type == MAX) {
160 for (int i = 1; i < nRects; i++)
161 if (fRet <= pArray[i])
162 fRet = pArray[i];
163 } else {
164 for (int i = 1; i < nRects; i++)
165 if (fRet >= pArray[i])
166 fRet = pArray[i];
167 }
168 delete[] pArray;
169 return fRet;
170 }
171
172 CFX_FloatRect CalculateRect(CPDF_RectArray* pRectArray) {
173 CFX_FloatRect rcRet;
174
175 rcRet.left = GetMinMaxValue(*pRectArray, MIN, LEFT);
176 rcRet.top = GetMinMaxValue(*pRectArray, MAX, TOP);
177 rcRet.right = GetMinMaxValue(*pRectArray, MAX, RIGHT);
178 rcRet.bottom = GetMinMaxValue(*pRectArray, MIN, BOTTOM);
179
180 return rcRet;
181 }
182
183 void SetPageContents(CFX_ByteString key,
184 CPDF_Dictionary* pPage,
185 CPDF_Document* pDocument) {
186 CPDF_Object* pContentsObj = pPage->GetStreamBy("Contents");
187 if (!pContentsObj) {
188 pContentsObj = pPage->GetArrayBy("Contents");
189 }
190
191 if (!pContentsObj) {
192 // Create a new contents dictionary
193 if (!key.IsEmpty()) {
194 CPDF_Stream* pNewContents = new CPDF_Stream(NULL, 0, new CPDF_Dictionary);
195 pPage->SetAtReference("Contents", pDocument,
196 pDocument->AddIndirectObject(pNewContents));
197
198 CFX_ByteString sStream;
199 sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str());
200 pNewContents->SetData((const uint8_t*)sStream, sStream.GetLength(), FALSE,
201 FALSE);
202 }
203 return;
204 }
205
206 CPDF_Array* pContentsArray = NULL;
207
208 switch (pContentsObj->GetType()) {
209 case CPDF_Object::STREAM: {
210 pContentsArray = new CPDF_Array;
211 CPDF_Stream* pContents = pContentsObj->AsStream();
212 FX_DWORD dwObjNum = pDocument->AddIndirectObject(pContents);
213 CPDF_StreamAcc acc;
214 acc.LoadAllData(pContents);
215 CFX_ByteString sStream = "q\n";
216 CFX_ByteString sBody =
217 CFX_ByteString((const FX_CHAR*)acc.GetData(), acc.GetSize());
218 sStream = sStream + sBody + "\nQ";
219 pContents->SetData((const uint8_t*)sStream, sStream.GetLength(), FALSE,
220 FALSE);
221 pContentsArray->AddReference(pDocument, dwObjNum);
222 break;
223 }
224
225 case CPDF_Object::ARRAY: {
226 pContentsArray = pContentsObj->AsArray();
227 break;
228 }
229 default:
230 break;
231 }
232
233 if (!pContentsArray)
234 return;
235
236 FX_DWORD dwObjNum = pDocument->AddIndirectObject(pContentsArray);
237 pPage->SetAtReference("Contents", pDocument, dwObjNum);
238
239 if (!key.IsEmpty()) {
240 CPDF_Stream* pNewContents = new CPDF_Stream(NULL, 0, new CPDF_Dictionary);
241 dwObjNum = pDocument->AddIndirectObject(pNewContents);
242 pContentsArray->AddReference(pDocument, dwObjNum);
243
244 CFX_ByteString sStream;
245 sStream.Format("q 1 0 0 1 0 0 cm /%s Do Q", key.c_str());
246 pNewContents->SetData((const uint8_t*)sStream, sStream.GetLength(), FALSE,
247 FALSE);
248 }
249 }
250
251 CFX_Matrix GetMatrix(CFX_FloatRect rcAnnot,
252 CFX_FloatRect rcStream,
253 const CFX_Matrix& matrix) {
254 if (rcStream.IsEmpty())
255 return CFX_Matrix();
256
257 matrix.TransformRect(rcStream);
258 rcStream.Normalize();
259
260 FX_FLOAT a = rcAnnot.Width() / rcStream.Width();
261 FX_FLOAT d = rcAnnot.Height() / rcStream.Height();
262
263 FX_FLOAT e = rcAnnot.left - rcStream.left * a;
264 FX_FLOAT f = rcAnnot.bottom - rcStream.bottom * d;
265 return CFX_Matrix(a, 0, 0, d, e, f);
266 }
267
268 void GetOffset(FX_FLOAT& fa,
269 FX_FLOAT& fd,
270 FX_FLOAT& fe,
271 FX_FLOAT& ff,
272 CFX_FloatRect rcAnnot,
273 CFX_FloatRect rcStream,
274 const CFX_Matrix& matrix) {
275 FX_FLOAT fStreamWidth = 0.0f;
276 FX_FLOAT fStreamHeight = 0.0f;
277
278 if (matrix.a != 0 && matrix.d != 0) {
279 fStreamWidth = rcStream.right - rcStream.left;
280 fStreamHeight = rcStream.top - rcStream.bottom;
281 } else {
282 fStreamWidth = rcStream.top - rcStream.bottom;
283 fStreamHeight = rcStream.right - rcStream.left;
284 }
285
286 FX_FLOAT x1 =
287 matrix.a * rcStream.left + matrix.c * rcStream.bottom + matrix.e;
288 FX_FLOAT y1 =
289 matrix.b * rcStream.left + matrix.d * rcStream.bottom + matrix.f;
290 FX_FLOAT x2 = matrix.a * rcStream.left + matrix.c * rcStream.top + matrix.e;
291 FX_FLOAT y2 = matrix.b * rcStream.left + matrix.d * rcStream.top + matrix.f;
292 FX_FLOAT x3 =
293 matrix.a * rcStream.right + matrix.c * rcStream.bottom + matrix.e;
294 FX_FLOAT y3 =
295 matrix.b * rcStream.right + matrix.d * rcStream.bottom + matrix.f;
296 FX_FLOAT x4 = matrix.a * rcStream.right + matrix.c * rcStream.top + matrix.e;
297 FX_FLOAT y4 = matrix.b * rcStream.right + matrix.d * rcStream.top + matrix.f;
298
299 FX_FLOAT left = std::min(std::min(x1, x2), std::min(x3, x4));
300 FX_FLOAT bottom = std::min(std::min(y1, y2), std::min(y3, y4));
301
302 fa = (rcAnnot.right - rcAnnot.left) / fStreamWidth;
303 fd = (rcAnnot.top - rcAnnot.bottom) / fStreamHeight;
304 fe = rcAnnot.left - left * fa;
305 ff = rcAnnot.bottom - bottom * fd;
306 }
307
308 DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) {
309 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
310 if (!page) {
311 return FLATTEN_FAIL;
312 }
313
314 CPDF_Document* pDocument = pPage->m_pDocument;
315 CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
316
317 if (!pDocument || !pPageDict) {
318 return FLATTEN_FAIL;
319 }
320
321 CPDF_ObjectArray ObjectArray;
322 CPDF_RectArray RectArray;
323
324 int iRet = FLATTEN_FAIL;
325 iRet = ParserAnnots(pDocument, pPageDict, &RectArray, &ObjectArray, nFlag);
326 if (iRet == FLATTEN_NOTHINGTODO || iRet == FLATTEN_FAIL)
327 return iRet;
328
329 CFX_FloatRect rcOriginalCB;
330 CFX_FloatRect rcMerger = CalculateRect(&RectArray);
331 CFX_FloatRect rcOriginalMB = pPageDict->GetRectBy("MediaBox");
332
333 if (pPageDict->KeyExist("CropBox"))
334 rcOriginalMB = pPageDict->GetRectBy("CropBox");
335
336 if (rcOriginalMB.IsEmpty()) {
337 rcOriginalMB = CFX_FloatRect(0.0f, 0.0f, 612.0f, 792.0f);
338 }
339
340 rcMerger.left =
341 rcMerger.left < rcOriginalMB.left ? rcOriginalMB.left : rcMerger.left;
342 rcMerger.right =
343 rcMerger.right > rcOriginalMB.right ? rcOriginalMB.right : rcMerger.right;
344 rcMerger.top =
345 rcMerger.top > rcOriginalMB.top ? rcOriginalMB.top : rcMerger.top;
346 rcMerger.bottom = rcMerger.bottom < rcOriginalMB.bottom ? rcOriginalMB.bottom
347 : rcMerger.bottom;
348
349 if (pPageDict->KeyExist("ArtBox"))
350 rcOriginalCB = pPageDict->GetRectBy("ArtBox");
351 else
352 rcOriginalCB = rcOriginalMB;
353
354 if (!rcOriginalMB.IsEmpty()) {
355 CPDF_Array* pMediaBox = new CPDF_Array();
356 pMediaBox->Add(new CPDF_Number(rcOriginalMB.left));
357 pMediaBox->Add(new CPDF_Number(rcOriginalMB.bottom));
358 pMediaBox->Add(new CPDF_Number(rcOriginalMB.right));
359 pMediaBox->Add(new CPDF_Number(rcOriginalMB.top));
360 pPageDict->SetAt("MediaBox", pMediaBox);
361 }
362
363 if (!rcOriginalCB.IsEmpty()) {
364 CPDF_Array* pCropBox = new CPDF_Array();
365 pCropBox->Add(new CPDF_Number(rcOriginalCB.left));
366 pCropBox->Add(new CPDF_Number(rcOriginalCB.bottom));
367 pCropBox->Add(new CPDF_Number(rcOriginalCB.right));
368 pCropBox->Add(new CPDF_Number(rcOriginalCB.top));
369 pPageDict->SetAt("ArtBox", pCropBox);
370 }
371
372 CPDF_Dictionary* pRes = pPageDict->GetDictBy("Resources");
373 if (!pRes) {
374 pRes = new CPDF_Dictionary;
375 pPageDict->SetAt("Resources", pRes);
376 }
377
378 CPDF_Stream* pNewXObject = new CPDF_Stream(NULL, 0, new CPDF_Dictionary);
379 FX_DWORD dwObjNum = pDocument->AddIndirectObject(pNewXObject);
380 CPDF_Dictionary* pPageXObject = pRes->GetDictBy("XObject");
381 if (!pPageXObject) {
382 pPageXObject = new CPDF_Dictionary;
383 pRes->SetAt("XObject", pPageXObject);
384 }
385
386 CFX_ByteString key = "";
387 int nStreams = ObjectArray.GetSize();
388
389 if (nStreams > 0) {
390 for (int iKey = 0; /*iKey < 100*/; iKey++) {
391 char sExtend[5] = {};
392 FXSYS_itoa(iKey, sExtend, 10);
393 key = CFX_ByteString("FFT") + CFX_ByteString(sExtend);
394
395 if (!pPageXObject->KeyExist(key))
396 break;
397 }
398 }
399
400 SetPageContents(key, pPageDict, pDocument);
401
402 CPDF_Dictionary* pNewXORes = NULL;
403
404 if (!key.IsEmpty()) {
405 pPageXObject->SetAtReference(key, pDocument, dwObjNum);
406 CPDF_Dictionary* pNewOXbjectDic = pNewXObject->GetDict();
407 pNewXORes = new CPDF_Dictionary;
408 pNewOXbjectDic->SetAt("Resources", pNewXORes);
409 pNewOXbjectDic->SetAtName("Type", "XObject");
410 pNewOXbjectDic->SetAtName("Subtype", "Form");
411 pNewOXbjectDic->SetAtInteger("FormType", 1);
412 pNewOXbjectDic->SetAtName("Name", "FRM");
413 CFX_FloatRect rcBBox = pPageDict->GetRectBy("ArtBox");
414 pNewOXbjectDic->SetAtRect("BBox", rcBBox);
415 }
416
417 for (int i = 0; i < nStreams; i++) {
418 CPDF_Dictionary* pAnnotDic = ObjectArray.GetAt(i);
419 if (!pAnnotDic)
420 continue;
421
422 CFX_FloatRect rcAnnot = pAnnotDic->GetRectBy("Rect");
423 rcAnnot.Normalize();
424
425 CFX_ByteString sAnnotState = pAnnotDic->GetStringBy("AS");
426 CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictBy("AP");
427 if (!pAnnotAP)
428 continue;
429
430 CPDF_Stream* pAPStream = pAnnotAP->GetStreamBy("N");
431 if (!pAPStream) {
432 CPDF_Dictionary* pAPDic = pAnnotAP->GetDictBy("N");
433 if (!pAPDic)
434 continue;
435
436 if (!sAnnotState.IsEmpty()) {
437 pAPStream = pAPDic->GetStreamBy(sAnnotState);
438 } else {
439 auto it = pAPDic->begin();
440 if (it != pAPDic->end()) {
441 CPDF_Object* pFirstObj = it->second;
442 if (pFirstObj) {
443 if (pFirstObj->IsReference())
444 pFirstObj = pFirstObj->GetDirect();
445 if (!pFirstObj->IsStream())
446 continue;
447 pAPStream = pFirstObj->AsStream();
448 }
449 }
450 }
451 }
452 if (!pAPStream)
453 continue;
454
455 CPDF_Dictionary* pAPDic = pAPStream->GetDict();
456 CFX_Matrix matrix = pAPDic->GetMatrixBy("Matrix");
457
458 CFX_FloatRect rcStream;
459 if (pAPDic->KeyExist("Rect"))
460 rcStream = pAPDic->GetRectBy("Rect");
461 else if (pAPDic->KeyExist("BBox"))
462 rcStream = pAPDic->GetRectBy("BBox");
463
464 if (rcStream.IsEmpty())
465 continue;
466
467 CPDF_Object* pObj = pAPStream;
468
469 if (pObj) {
470 CPDF_Dictionary* pObjDic = pObj->GetDict();
471 if (pObjDic) {
472 pObjDic->SetAtName("Type", "XObject");
473 pObjDic->SetAtName("Subtype", "Form");
474 }
475 }
476
477 CPDF_Dictionary* pXObject = pNewXORes->GetDictBy("XObject");
478 if (!pXObject) {
479 pXObject = new CPDF_Dictionary;
480 pNewXORes->SetAt("XObject", pXObject);
481 }
482
483 CFX_ByteString sFormName;
484 sFormName.Format("F%d", i);
485 FX_DWORD dwObjNum = pDocument->AddIndirectObject(pObj);
486 pXObject->SetAtReference(sFormName, pDocument, dwObjNum);
487
488 CPDF_StreamAcc acc;
489 acc.LoadAllData(pNewXObject);
490
491 const uint8_t* pData = acc.GetData();
492 CFX_ByteString sStream(pData, acc.GetSize());
493 CFX_ByteString sTemp;
494
495 if (matrix.IsIdentity()) {
496 matrix.a = 1.0f;
497 matrix.b = 0.0f;
498 matrix.c = 0.0f;
499 matrix.d = 1.0f;
500 matrix.e = 0.0f;
501 matrix.f = 0.0f;
502 }
503
504 CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix);
505 sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f,
506 sFormName.c_str());
507 sStream += sTemp;
508
509 pNewXObject->SetData((const uint8_t*)sStream, sStream.GetLength(), FALSE,
510 FALSE);
511 }
512 pPageDict->RemoveAt("Annots");
513
514 ObjectArray.RemoveAll();
515 RectArray.RemoveAll();
516
517 return FLATTEN_SUCCESS;
518 }
OLDNEW
« no previous file with comments | « fpdfsdk/src/fpdf_ext.cpp ('k') | fpdfsdk/src/fpdf_progressive.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698