xref: /aosp_15_r20/external/pdfium/samples/helpers/write.cc (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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