1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2018 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/write.h"
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include <limits.h>
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <sstream>
10*3ac0a46fSAndroid Build Coastguard Worker #include <string>
11*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
12*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
13*3ac0a46fSAndroid Build Coastguard Worker
14*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_annot.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_attachment.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_edit.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_thumbnail.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "testing/fx_string_testhelpers.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "testing/image_diff/image_diff_png.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/notreached.h"
22*3ac0a46fSAndroid Build Coastguard Worker
23*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
24*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkPicture.h" // nogncheck
25*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkStream.h" // nogncheck
26*3ac0a46fSAndroid Build Coastguard Worker #endif
27*3ac0a46fSAndroid Build Coastguard Worker
28*3ac0a46fSAndroid Build Coastguard Worker namespace {
29*3ac0a46fSAndroid Build Coastguard Worker
CheckDimensions(int stride,int width,int height)30*3ac0a46fSAndroid Build Coastguard Worker bool CheckDimensions(int stride, int width, int height) {
31*3ac0a46fSAndroid Build Coastguard Worker if (stride < 0 || width < 0 || height < 0) {
32*3ac0a46fSAndroid Build Coastguard Worker return false;
33*3ac0a46fSAndroid Build Coastguard Worker }
34*3ac0a46fSAndroid Build Coastguard Worker if (height > 0 && stride > INT_MAX / height) {
35*3ac0a46fSAndroid Build Coastguard Worker return false;
36*3ac0a46fSAndroid Build Coastguard Worker }
37*3ac0a46fSAndroid Build Coastguard Worker return true;
38*3ac0a46fSAndroid Build Coastguard Worker }
39*3ac0a46fSAndroid Build Coastguard Worker
AnnotSubtypeToCString(FPDF_ANNOTATION_SUBTYPE subtype)40*3ac0a46fSAndroid Build Coastguard Worker const char* AnnotSubtypeToCString(FPDF_ANNOTATION_SUBTYPE subtype) {
41*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_TEXT) {
42*3ac0a46fSAndroid Build Coastguard Worker return "Text";
43*3ac0a46fSAndroid Build Coastguard Worker }
44*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_LINK) {
45*3ac0a46fSAndroid Build Coastguard Worker return "Link";
46*3ac0a46fSAndroid Build Coastguard Worker }
47*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_FREETEXT) {
48*3ac0a46fSAndroid Build Coastguard Worker return "FreeText";
49*3ac0a46fSAndroid Build Coastguard Worker }
50*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_LINE) {
51*3ac0a46fSAndroid Build Coastguard Worker return "Line";
52*3ac0a46fSAndroid Build Coastguard Worker }
53*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_SQUARE) {
54*3ac0a46fSAndroid Build Coastguard Worker return "Square";
55*3ac0a46fSAndroid Build Coastguard Worker }
56*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_CIRCLE) {
57*3ac0a46fSAndroid Build Coastguard Worker return "Circle";
58*3ac0a46fSAndroid Build Coastguard Worker }
59*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_POLYGON) {
60*3ac0a46fSAndroid Build Coastguard Worker return "Polygon";
61*3ac0a46fSAndroid Build Coastguard Worker }
62*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_POLYLINE) {
63*3ac0a46fSAndroid Build Coastguard Worker return "PolyLine";
64*3ac0a46fSAndroid Build Coastguard Worker }
65*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_HIGHLIGHT) {
66*3ac0a46fSAndroid Build Coastguard Worker return "Highlight";
67*3ac0a46fSAndroid Build Coastguard Worker }
68*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_UNDERLINE) {
69*3ac0a46fSAndroid Build Coastguard Worker return "Underline";
70*3ac0a46fSAndroid Build Coastguard Worker }
71*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_SQUIGGLY) {
72*3ac0a46fSAndroid Build Coastguard Worker return "Squiggly";
73*3ac0a46fSAndroid Build Coastguard Worker }
74*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_STRIKEOUT) {
75*3ac0a46fSAndroid Build Coastguard Worker return "StrikeOut";
76*3ac0a46fSAndroid Build Coastguard Worker }
77*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_STAMP) {
78*3ac0a46fSAndroid Build Coastguard Worker return "Stamp";
79*3ac0a46fSAndroid Build Coastguard Worker }
80*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_CARET) {
81*3ac0a46fSAndroid Build Coastguard Worker return "Caret";
82*3ac0a46fSAndroid Build Coastguard Worker }
83*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_INK) {
84*3ac0a46fSAndroid Build Coastguard Worker return "Ink";
85*3ac0a46fSAndroid Build Coastguard Worker }
86*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_POPUP) {
87*3ac0a46fSAndroid Build Coastguard Worker return "Popup";
88*3ac0a46fSAndroid Build Coastguard Worker }
89*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_FILEATTACHMENT) {
90*3ac0a46fSAndroid Build Coastguard Worker return "FileAttachment";
91*3ac0a46fSAndroid Build Coastguard Worker }
92*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_SOUND) {
93*3ac0a46fSAndroid Build Coastguard Worker return "Sound";
94*3ac0a46fSAndroid Build Coastguard Worker }
95*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_MOVIE) {
96*3ac0a46fSAndroid Build Coastguard Worker return "Movie";
97*3ac0a46fSAndroid Build Coastguard Worker }
98*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_WIDGET) {
99*3ac0a46fSAndroid Build Coastguard Worker return "Widget";
100*3ac0a46fSAndroid Build Coastguard Worker }
101*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_SCREEN) {
102*3ac0a46fSAndroid Build Coastguard Worker return "Screen";
103*3ac0a46fSAndroid Build Coastguard Worker }
104*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_PRINTERMARK) {
105*3ac0a46fSAndroid Build Coastguard Worker return "PrinterMark";
106*3ac0a46fSAndroid Build Coastguard Worker }
107*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_TRAPNET) {
108*3ac0a46fSAndroid Build Coastguard Worker return "TrapNet";
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_WATERMARK) {
111*3ac0a46fSAndroid Build Coastguard Worker return "Watermark";
112*3ac0a46fSAndroid Build Coastguard Worker }
113*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_THREED) {
114*3ac0a46fSAndroid Build Coastguard Worker return "3D";
115*3ac0a46fSAndroid Build Coastguard Worker }
116*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_RICHMEDIA) {
117*3ac0a46fSAndroid Build Coastguard Worker return "RichMedia";
118*3ac0a46fSAndroid Build Coastguard Worker }
119*3ac0a46fSAndroid Build Coastguard Worker if (subtype == FPDF_ANNOT_XFAWIDGET) {
120*3ac0a46fSAndroid Build Coastguard Worker return "XFAWidget";
121*3ac0a46fSAndroid Build Coastguard Worker }
122*3ac0a46fSAndroid Build Coastguard Worker NOTREACHED_NORETURN();
123*3ac0a46fSAndroid Build Coastguard Worker }
124*3ac0a46fSAndroid Build Coastguard Worker
AppendFlagString(const char * flag,std::string * output)125*3ac0a46fSAndroid Build Coastguard Worker void AppendFlagString(const char* flag, std::string* output) {
126*3ac0a46fSAndroid Build Coastguard Worker if (!output->empty()) {
127*3ac0a46fSAndroid Build Coastguard Worker *output += ", ";
128*3ac0a46fSAndroid Build Coastguard Worker }
129*3ac0a46fSAndroid Build Coastguard Worker *output += flag;
130*3ac0a46fSAndroid Build Coastguard Worker }
131*3ac0a46fSAndroid Build Coastguard Worker
AnnotFlagsToString(int flags)132*3ac0a46fSAndroid Build Coastguard Worker std::string AnnotFlagsToString(int flags) {
133*3ac0a46fSAndroid Build Coastguard Worker std::string str;
134*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_INVISIBLE) {
135*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("Invisible", &str);
136*3ac0a46fSAndroid Build Coastguard Worker }
137*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_HIDDEN) {
138*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("Hidden", &str);
139*3ac0a46fSAndroid Build Coastguard Worker }
140*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_PRINT) {
141*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("Print", &str);
142*3ac0a46fSAndroid Build Coastguard Worker }
143*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_NOZOOM) {
144*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("NoZoom", &str);
145*3ac0a46fSAndroid Build Coastguard Worker }
146*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_NOROTATE) {
147*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("NoRotate", &str);
148*3ac0a46fSAndroid Build Coastguard Worker }
149*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_NOVIEW) {
150*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("NoView", &str);
151*3ac0a46fSAndroid Build Coastguard Worker }
152*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_READONLY) {
153*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("ReadOnly", &str);
154*3ac0a46fSAndroid Build Coastguard Worker }
155*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_LOCKED) {
156*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("Locked", &str);
157*3ac0a46fSAndroid Build Coastguard Worker }
158*3ac0a46fSAndroid Build Coastguard Worker if (flags & FPDF_ANNOT_FLAG_TOGGLENOVIEW) {
159*3ac0a46fSAndroid Build Coastguard Worker AppendFlagString("ToggleNoView", &str);
160*3ac0a46fSAndroid Build Coastguard Worker }
161*3ac0a46fSAndroid Build Coastguard Worker return str;
162*3ac0a46fSAndroid Build Coastguard Worker }
163*3ac0a46fSAndroid Build Coastguard Worker
PageObjectTypeToCString(int type)164*3ac0a46fSAndroid Build Coastguard Worker const char* PageObjectTypeToCString(int type) {
165*3ac0a46fSAndroid Build Coastguard Worker if (type == FPDF_PAGEOBJ_TEXT) {
166*3ac0a46fSAndroid Build Coastguard Worker return "Text";
167*3ac0a46fSAndroid Build Coastguard Worker }
168*3ac0a46fSAndroid Build Coastguard Worker if (type == FPDF_PAGEOBJ_PATH) {
169*3ac0a46fSAndroid Build Coastguard Worker return "Path";
170*3ac0a46fSAndroid Build Coastguard Worker }
171*3ac0a46fSAndroid Build Coastguard Worker if (type == FPDF_PAGEOBJ_IMAGE) {
172*3ac0a46fSAndroid Build Coastguard Worker return "Image";
173*3ac0a46fSAndroid Build Coastguard Worker }
174*3ac0a46fSAndroid Build Coastguard Worker if (type == FPDF_PAGEOBJ_SHADING) {
175*3ac0a46fSAndroid Build Coastguard Worker return "Shading";
176*3ac0a46fSAndroid Build Coastguard Worker }
177*3ac0a46fSAndroid Build Coastguard Worker if (type == FPDF_PAGEOBJ_FORM) {
178*3ac0a46fSAndroid Build Coastguard Worker return "Form";
179*3ac0a46fSAndroid Build Coastguard Worker }
180*3ac0a46fSAndroid Build Coastguard Worker NOTREACHED_NORETURN();
181*3ac0a46fSAndroid Build Coastguard Worker }
182*3ac0a46fSAndroid Build Coastguard Worker
EncodePng(pdfium::span<const uint8_t> input,int width,int height,int stride,int format)183*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> EncodePng(pdfium::span<const uint8_t> input,
184*3ac0a46fSAndroid Build Coastguard Worker int width,
185*3ac0a46fSAndroid Build Coastguard Worker int height,
186*3ac0a46fSAndroid Build Coastguard Worker int stride,
187*3ac0a46fSAndroid Build Coastguard Worker int format) {
188*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png;
189*3ac0a46fSAndroid Build Coastguard Worker switch (format) {
190*3ac0a46fSAndroid Build Coastguard Worker case FPDFBitmap_Unknown:
191*3ac0a46fSAndroid Build Coastguard Worker break;
192*3ac0a46fSAndroid Build Coastguard Worker case FPDFBitmap_Gray:
193*3ac0a46fSAndroid Build Coastguard Worker png = image_diff_png::EncodeGrayPNG(input, width, height, stride);
194*3ac0a46fSAndroid Build Coastguard Worker break;
195*3ac0a46fSAndroid Build Coastguard Worker case FPDFBitmap_BGR:
196*3ac0a46fSAndroid Build Coastguard Worker png = image_diff_png::EncodeBGRPNG(input, width, height, stride);
197*3ac0a46fSAndroid Build Coastguard Worker break;
198*3ac0a46fSAndroid Build Coastguard Worker case FPDFBitmap_BGRx:
199*3ac0a46fSAndroid Build Coastguard Worker png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
200*3ac0a46fSAndroid Build Coastguard Worker /*discard_transparency=*/true);
201*3ac0a46fSAndroid Build Coastguard Worker break;
202*3ac0a46fSAndroid Build Coastguard Worker case FPDFBitmap_BGRA:
203*3ac0a46fSAndroid Build Coastguard Worker png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
204*3ac0a46fSAndroid Build Coastguard Worker /*discard_transparency=*/false);
205*3ac0a46fSAndroid Build Coastguard Worker break;
206*3ac0a46fSAndroid Build Coastguard Worker default:
207*3ac0a46fSAndroid Build Coastguard Worker NOTREACHED_NORETURN();
208*3ac0a46fSAndroid Build Coastguard Worker }
209*3ac0a46fSAndroid Build Coastguard Worker return png;
210*3ac0a46fSAndroid Build Coastguard Worker }
211*3ac0a46fSAndroid Build Coastguard Worker
212*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
EnhMetaFileProc(HDC hdc,HANDLETABLE * handle_table,const ENHMETARECORD * record,int objects_count,LPARAM param)213*3ac0a46fSAndroid Build Coastguard Worker int CALLBACK EnhMetaFileProc(HDC hdc,
214*3ac0a46fSAndroid Build Coastguard Worker HANDLETABLE* handle_table,
215*3ac0a46fSAndroid Build Coastguard Worker const ENHMETARECORD* record,
216*3ac0a46fSAndroid Build Coastguard Worker int objects_count,
217*3ac0a46fSAndroid Build Coastguard Worker LPARAM param) {
218*3ac0a46fSAndroid Build Coastguard Worker std::vector<const ENHMETARECORD*>& items =
219*3ac0a46fSAndroid Build Coastguard Worker *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
220*3ac0a46fSAndroid Build Coastguard Worker items.push_back(record);
221*3ac0a46fSAndroid Build Coastguard Worker return 1;
222*3ac0a46fSAndroid Build Coastguard Worker }
223*3ac0a46fSAndroid Build Coastguard Worker #endif // _WIN32
224*3ac0a46fSAndroid Build Coastguard Worker
GeneratePageOutputFilename(const char * pdf_name,int page_num,const char * extension)225*3ac0a46fSAndroid Build Coastguard Worker std::string GeneratePageOutputFilename(const char* pdf_name,
226*3ac0a46fSAndroid Build Coastguard Worker int page_num,
227*3ac0a46fSAndroid Build Coastguard Worker const char* extension) {
228*3ac0a46fSAndroid Build Coastguard Worker std::ostringstream stream;
229*3ac0a46fSAndroid Build Coastguard Worker stream << pdf_name << "." << page_num << "." << extension;
230*3ac0a46fSAndroid Build Coastguard Worker std::string filename = stream.str();
231*3ac0a46fSAndroid Build Coastguard Worker if (filename.size() >= 256) {
232*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Filename %s is too long\n", filename.c_str());
233*3ac0a46fSAndroid Build Coastguard Worker return std::string();
234*3ac0a46fSAndroid Build Coastguard Worker }
235*3ac0a46fSAndroid Build Coastguard Worker
236*3ac0a46fSAndroid Build Coastguard Worker return filename;
237*3ac0a46fSAndroid Build Coastguard Worker }
238*3ac0a46fSAndroid Build Coastguard Worker
GenerateImageOutputFilename(const char * pdf_name,int page_num,int image_num,const char * extension)239*3ac0a46fSAndroid Build Coastguard Worker std::string GenerateImageOutputFilename(const char* pdf_name,
240*3ac0a46fSAndroid Build Coastguard Worker int page_num,
241*3ac0a46fSAndroid Build Coastguard Worker int image_num,
242*3ac0a46fSAndroid Build Coastguard Worker const char* extension) {
243*3ac0a46fSAndroid Build Coastguard Worker std::ostringstream stream;
244*3ac0a46fSAndroid Build Coastguard Worker stream << pdf_name << "." << page_num << "." << image_num << "." << extension;
245*3ac0a46fSAndroid Build Coastguard Worker std::string filename = stream.str();
246*3ac0a46fSAndroid Build Coastguard Worker if (filename.size() >= 256) {
247*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Filename %s for saving image is too long.\n",
248*3ac0a46fSAndroid Build Coastguard Worker filename.c_str());
249*3ac0a46fSAndroid Build Coastguard Worker return std::string();
250*3ac0a46fSAndroid Build Coastguard Worker }
251*3ac0a46fSAndroid Build Coastguard Worker
252*3ac0a46fSAndroid Build Coastguard Worker return filename;
253*3ac0a46fSAndroid Build Coastguard Worker }
254*3ac0a46fSAndroid Build Coastguard Worker
255*3ac0a46fSAndroid Build Coastguard Worker } // namespace
256*3ac0a46fSAndroid Build Coastguard Worker
WritePpm(const char * pdf_name,int num,void * buffer_void,int stride,int width,int height)257*3ac0a46fSAndroid Build Coastguard Worker std::string WritePpm(const char* pdf_name,
258*3ac0a46fSAndroid Build Coastguard Worker int num,
259*3ac0a46fSAndroid Build Coastguard Worker void* buffer_void,
260*3ac0a46fSAndroid Build Coastguard Worker int stride,
261*3ac0a46fSAndroid Build Coastguard Worker int width,
262*3ac0a46fSAndroid Build Coastguard Worker int height) {
263*3ac0a46fSAndroid Build Coastguard Worker if (!CheckDimensions(stride, width, height)) {
264*3ac0a46fSAndroid Build Coastguard Worker return "";
265*3ac0a46fSAndroid Build Coastguard Worker }
266*3ac0a46fSAndroid Build Coastguard Worker
267*3ac0a46fSAndroid Build Coastguard Worker int out_len = width * height;
268*3ac0a46fSAndroid Build Coastguard Worker if (out_len > INT_MAX / 3) {
269*3ac0a46fSAndroid Build Coastguard Worker return "";
270*3ac0a46fSAndroid Build Coastguard Worker }
271*3ac0a46fSAndroid Build Coastguard Worker
272*3ac0a46fSAndroid Build Coastguard Worker out_len *= 3;
273*3ac0a46fSAndroid Build Coastguard Worker
274*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "ppm");
275*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
276*3ac0a46fSAndroid Build Coastguard Worker return std::string();
277*3ac0a46fSAndroid Build Coastguard Worker }
278*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "wb");
279*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
280*3ac0a46fSAndroid Build Coastguard Worker return std::string();
281*3ac0a46fSAndroid Build Coastguard Worker }
282*3ac0a46fSAndroid Build Coastguard Worker
283*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
284*3ac0a46fSAndroid Build Coastguard Worker // Source data is B, G, R, unused.
285*3ac0a46fSAndroid Build Coastguard Worker // Dest data is R, G, B.
286*3ac0a46fSAndroid Build Coastguard Worker const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buffer_void);
287*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> result(out_len);
288*3ac0a46fSAndroid Build Coastguard Worker for (int h = 0; h < height; ++h) {
289*3ac0a46fSAndroid Build Coastguard Worker const uint8_t* src_line = buffer + (stride * h);
290*3ac0a46fSAndroid Build Coastguard Worker uint8_t* dest_line = result.data() + (width * h * 3);
291*3ac0a46fSAndroid Build Coastguard Worker for (int w = 0; w < width; ++w) {
292*3ac0a46fSAndroid Build Coastguard Worker // R
293*3ac0a46fSAndroid Build Coastguard Worker dest_line[w * 3] = src_line[(w * 4) + 2];
294*3ac0a46fSAndroid Build Coastguard Worker // G
295*3ac0a46fSAndroid Build Coastguard Worker dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
296*3ac0a46fSAndroid Build Coastguard Worker // B
297*3ac0a46fSAndroid Build Coastguard Worker dest_line[(w * 3) + 2] = src_line[w * 4];
298*3ac0a46fSAndroid Build Coastguard Worker }
299*3ac0a46fSAndroid Build Coastguard Worker }
300*3ac0a46fSAndroid Build Coastguard Worker if (fwrite(result.data(), out_len, 1, fp) != 1) {
301*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
302*3ac0a46fSAndroid Build Coastguard Worker }
303*3ac0a46fSAndroid Build Coastguard Worker
304*3ac0a46fSAndroid Build Coastguard Worker fclose(fp);
305*3ac0a46fSAndroid Build Coastguard Worker return filename;
306*3ac0a46fSAndroid Build Coastguard Worker }
307*3ac0a46fSAndroid Build Coastguard Worker
WriteText(FPDF_TEXTPAGE textpage,const char * pdf_name,int num)308*3ac0a46fSAndroid Build Coastguard Worker void WriteText(FPDF_TEXTPAGE textpage, const char* pdf_name, int num) {
309*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "txt");
310*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
311*3ac0a46fSAndroid Build Coastguard Worker return;
312*3ac0a46fSAndroid Build Coastguard Worker }
313*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "w");
314*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
315*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to open %s for output\n", filename.c_str());
316*3ac0a46fSAndroid Build Coastguard Worker return;
317*3ac0a46fSAndroid Build Coastguard Worker }
318*3ac0a46fSAndroid Build Coastguard Worker
319*3ac0a46fSAndroid Build Coastguard Worker // Output in UTF32-LE.
320*3ac0a46fSAndroid Build Coastguard Worker uint32_t bom = 0x0000FEFF;
321*3ac0a46fSAndroid Build Coastguard Worker if (fwrite(&bom, sizeof(bom), 1, fp) != 1) {
322*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
323*3ac0a46fSAndroid Build Coastguard Worker (void)fclose(fp);
324*3ac0a46fSAndroid Build Coastguard Worker return;
325*3ac0a46fSAndroid Build Coastguard Worker }
326*3ac0a46fSAndroid Build Coastguard Worker
327*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < FPDFText_CountChars(textpage); i++) {
328*3ac0a46fSAndroid Build Coastguard Worker uint32_t c = FPDFText_GetUnicode(textpage, i);
329*3ac0a46fSAndroid Build Coastguard Worker if (fwrite(&c, sizeof(c), 1, fp) != 1) {
330*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
331*3ac0a46fSAndroid Build Coastguard Worker break;
332*3ac0a46fSAndroid Build Coastguard Worker }
333*3ac0a46fSAndroid Build Coastguard Worker }
334*3ac0a46fSAndroid Build Coastguard Worker (void)fclose(fp);
335*3ac0a46fSAndroid Build Coastguard Worker }
336*3ac0a46fSAndroid Build Coastguard Worker
WriteAnnot(FPDF_PAGE page,const char * pdf_name,int num)337*3ac0a46fSAndroid Build Coastguard Worker void WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) {
338*3ac0a46fSAndroid Build Coastguard Worker // Open the output text file.
339*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "annot.txt");
340*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
341*3ac0a46fSAndroid Build Coastguard Worker return;
342*3ac0a46fSAndroid Build Coastguard Worker }
343*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "w");
344*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
345*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to open %s for output\n", filename.c_str());
346*3ac0a46fSAndroid Build Coastguard Worker return;
347*3ac0a46fSAndroid Build Coastguard Worker }
348*3ac0a46fSAndroid Build Coastguard Worker
349*3ac0a46fSAndroid Build Coastguard Worker int annot_count = FPDFPage_GetAnnotCount(page);
350*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Number of annotations: %d\n\n", annot_count);
351*3ac0a46fSAndroid Build Coastguard Worker
352*3ac0a46fSAndroid Build Coastguard Worker // Iterate through all annotations on this page.
353*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < annot_count; ++i) {
354*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation object and its subtype.
355*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Annotation #%d:\n", i + 1);
356*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, i));
357*3ac0a46fSAndroid Build Coastguard Worker if (!annot) {
358*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Failed to retrieve annotation!\n\n");
359*3ac0a46fSAndroid Build Coastguard Worker continue;
360*3ac0a46fSAndroid Build Coastguard Worker }
361*3ac0a46fSAndroid Build Coastguard Worker
362*3ac0a46fSAndroid Build Coastguard Worker FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot.get());
363*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Subtype: %s\n", AnnotSubtypeToCString(subtype));
364*3ac0a46fSAndroid Build Coastguard Worker
365*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation flags.
366*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Flags set: %s\n",
367*3ac0a46fSAndroid Build Coastguard Worker AnnotFlagsToString(FPDFAnnot_GetFlags(annot.get())).c_str());
368*3ac0a46fSAndroid Build Coastguard Worker
369*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation's object count and object types.
370*3ac0a46fSAndroid Build Coastguard Worker const int obj_count = FPDFAnnot_GetObjectCount(annot.get());
371*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Number of objects: %d\n", obj_count);
372*3ac0a46fSAndroid Build Coastguard Worker if (obj_count > 0) {
373*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Object types: ");
374*3ac0a46fSAndroid Build Coastguard Worker for (int j = 0; j < obj_count; ++j) {
375*3ac0a46fSAndroid Build Coastguard Worker const char* type = PageObjectTypeToCString(
376*3ac0a46fSAndroid Build Coastguard Worker FPDFPageObj_GetType(FPDFAnnot_GetObject(annot.get(), j)));
377*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "%s ", type);
378*3ac0a46fSAndroid Build Coastguard Worker }
379*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "\n");
380*3ac0a46fSAndroid Build Coastguard Worker }
381*3ac0a46fSAndroid Build Coastguard Worker
382*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation's color and interior color.
383*3ac0a46fSAndroid Build Coastguard Worker unsigned int R;
384*3ac0a46fSAndroid Build Coastguard Worker unsigned int G;
385*3ac0a46fSAndroid Build Coastguard Worker unsigned int B;
386*3ac0a46fSAndroid Build Coastguard Worker unsigned int A;
387*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_Color, &R, &G, &B,
388*3ac0a46fSAndroid Build Coastguard Worker &A)) {
389*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Color in RGBA: %d %d %d %d\n", R, G, B, A);
390*3ac0a46fSAndroid Build Coastguard Worker } else {
391*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Failed to retrieve color.\n");
392*3ac0a46fSAndroid Build Coastguard Worker }
393*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_GetColor(annot.get(), FPDFANNOT_COLORTYPE_InteriorColor, &R,
394*3ac0a46fSAndroid Build Coastguard Worker &G, &B, &A)) {
395*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Interior color in RGBA: %d %d %d %d\n", R, G, B, A);
396*3ac0a46fSAndroid Build Coastguard Worker } else {
397*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Failed to retrieve interior color.\n");
398*3ac0a46fSAndroid Build Coastguard Worker }
399*3ac0a46fSAndroid Build Coastguard Worker
400*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation's contents and author.
401*3ac0a46fSAndroid Build Coastguard Worker static constexpr char kContentsKey[] = "Contents";
402*3ac0a46fSAndroid Build Coastguard Worker static constexpr char kAuthorKey[] = "T";
403*3ac0a46fSAndroid Build Coastguard Worker unsigned long length_bytes =
404*3ac0a46fSAndroid Build Coastguard Worker FPDFAnnot_GetStringValue(annot.get(), kContentsKey, nullptr, 0);
405*3ac0a46fSAndroid Build Coastguard Worker std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
406*3ac0a46fSAndroid Build Coastguard Worker FPDFAnnot_GetStringValue(annot.get(), kContentsKey, buf.data(),
407*3ac0a46fSAndroid Build Coastguard Worker length_bytes);
408*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Content: %ls\n", GetPlatformWString(buf.data()).c_str());
409*3ac0a46fSAndroid Build Coastguard Worker length_bytes =
410*3ac0a46fSAndroid Build Coastguard Worker FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, nullptr, 0);
411*3ac0a46fSAndroid Build Coastguard Worker buf = GetFPDFWideStringBuffer(length_bytes);
412*3ac0a46fSAndroid Build Coastguard Worker FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, buf.data(), length_bytes);
413*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Author: %ls\n", GetPlatformWString(buf.data()).c_str());
414*3ac0a46fSAndroid Build Coastguard Worker
415*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation's quadpoints if it is a markup annotation.
416*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_HasAttachmentPoints(annot.get())) {
417*3ac0a46fSAndroid Build Coastguard Worker size_t qp_count = FPDFAnnot_CountAttachmentPoints(annot.get());
418*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Number of quadpoints sets: %zu\n", qp_count);
419*3ac0a46fSAndroid Build Coastguard Worker
420*3ac0a46fSAndroid Build Coastguard Worker // Iterate through all quadpoints of the current annotation
421*3ac0a46fSAndroid Build Coastguard Worker for (size_t j = 0; j < qp_count; ++j) {
422*3ac0a46fSAndroid Build Coastguard Worker FS_QUADPOINTSF quadpoints;
423*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_GetAttachmentPoints(annot.get(), j, &quadpoints)) {
424*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp,
425*3ac0a46fSAndroid Build Coastguard Worker "Quadpoints set #%zu: (%.3f, %.3f), (%.3f, %.3f), "
426*3ac0a46fSAndroid Build Coastguard Worker "(%.3f, %.3f), (%.3f, %.3f)\n",
427*3ac0a46fSAndroid Build Coastguard Worker j + 1, quadpoints.x1, quadpoints.y1, quadpoints.x2,
428*3ac0a46fSAndroid Build Coastguard Worker quadpoints.y2, quadpoints.x3, quadpoints.y3, quadpoints.x4,
429*3ac0a46fSAndroid Build Coastguard Worker quadpoints.y4);
430*3ac0a46fSAndroid Build Coastguard Worker } else {
431*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Failed to retrieve quadpoints set #%zu.\n", j + 1);
432*3ac0a46fSAndroid Build Coastguard Worker }
433*3ac0a46fSAndroid Build Coastguard Worker }
434*3ac0a46fSAndroid Build Coastguard Worker }
435*3ac0a46fSAndroid Build Coastguard Worker
436*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the annotation's rectangle coordinates.
437*3ac0a46fSAndroid Build Coastguard Worker FS_RECTF rect;
438*3ac0a46fSAndroid Build Coastguard Worker if (FPDFAnnot_GetRect(annot.get(), &rect)) {
439*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Rectangle: l - %.3f, b - %.3f, r - %.3f, t - %.3f\n\n",
440*3ac0a46fSAndroid Build Coastguard Worker rect.left, rect.bottom, rect.right, rect.top);
441*3ac0a46fSAndroid Build Coastguard Worker } else {
442*3ac0a46fSAndroid Build Coastguard Worker fprintf(fp, "Failed to retrieve annotation rectangle.\n");
443*3ac0a46fSAndroid Build Coastguard Worker }
444*3ac0a46fSAndroid Build Coastguard Worker }
445*3ac0a46fSAndroid Build Coastguard Worker
446*3ac0a46fSAndroid Build Coastguard Worker (void)fclose(fp);
447*3ac0a46fSAndroid Build Coastguard Worker }
448*3ac0a46fSAndroid Build Coastguard Worker
WritePng(const char * pdf_name,int num,void * buffer,int stride,int width,int height)449*3ac0a46fSAndroid Build Coastguard Worker std::string WritePng(const char* pdf_name,
450*3ac0a46fSAndroid Build Coastguard Worker int num,
451*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
452*3ac0a46fSAndroid Build Coastguard Worker int stride,
453*3ac0a46fSAndroid Build Coastguard Worker int width,
454*3ac0a46fSAndroid Build Coastguard Worker int height) {
455*3ac0a46fSAndroid Build Coastguard Worker if (!CheckDimensions(stride, width, height)) {
456*3ac0a46fSAndroid Build Coastguard Worker return "";
457*3ac0a46fSAndroid Build Coastguard Worker }
458*3ac0a46fSAndroid Build Coastguard Worker
459*3ac0a46fSAndroid Build Coastguard Worker auto input =
460*3ac0a46fSAndroid Build Coastguard Worker pdfium::make_span(static_cast<uint8_t*>(buffer), stride * height);
461*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png_encoding =
462*3ac0a46fSAndroid Build Coastguard Worker EncodePng(input, width, height, stride, FPDFBitmap_BGRA);
463*3ac0a46fSAndroid Build Coastguard Worker if (png_encoding.empty()) {
464*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to convert bitmap to PNG\n");
465*3ac0a46fSAndroid Build Coastguard Worker return "";
466*3ac0a46fSAndroid Build Coastguard Worker }
467*3ac0a46fSAndroid Build Coastguard Worker
468*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "png");
469*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
470*3ac0a46fSAndroid Build Coastguard Worker return std::string();
471*3ac0a46fSAndroid Build Coastguard Worker }
472*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "wb");
473*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
474*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to open %s for output\n", filename.c_str());
475*3ac0a46fSAndroid Build Coastguard Worker return std::string();
476*3ac0a46fSAndroid Build Coastguard Worker }
477*3ac0a46fSAndroid Build Coastguard Worker
478*3ac0a46fSAndroid Build Coastguard Worker size_t bytes_written =
479*3ac0a46fSAndroid Build Coastguard Worker fwrite(&png_encoding.front(), 1, png_encoding.size(), fp);
480*3ac0a46fSAndroid Build Coastguard Worker if (bytes_written != png_encoding.size()) {
481*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
482*3ac0a46fSAndroid Build Coastguard Worker }
483*3ac0a46fSAndroid Build Coastguard Worker
484*3ac0a46fSAndroid Build Coastguard Worker (void)fclose(fp);
485*3ac0a46fSAndroid Build Coastguard Worker return filename;
486*3ac0a46fSAndroid Build Coastguard Worker }
487*3ac0a46fSAndroid Build Coastguard Worker
488*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
WriteBmp(const char * pdf_name,int num,void * buffer,int stride,int width,int height)489*3ac0a46fSAndroid Build Coastguard Worker std::string WriteBmp(const char* pdf_name,
490*3ac0a46fSAndroid Build Coastguard Worker int num,
491*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
492*3ac0a46fSAndroid Build Coastguard Worker int stride,
493*3ac0a46fSAndroid Build Coastguard Worker int width,
494*3ac0a46fSAndroid Build Coastguard Worker int height) {
495*3ac0a46fSAndroid Build Coastguard Worker if (!CheckDimensions(stride, width, height)) {
496*3ac0a46fSAndroid Build Coastguard Worker return std::string();
497*3ac0a46fSAndroid Build Coastguard Worker }
498*3ac0a46fSAndroid Build Coastguard Worker
499*3ac0a46fSAndroid Build Coastguard Worker int out_len = stride * height;
500*3ac0a46fSAndroid Build Coastguard Worker if (out_len > INT_MAX / 3) {
501*3ac0a46fSAndroid Build Coastguard Worker return std::string();
502*3ac0a46fSAndroid Build Coastguard Worker }
503*3ac0a46fSAndroid Build Coastguard Worker
504*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "bmp");
505*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
506*3ac0a46fSAndroid Build Coastguard Worker return std::string();
507*3ac0a46fSAndroid Build Coastguard Worker }
508*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "wb");
509*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
510*3ac0a46fSAndroid Build Coastguard Worker return std::string();
511*3ac0a46fSAndroid Build Coastguard Worker }
512*3ac0a46fSAndroid Build Coastguard Worker
513*3ac0a46fSAndroid Build Coastguard Worker BITMAPINFO bmi = {};
514*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
515*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biWidth = width;
516*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biHeight = -height; // top-down image
517*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biPlanes = 1;
518*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biBitCount = 32;
519*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biCompression = BI_RGB;
520*3ac0a46fSAndroid Build Coastguard Worker bmi.bmiHeader.biSizeImage = 0;
521*3ac0a46fSAndroid Build Coastguard Worker
522*3ac0a46fSAndroid Build Coastguard Worker BITMAPFILEHEADER file_header = {};
523*3ac0a46fSAndroid Build Coastguard Worker file_header.bfType = 0x4d42;
524*3ac0a46fSAndroid Build Coastguard Worker file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
525*3ac0a46fSAndroid Build Coastguard Worker file_header.bfOffBits = file_header.bfSize - out_len;
526*3ac0a46fSAndroid Build Coastguard Worker
527*3ac0a46fSAndroid Build Coastguard Worker if (fwrite(&file_header, sizeof(file_header), 1, fp) != 1 ||
528*3ac0a46fSAndroid Build Coastguard Worker fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp) != 1 ||
529*3ac0a46fSAndroid Build Coastguard Worker fwrite(buffer, out_len, 1, fp) != 1) {
530*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
531*3ac0a46fSAndroid Build Coastguard Worker }
532*3ac0a46fSAndroid Build Coastguard Worker fclose(fp);
533*3ac0a46fSAndroid Build Coastguard Worker return filename;
534*3ac0a46fSAndroid Build Coastguard Worker }
535*3ac0a46fSAndroid Build Coastguard Worker
WriteEmf(FPDF_PAGE page,const char * pdf_name,int num)536*3ac0a46fSAndroid Build Coastguard Worker void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
537*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "emf");
538*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
539*3ac0a46fSAndroid Build Coastguard Worker return;
540*3ac0a46fSAndroid Build Coastguard Worker }
541*3ac0a46fSAndroid Build Coastguard Worker
542*3ac0a46fSAndroid Build Coastguard Worker HDC dc = CreateEnhMetaFileA(nullptr, filename.c_str(), nullptr, nullptr);
543*3ac0a46fSAndroid Build Coastguard Worker
544*3ac0a46fSAndroid Build Coastguard Worker int width = static_cast<int>(FPDF_GetPageWidthF(page));
545*3ac0a46fSAndroid Build Coastguard Worker int height = static_cast<int>(FPDF_GetPageHeightF(page));
546*3ac0a46fSAndroid Build Coastguard Worker HRGN rgn = CreateRectRgn(0, 0, width, height);
547*3ac0a46fSAndroid Build Coastguard Worker SelectClipRgn(dc, rgn);
548*3ac0a46fSAndroid Build Coastguard Worker DeleteObject(rgn);
549*3ac0a46fSAndroid Build Coastguard Worker
550*3ac0a46fSAndroid Build Coastguard Worker SelectObject(dc, GetStockObject(NULL_PEN));
551*3ac0a46fSAndroid Build Coastguard Worker SelectObject(dc, GetStockObject(WHITE_BRUSH));
552*3ac0a46fSAndroid Build Coastguard Worker // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
553*3ac0a46fSAndroid Build Coastguard Worker Rectangle(dc, 0, 0, width + 1, height + 1);
554*3ac0a46fSAndroid Build Coastguard Worker
555*3ac0a46fSAndroid Build Coastguard Worker FPDF_RenderPage(dc, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_PRINTING);
556*3ac0a46fSAndroid Build Coastguard Worker
557*3ac0a46fSAndroid Build Coastguard Worker DeleteEnhMetaFile(CloseEnhMetaFile(dc));
558*3ac0a46fSAndroid Build Coastguard Worker }
559*3ac0a46fSAndroid Build Coastguard Worker
WritePS(FPDF_PAGE page,const char * pdf_name,int num)560*3ac0a46fSAndroid Build Coastguard Worker void WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
561*3ac0a46fSAndroid Build Coastguard Worker std::string filename = GeneratePageOutputFilename(pdf_name, num, "ps");
562*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
563*3ac0a46fSAndroid Build Coastguard Worker return;
564*3ac0a46fSAndroid Build Coastguard Worker }
565*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename.c_str(), "wb");
566*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
567*3ac0a46fSAndroid Build Coastguard Worker return;
568*3ac0a46fSAndroid Build Coastguard Worker }
569*3ac0a46fSAndroid Build Coastguard Worker
570*3ac0a46fSAndroid Build Coastguard Worker HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
571*3ac0a46fSAndroid Build Coastguard Worker
572*3ac0a46fSAndroid Build Coastguard Worker int width = static_cast<int>(FPDF_GetPageWidthF(page));
573*3ac0a46fSAndroid Build Coastguard Worker int height = static_cast<int>(FPDF_GetPageHeightF(page));
574*3ac0a46fSAndroid Build Coastguard Worker FPDF_RenderPage(dc, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_PRINTING);
575*3ac0a46fSAndroid Build Coastguard Worker
576*3ac0a46fSAndroid Build Coastguard Worker HENHMETAFILE emf = CloseEnhMetaFile(dc);
577*3ac0a46fSAndroid Build Coastguard Worker std::vector<const ENHMETARECORD*> items;
578*3ac0a46fSAndroid Build Coastguard Worker EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
579*3ac0a46fSAndroid Build Coastguard Worker for (const ENHMETARECORD* record : items) {
580*3ac0a46fSAndroid Build Coastguard Worker if (record->iType != EMR_GDICOMMENT) {
581*3ac0a46fSAndroid Build Coastguard Worker continue;
582*3ac0a46fSAndroid Build Coastguard Worker }
583*3ac0a46fSAndroid Build Coastguard Worker
584*3ac0a46fSAndroid Build Coastguard Worker const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
585*3ac0a46fSAndroid Build Coastguard Worker const char* data = reinterpret_cast<const char*>(comment->Data);
586*3ac0a46fSAndroid Build Coastguard Worker uint16_t size = *reinterpret_cast<const uint16_t*>(data);
587*3ac0a46fSAndroid Build Coastguard Worker if (fwrite(data + sizeof(uint16_t), size, 1, fp) != 1) {
588*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s\n", filename.c_str());
589*3ac0a46fSAndroid Build Coastguard Worker break;
590*3ac0a46fSAndroid Build Coastguard Worker }
591*3ac0a46fSAndroid Build Coastguard Worker }
592*3ac0a46fSAndroid Build Coastguard Worker fclose(fp);
593*3ac0a46fSAndroid Build Coastguard Worker DeleteEnhMetaFile(emf);
594*3ac0a46fSAndroid Build Coastguard Worker }
595*3ac0a46fSAndroid Build Coastguard Worker #endif // _WIN32
596*3ac0a46fSAndroid Build Coastguard Worker
597*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
WriteToSkWStream(const std::string & pdf_name,int num,const std::string & extension)598*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<SkWStream> WriteToSkWStream(const std::string& pdf_name,
599*3ac0a46fSAndroid Build Coastguard Worker int num,
600*3ac0a46fSAndroid Build Coastguard Worker const std::string& extension) {
601*3ac0a46fSAndroid Build Coastguard Worker std::string discarded_filename;
602*3ac0a46fSAndroid Build Coastguard Worker return WriteToSkWStream(pdf_name, num, extension, discarded_filename);
603*3ac0a46fSAndroid Build Coastguard Worker }
604*3ac0a46fSAndroid Build Coastguard Worker
WriteToSkWStream(const std::string & pdf_name,int num,const std::string & extension,std::string & filename)605*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<SkWStream> WriteToSkWStream(const std::string& pdf_name,
606*3ac0a46fSAndroid Build Coastguard Worker int num,
607*3ac0a46fSAndroid Build Coastguard Worker const std::string& extension,
608*3ac0a46fSAndroid Build Coastguard Worker std::string& filename) {
609*3ac0a46fSAndroid Build Coastguard Worker filename =
610*3ac0a46fSAndroid Build Coastguard Worker GeneratePageOutputFilename(pdf_name.c_str(), num, extension.c_str());
611*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
612*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
613*3ac0a46fSAndroid Build Coastguard Worker }
614*3ac0a46fSAndroid Build Coastguard Worker
615*3ac0a46fSAndroid Build Coastguard Worker auto stream = std::make_unique<SkFILEWStream>(filename.c_str());
616*3ac0a46fSAndroid Build Coastguard Worker if (!stream->isValid()) {
617*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
618*3ac0a46fSAndroid Build Coastguard Worker }
619*3ac0a46fSAndroid Build Coastguard Worker
620*3ac0a46fSAndroid Build Coastguard Worker return stream;
621*3ac0a46fSAndroid Build Coastguard Worker }
622*3ac0a46fSAndroid Build Coastguard Worker
WriteSkp(const char * pdf_name,int num,const SkPicture & picture)623*3ac0a46fSAndroid Build Coastguard Worker std::string WriteSkp(const char* pdf_name, int num, const SkPicture& picture) {
624*3ac0a46fSAndroid Build Coastguard Worker std::string filename;
625*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<SkWStream> stream =
626*3ac0a46fSAndroid Build Coastguard Worker WriteToSkWStream(pdf_name, num, "skp", filename);
627*3ac0a46fSAndroid Build Coastguard Worker if (!stream) {
628*3ac0a46fSAndroid Build Coastguard Worker return "";
629*3ac0a46fSAndroid Build Coastguard Worker }
630*3ac0a46fSAndroid Build Coastguard Worker
631*3ac0a46fSAndroid Build Coastguard Worker picture.serialize(stream.get());
632*3ac0a46fSAndroid Build Coastguard Worker return filename;
633*3ac0a46fSAndroid Build Coastguard Worker }
634*3ac0a46fSAndroid Build Coastguard Worker #endif // PDF_ENABLE_SKIA
635*3ac0a46fSAndroid Build Coastguard Worker
636*3ac0a46fSAndroid Build Coastguard Worker enum class ThumbnailDecodeType { kBitmap, kRawStream, kDecodedStream };
637*3ac0a46fSAndroid Build Coastguard Worker
GetThumbnailFilename(char * name_buf,size_t name_buf_size,const char * pdf_name,int page_num,ThumbnailDecodeType decode_type)638*3ac0a46fSAndroid Build Coastguard Worker bool GetThumbnailFilename(char* name_buf,
639*3ac0a46fSAndroid Build Coastguard Worker size_t name_buf_size,
640*3ac0a46fSAndroid Build Coastguard Worker const char* pdf_name,
641*3ac0a46fSAndroid Build Coastguard Worker int page_num,
642*3ac0a46fSAndroid Build Coastguard Worker ThumbnailDecodeType decode_type) {
643*3ac0a46fSAndroid Build Coastguard Worker const char* format;
644*3ac0a46fSAndroid Build Coastguard Worker switch (decode_type) {
645*3ac0a46fSAndroid Build Coastguard Worker case ThumbnailDecodeType::kBitmap:
646*3ac0a46fSAndroid Build Coastguard Worker format = "%s.thumbnail.%d.png";
647*3ac0a46fSAndroid Build Coastguard Worker break;
648*3ac0a46fSAndroid Build Coastguard Worker case ThumbnailDecodeType::kDecodedStream:
649*3ac0a46fSAndroid Build Coastguard Worker format = "%s.thumbnail.decoded.%d.bin";
650*3ac0a46fSAndroid Build Coastguard Worker break;
651*3ac0a46fSAndroid Build Coastguard Worker case ThumbnailDecodeType::kRawStream:
652*3ac0a46fSAndroid Build Coastguard Worker format = "%s.thumbnail.raw.%d.bin";
653*3ac0a46fSAndroid Build Coastguard Worker break;
654*3ac0a46fSAndroid Build Coastguard Worker }
655*3ac0a46fSAndroid Build Coastguard Worker
656*3ac0a46fSAndroid Build Coastguard Worker int chars_formatted =
657*3ac0a46fSAndroid Build Coastguard Worker snprintf(name_buf, name_buf_size, format, pdf_name, page_num);
658*3ac0a46fSAndroid Build Coastguard Worker if (chars_formatted < 0 ||
659*3ac0a46fSAndroid Build Coastguard Worker static_cast<size_t>(chars_formatted) >= name_buf_size) {
660*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Filename %s for saving is too long.\n", name_buf);
661*3ac0a46fSAndroid Build Coastguard Worker return false;
662*3ac0a46fSAndroid Build Coastguard Worker }
663*3ac0a46fSAndroid Build Coastguard Worker
664*3ac0a46fSAndroid Build Coastguard Worker return true;
665*3ac0a46fSAndroid Build Coastguard Worker }
666*3ac0a46fSAndroid Build Coastguard Worker
WriteBufferToFile(const void * buf,size_t buflen,const char * filename,const char * filetype)667*3ac0a46fSAndroid Build Coastguard Worker void WriteBufferToFile(const void* buf,
668*3ac0a46fSAndroid Build Coastguard Worker size_t buflen,
669*3ac0a46fSAndroid Build Coastguard Worker const char* filename,
670*3ac0a46fSAndroid Build Coastguard Worker const char* filetype) {
671*3ac0a46fSAndroid Build Coastguard Worker FILE* fp = fopen(filename, "wb");
672*3ac0a46fSAndroid Build Coastguard Worker if (!fp) {
673*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to open %s for saving %s.", filename, filetype);
674*3ac0a46fSAndroid Build Coastguard Worker return;
675*3ac0a46fSAndroid Build Coastguard Worker }
676*3ac0a46fSAndroid Build Coastguard Worker
677*3ac0a46fSAndroid Build Coastguard Worker size_t bytes_written = fwrite(buf, 1, buflen, fp);
678*3ac0a46fSAndroid Build Coastguard Worker if (bytes_written == buflen) {
679*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Successfully wrote %s %s.\n", filetype, filename);
680*3ac0a46fSAndroid Build Coastguard Worker } else {
681*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to %s.\n", filename);
682*3ac0a46fSAndroid Build Coastguard Worker }
683*3ac0a46fSAndroid Build Coastguard Worker fclose(fp);
684*3ac0a46fSAndroid Build Coastguard Worker }
685*3ac0a46fSAndroid Build Coastguard Worker
EncodeBitmapToPng(ScopedFPDFBitmap bitmap)686*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> EncodeBitmapToPng(ScopedFPDFBitmap bitmap) {
687*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png_encoding;
688*3ac0a46fSAndroid Build Coastguard Worker int format = FPDFBitmap_GetFormat(bitmap.get());
689*3ac0a46fSAndroid Build Coastguard Worker if (format == FPDFBitmap_Unknown) {
690*3ac0a46fSAndroid Build Coastguard Worker return png_encoding;
691*3ac0a46fSAndroid Build Coastguard Worker }
692*3ac0a46fSAndroid Build Coastguard Worker
693*3ac0a46fSAndroid Build Coastguard Worker int width = FPDFBitmap_GetWidth(bitmap.get());
694*3ac0a46fSAndroid Build Coastguard Worker int height = FPDFBitmap_GetHeight(bitmap.get());
695*3ac0a46fSAndroid Build Coastguard Worker int stride = FPDFBitmap_GetStride(bitmap.get());
696*3ac0a46fSAndroid Build Coastguard Worker if (!CheckDimensions(stride, width, height)) {
697*3ac0a46fSAndroid Build Coastguard Worker return png_encoding;
698*3ac0a46fSAndroid Build Coastguard Worker }
699*3ac0a46fSAndroid Build Coastguard Worker
700*3ac0a46fSAndroid Build Coastguard Worker auto input = pdfium::make_span(
701*3ac0a46fSAndroid Build Coastguard Worker static_cast<const uint8_t*>(FPDFBitmap_GetBuffer(bitmap.get())),
702*3ac0a46fSAndroid Build Coastguard Worker stride * height);
703*3ac0a46fSAndroid Build Coastguard Worker
704*3ac0a46fSAndroid Build Coastguard Worker png_encoding = EncodePng(input, width, height, stride, format);
705*3ac0a46fSAndroid Build Coastguard Worker return png_encoding;
706*3ac0a46fSAndroid Build Coastguard Worker }
707*3ac0a46fSAndroid Build Coastguard Worker
WriteAttachments(FPDF_DOCUMENT doc,const std::string & name)708*3ac0a46fSAndroid Build Coastguard Worker void WriteAttachments(FPDF_DOCUMENT doc, const std::string& name) {
709*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < FPDFDoc_GetAttachmentCount(doc); ++i) {
710*3ac0a46fSAndroid Build Coastguard Worker FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(doc, i);
711*3ac0a46fSAndroid Build Coastguard Worker
712*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the attachment file name.
713*3ac0a46fSAndroid Build Coastguard Worker std::string attachment_name;
714*3ac0a46fSAndroid Build Coastguard Worker unsigned long length_bytes = FPDFAttachment_GetName(attachment, nullptr, 0);
715*3ac0a46fSAndroid Build Coastguard Worker if (length_bytes) {
716*3ac0a46fSAndroid Build Coastguard Worker std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
717*3ac0a46fSAndroid Build Coastguard Worker unsigned long actual_length_bytes =
718*3ac0a46fSAndroid Build Coastguard Worker FPDFAttachment_GetName(attachment, buf.data(), length_bytes);
719*3ac0a46fSAndroid Build Coastguard Worker if (actual_length_bytes == length_bytes) {
720*3ac0a46fSAndroid Build Coastguard Worker attachment_name = GetPlatformString(buf.data());
721*3ac0a46fSAndroid Build Coastguard Worker }
722*3ac0a46fSAndroid Build Coastguard Worker }
723*3ac0a46fSAndroid Build Coastguard Worker if (attachment_name.empty()) {
724*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Attachment #%d has an empty file name.\n", i + 1);
725*3ac0a46fSAndroid Build Coastguard Worker continue;
726*3ac0a46fSAndroid Build Coastguard Worker }
727*3ac0a46fSAndroid Build Coastguard Worker
728*3ac0a46fSAndroid Build Coastguard Worker // Calculate the full attachment file name.
729*3ac0a46fSAndroid Build Coastguard Worker char save_name[256];
730*3ac0a46fSAndroid Build Coastguard Worker int chars_formatted =
731*3ac0a46fSAndroid Build Coastguard Worker snprintf(save_name, sizeof(save_name), "%s.attachment.%s", name.c_str(),
732*3ac0a46fSAndroid Build Coastguard Worker attachment_name.c_str());
733*3ac0a46fSAndroid Build Coastguard Worker if (chars_formatted < 0 ||
734*3ac0a46fSAndroid Build Coastguard Worker static_cast<size_t>(chars_formatted) >= sizeof(save_name)) {
735*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Filename %s is too long.\n", save_name);
736*3ac0a46fSAndroid Build Coastguard Worker continue;
737*3ac0a46fSAndroid Build Coastguard Worker }
738*3ac0a46fSAndroid Build Coastguard Worker
739*3ac0a46fSAndroid Build Coastguard Worker // Retrieve the attachment.
740*3ac0a46fSAndroid Build Coastguard Worker if (!FPDFAttachment_GetFile(attachment, nullptr, 0, &length_bytes)) {
741*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to retrieve attachment \"%s\".\n",
742*3ac0a46fSAndroid Build Coastguard Worker attachment_name.c_str());
743*3ac0a46fSAndroid Build Coastguard Worker continue;
744*3ac0a46fSAndroid Build Coastguard Worker }
745*3ac0a46fSAndroid Build Coastguard Worker
746*3ac0a46fSAndroid Build Coastguard Worker std::vector<char> data_buf(length_bytes);
747*3ac0a46fSAndroid Build Coastguard Worker if (length_bytes) {
748*3ac0a46fSAndroid Build Coastguard Worker unsigned long actual_length_bytes;
749*3ac0a46fSAndroid Build Coastguard Worker if (!FPDFAttachment_GetFile(attachment, data_buf.data(), length_bytes,
750*3ac0a46fSAndroid Build Coastguard Worker &actual_length_bytes)) {
751*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to retrieve attachment \"%s\".\n",
752*3ac0a46fSAndroid Build Coastguard Worker attachment_name.c_str());
753*3ac0a46fSAndroid Build Coastguard Worker continue;
754*3ac0a46fSAndroid Build Coastguard Worker }
755*3ac0a46fSAndroid Build Coastguard Worker }
756*3ac0a46fSAndroid Build Coastguard Worker
757*3ac0a46fSAndroid Build Coastguard Worker // Write the attachment file. Since a PDF document could have 0-byte files
758*3ac0a46fSAndroid Build Coastguard Worker // as attachments, we should allow saving the 0-byte attachments to files.
759*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(data_buf.data(), length_bytes, save_name, "attachment");
760*3ac0a46fSAndroid Build Coastguard Worker }
761*3ac0a46fSAndroid Build Coastguard Worker }
762*3ac0a46fSAndroid Build Coastguard Worker
WriteImages(FPDF_PAGE page,const char * pdf_name,int page_num)763*3ac0a46fSAndroid Build Coastguard Worker void WriteImages(FPDF_PAGE page, const char* pdf_name, int page_num) {
764*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < FPDFPage_CountObjects(page); ++i) {
765*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
766*3ac0a46fSAndroid Build Coastguard Worker if (FPDFPageObj_GetType(obj) != FPDF_PAGEOBJ_IMAGE) {
767*3ac0a46fSAndroid Build Coastguard Worker continue;
768*3ac0a46fSAndroid Build Coastguard Worker }
769*3ac0a46fSAndroid Build Coastguard Worker
770*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
771*3ac0a46fSAndroid Build Coastguard Worker if (!bitmap) {
772*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Image object #%d on page #%d has an empty bitmap.\n",
773*3ac0a46fSAndroid Build Coastguard Worker i + 1, page_num + 1);
774*3ac0a46fSAndroid Build Coastguard Worker continue;
775*3ac0a46fSAndroid Build Coastguard Worker }
776*3ac0a46fSAndroid Build Coastguard Worker
777*3ac0a46fSAndroid Build Coastguard Worker std::string filename =
778*3ac0a46fSAndroid Build Coastguard Worker GenerateImageOutputFilename(pdf_name, page_num, i, "png");
779*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
780*3ac0a46fSAndroid Build Coastguard Worker continue;
781*3ac0a46fSAndroid Build Coastguard Worker }
782*3ac0a46fSAndroid Build Coastguard Worker
783*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png_encoding = EncodeBitmapToPng(std::move(bitmap));
784*3ac0a46fSAndroid Build Coastguard Worker if (png_encoding.empty()) {
785*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr,
786*3ac0a46fSAndroid Build Coastguard Worker "Failed to convert image object #%d, on page #%d to png.\n",
787*3ac0a46fSAndroid Build Coastguard Worker i + 1, page_num + 1);
788*3ac0a46fSAndroid Build Coastguard Worker continue;
789*3ac0a46fSAndroid Build Coastguard Worker }
790*3ac0a46fSAndroid Build Coastguard Worker
791*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(&png_encoding.front(), png_encoding.size(),
792*3ac0a46fSAndroid Build Coastguard Worker filename.c_str(), "image");
793*3ac0a46fSAndroid Build Coastguard Worker }
794*3ac0a46fSAndroid Build Coastguard Worker }
795*3ac0a46fSAndroid Build Coastguard Worker
WriteRenderedImages(FPDF_DOCUMENT doc,FPDF_PAGE page,const char * pdf_name,int page_num)796*3ac0a46fSAndroid Build Coastguard Worker void WriteRenderedImages(FPDF_DOCUMENT doc,
797*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE page,
798*3ac0a46fSAndroid Build Coastguard Worker const char* pdf_name,
799*3ac0a46fSAndroid Build Coastguard Worker int page_num) {
800*3ac0a46fSAndroid Build Coastguard Worker for (int i = 0; i < FPDFPage_CountObjects(page); ++i) {
801*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
802*3ac0a46fSAndroid Build Coastguard Worker if (FPDFPageObj_GetType(obj) != FPDF_PAGEOBJ_IMAGE) {
803*3ac0a46fSAndroid Build Coastguard Worker continue;
804*3ac0a46fSAndroid Build Coastguard Worker }
805*3ac0a46fSAndroid Build Coastguard Worker
806*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap bitmap(FPDFImageObj_GetRenderedBitmap(doc, page, obj));
807*3ac0a46fSAndroid Build Coastguard Worker if (!bitmap) {
808*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Image object #%d on page #%d has an empty bitmap.\n",
809*3ac0a46fSAndroid Build Coastguard Worker i + 1, page_num + 1);
810*3ac0a46fSAndroid Build Coastguard Worker continue;
811*3ac0a46fSAndroid Build Coastguard Worker }
812*3ac0a46fSAndroid Build Coastguard Worker
813*3ac0a46fSAndroid Build Coastguard Worker std::string filename =
814*3ac0a46fSAndroid Build Coastguard Worker GenerateImageOutputFilename(pdf_name, page_num, i, "png");
815*3ac0a46fSAndroid Build Coastguard Worker if (filename.empty()) {
816*3ac0a46fSAndroid Build Coastguard Worker continue;
817*3ac0a46fSAndroid Build Coastguard Worker }
818*3ac0a46fSAndroid Build Coastguard Worker
819*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png_encoding = EncodeBitmapToPng(std::move(bitmap));
820*3ac0a46fSAndroid Build Coastguard Worker if (png_encoding.empty()) {
821*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr,
822*3ac0a46fSAndroid Build Coastguard Worker "Failed to convert image object #%d, on page #%d to png.\n",
823*3ac0a46fSAndroid Build Coastguard Worker i + 1, page_num + 1);
824*3ac0a46fSAndroid Build Coastguard Worker continue;
825*3ac0a46fSAndroid Build Coastguard Worker }
826*3ac0a46fSAndroid Build Coastguard Worker
827*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(&png_encoding.front(), png_encoding.size(),
828*3ac0a46fSAndroid Build Coastguard Worker filename.c_str(), "image");
829*3ac0a46fSAndroid Build Coastguard Worker }
830*3ac0a46fSAndroid Build Coastguard Worker }
831*3ac0a46fSAndroid Build Coastguard Worker
WriteDecodedThumbnailStream(FPDF_PAGE page,const char * pdf_name,int page_num)832*3ac0a46fSAndroid Build Coastguard Worker void WriteDecodedThumbnailStream(FPDF_PAGE page,
833*3ac0a46fSAndroid Build Coastguard Worker const char* pdf_name,
834*3ac0a46fSAndroid Build Coastguard Worker int page_num) {
835*3ac0a46fSAndroid Build Coastguard Worker char filename[256];
836*3ac0a46fSAndroid Build Coastguard Worker if (!GetThumbnailFilename(filename, sizeof(filename), pdf_name, page_num,
837*3ac0a46fSAndroid Build Coastguard Worker ThumbnailDecodeType::kDecodedStream)) {
838*3ac0a46fSAndroid Build Coastguard Worker return;
839*3ac0a46fSAndroid Build Coastguard Worker }
840*3ac0a46fSAndroid Build Coastguard Worker
841*3ac0a46fSAndroid Build Coastguard Worker unsigned long decoded_data_size =
842*3ac0a46fSAndroid Build Coastguard Worker FPDFPage_GetDecodedThumbnailData(page, nullptr, 0u);
843*3ac0a46fSAndroid Build Coastguard Worker
844*3ac0a46fSAndroid Build Coastguard Worker // Only continue if there actually is a thumbnail for this page
845*3ac0a46fSAndroid Build Coastguard Worker if (decoded_data_size == 0) {
846*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to get decoded thumbnail for page #%d.\n",
847*3ac0a46fSAndroid Build Coastguard Worker page_num + 1);
848*3ac0a46fSAndroid Build Coastguard Worker return;
849*3ac0a46fSAndroid Build Coastguard Worker }
850*3ac0a46fSAndroid Build Coastguard Worker
851*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> thumb_buf(decoded_data_size);
852*3ac0a46fSAndroid Build Coastguard Worker if (FPDFPage_GetDecodedThumbnailData(
853*3ac0a46fSAndroid Build Coastguard Worker page, thumb_buf.data(), decoded_data_size) != decoded_data_size) {
854*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to get decoded thumbnail data for %s.\n", filename);
855*3ac0a46fSAndroid Build Coastguard Worker return;
856*3ac0a46fSAndroid Build Coastguard Worker }
857*3ac0a46fSAndroid Build Coastguard Worker
858*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(thumb_buf.data(), decoded_data_size, filename,
859*3ac0a46fSAndroid Build Coastguard Worker "decoded thumbnail");
860*3ac0a46fSAndroid Build Coastguard Worker }
861*3ac0a46fSAndroid Build Coastguard Worker
WriteRawThumbnailStream(FPDF_PAGE page,const char * pdf_name,int page_num)862*3ac0a46fSAndroid Build Coastguard Worker void WriteRawThumbnailStream(FPDF_PAGE page,
863*3ac0a46fSAndroid Build Coastguard Worker const char* pdf_name,
864*3ac0a46fSAndroid Build Coastguard Worker int page_num) {
865*3ac0a46fSAndroid Build Coastguard Worker char filename[256];
866*3ac0a46fSAndroid Build Coastguard Worker if (!GetThumbnailFilename(filename, sizeof(filename), pdf_name, page_num,
867*3ac0a46fSAndroid Build Coastguard Worker ThumbnailDecodeType::kRawStream)) {
868*3ac0a46fSAndroid Build Coastguard Worker return;
869*3ac0a46fSAndroid Build Coastguard Worker }
870*3ac0a46fSAndroid Build Coastguard Worker
871*3ac0a46fSAndroid Build Coastguard Worker unsigned long raw_data_size = FPDFPage_GetRawThumbnailData(page, nullptr, 0u);
872*3ac0a46fSAndroid Build Coastguard Worker
873*3ac0a46fSAndroid Build Coastguard Worker // Only continue if there actually is a thumbnail for this page
874*3ac0a46fSAndroid Build Coastguard Worker if (raw_data_size == 0) {
875*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to get raw thumbnail data for page #%d.\n",
876*3ac0a46fSAndroid Build Coastguard Worker page_num + 1);
877*3ac0a46fSAndroid Build Coastguard Worker return;
878*3ac0a46fSAndroid Build Coastguard Worker }
879*3ac0a46fSAndroid Build Coastguard Worker
880*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> thumb_buf(raw_data_size);
881*3ac0a46fSAndroid Build Coastguard Worker if (FPDFPage_GetRawThumbnailData(page, thumb_buf.data(), raw_data_size) !=
882*3ac0a46fSAndroid Build Coastguard Worker raw_data_size) {
883*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to get raw thumbnail data for %s.\n", filename);
884*3ac0a46fSAndroid Build Coastguard Worker return;
885*3ac0a46fSAndroid Build Coastguard Worker }
886*3ac0a46fSAndroid Build Coastguard Worker
887*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(thumb_buf.data(), raw_data_size, filename, "raw thumbnail");
888*3ac0a46fSAndroid Build Coastguard Worker }
889*3ac0a46fSAndroid Build Coastguard Worker
WriteThumbnail(FPDF_PAGE page,const char * pdf_name,int page_num)890*3ac0a46fSAndroid Build Coastguard Worker void WriteThumbnail(FPDF_PAGE page, const char* pdf_name, int page_num) {
891*3ac0a46fSAndroid Build Coastguard Worker char filename[256];
892*3ac0a46fSAndroid Build Coastguard Worker if (!GetThumbnailFilename(filename, sizeof(filename), pdf_name, page_num,
893*3ac0a46fSAndroid Build Coastguard Worker ThumbnailDecodeType::kBitmap)) {
894*3ac0a46fSAndroid Build Coastguard Worker return;
895*3ac0a46fSAndroid Build Coastguard Worker }
896*3ac0a46fSAndroid Build Coastguard Worker
897*3ac0a46fSAndroid Build Coastguard Worker ScopedFPDFBitmap thumb_bitmap(FPDFPage_GetThumbnailAsBitmap(page));
898*3ac0a46fSAndroid Build Coastguard Worker if (!thumb_bitmap) {
899*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Thumbnail of page #%d has an empty bitmap.\n",
900*3ac0a46fSAndroid Build Coastguard Worker page_num + 1);
901*3ac0a46fSAndroid Build Coastguard Worker return;
902*3ac0a46fSAndroid Build Coastguard Worker }
903*3ac0a46fSAndroid Build Coastguard Worker
904*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint8_t> png_encoding =
905*3ac0a46fSAndroid Build Coastguard Worker EncodeBitmapToPng(std::move(thumb_bitmap));
906*3ac0a46fSAndroid Build Coastguard Worker if (png_encoding.empty()) {
907*3ac0a46fSAndroid Build Coastguard Worker fprintf(stderr, "Failed to convert thumbnail of page #%d to png.\n",
908*3ac0a46fSAndroid Build Coastguard Worker page_num + 1);
909*3ac0a46fSAndroid Build Coastguard Worker return;
910*3ac0a46fSAndroid Build Coastguard Worker }
911*3ac0a46fSAndroid Build Coastguard Worker
912*3ac0a46fSAndroid Build Coastguard Worker WriteBufferToFile(&png_encoding.front(), png_encoding.size(), filename,
913*3ac0a46fSAndroid Build Coastguard Worker "thumbnail");
914*3ac0a46fSAndroid Build Coastguard Worker }
915