#include "testing/helpers/write.h"
#include <limits.h>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "core/fxcrt/notreached.h"
#include "public/cpp/fpdf_scopers.h"
#include "public/fpdf_annot.h"
#include "public/fpdf_attachment.h"
#include "public/fpdf_edit.h"
#include "public/fpdf_thumbnail.h"
#include "testing/fx_string_testhelpers.h"
#include "testing/image_diff/image_diff_png.h"
#ifdef PDF_ENABLE_SKIA
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/encode/SkPngEncoder.h"
#endif
namespace {
bool CheckDimensions(int stride, int width, int height) { … }
const char* AnnotSubtypeToCString(FPDF_ANNOTATION_SUBTYPE subtype) { … }
void AppendFlagString(const char* flag, std::string* output) { … }
std::string AnnotFlagsToString(int flags) { … }
const char* PageObjectTypeToCString(int type) { … }
std::vector<uint8_t> EncodePng(pdfium::span<const uint8_t> input,
int width,
int height,
int stride,
int format) { … }
#ifdef _WIN32
int CALLBACK EnhMetaFileProc(HDC hdc,
HANDLETABLE* handle_table,
const ENHMETARECORD* record,
int objects_count,
LPARAM param) {
std::vector<const ENHMETARECORD*>& items =
*reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
items.push_back(record);
return 1;
}
#endif
std::string GeneratePageOutputFilename(const char* pdf_name,
int page_num,
const char* extension) { … }
std::string GenerateImageOutputFilename(const char* pdf_name,
int page_num,
int image_num,
const char* extension) { … }
}
std::string WritePpm(const char* pdf_name,
int num,
void* buffer_void,
int stride,
int width,
int height) { … }
void WriteText(FPDF_TEXTPAGE textpage, const char* pdf_name, int num) { … }
void WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) { … }
std::string WritePng(const char* pdf_name,
int num,
void* buffer,
int stride,
int width,
int height) { … }
#ifdef _WIN32
std::string WriteBmp(const char* pdf_name,
int num,
void* buffer,
int stride,
int width,
int height) {
if (!CheckDimensions(stride, width, height)) {
return std::string();
}
int out_len = stride * height;
if (out_len > INT_MAX / 3) {
return std::string();
}
std::string filename = GeneratePageOutputFilename(pdf_name, num, "bmp");
if (filename.empty()) {
return std::string();
}
FILE* fp = fopen(filename.c_str(), "wb");
if (!fp) {
return std::string();
}
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
BITMAPFILEHEADER file_header = {};
file_header.bfType = 0x4d42;
file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
file_header.bfOffBits = file_header.bfSize - out_len;
if (fwrite(&file_header, sizeof(file_header), 1, fp) != 1 ||
fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp) != 1 ||
fwrite(buffer, out_len, 1, fp) != 1) {
fprintf(stderr, "Failed to write to %s\n", filename.c_str());
}
fclose(fp);
return filename;
}
void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
std::string filename = GeneratePageOutputFilename(pdf_name, num, "emf");
if (filename.empty()) {
return;
}
HDC dc = CreateEnhMetaFileA(nullptr, filename.c_str(), nullptr, nullptr);
int width = static_cast<int>(FPDF_GetPageWidthF(page));
int height = static_cast<int>(FPDF_GetPageHeightF(page));
HRGN rgn = CreateRectRgn(0, 0, width, height);
SelectClipRgn(dc, rgn);
DeleteObject(rgn);
SelectObject(dc, GetStockObject(NULL_PEN));
SelectObject(dc, GetStockObject(WHITE_BRUSH));
Rectangle(dc, 0, 0, width + 1, height + 1);
FPDF_RenderPage(dc, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_PRINTING);
DeleteEnhMetaFile(CloseEnhMetaFile(dc));
}
void WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
std::string filename = GeneratePageOutputFilename(pdf_name, num, "ps");
if (filename.empty()) {
return;
}
FILE* fp = fopen(filename.c_str(), "wb");
if (!fp) {
return;
}
HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
int width = static_cast<int>(FPDF_GetPageWidthF(page));
int height = static_cast<int>(FPDF_GetPageHeightF(page));
FPDF_RenderPage(dc, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_PRINTING);
HENHMETAFILE emf = CloseEnhMetaFile(dc);
std::vector<const ENHMETARECORD*> items;
EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
for (const ENHMETARECORD* record : items) {
if (record->iType != EMR_GDICOMMENT) {
continue;
}
const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
const char* data = reinterpret_cast<const char*>(comment->Data);
uint16_t size = *reinterpret_cast<const uint16_t*>(data);
if (fwrite(data + sizeof(uint16_t), size, 1, fp) != 1) {
fprintf(stderr, "Failed to write to %s\n", filename.c_str());
break;
}
}
fclose(fp);
DeleteEnhMetaFile(emf);
}
#endif
#ifdef PDF_ENABLE_SKIA
std::unique_ptr<SkWStream> WriteToSkWStream(const std::string& pdf_name,
int num,
const std::string& extension) { … }
std::unique_ptr<SkWStream> WriteToSkWStream(const std::string& pdf_name,
int num,
const std::string& extension,
std::string& filename) { … }
std::string WriteSkp(const char* pdf_name, int num, const SkPicture& picture) { … }
#endif
enum class ThumbnailDecodeType { … };
bool GetThumbnailFilename(char* name_buf,
size_t name_buf_size,
const char* pdf_name,
int page_num,
ThumbnailDecodeType decode_type) { … }
void WriteBufferToFile(const void* buf,
size_t buflen,
const char* filename,
const char* filetype) { … }
std::vector<uint8_t> EncodeBitmapToPng(ScopedFPDFBitmap bitmap) { … }
void WriteAttachments(FPDF_DOCUMENT doc, const std::string& name) { … }
void WriteImages(FPDF_PAGE page, const char* pdf_name, int page_num) { … }
void WriteRenderedImages(FPDF_DOCUMENT doc,
FPDF_PAGE page,
const char* pdf_name,
int page_num) { … }
void WriteDecodedThumbnailStream(FPDF_PAGE page,
const char* pdf_name,
int page_num) { … }
void WriteRawThumbnailStream(FPDF_PAGE page,
const char* pdf_name,
int page_num) { … }
void WriteThumbnail(FPDF_PAGE page, const char* pdf_name, int page_num) { … }