| // Copyright 2018 The PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "samples/pdfium_test_dump_helper.h" |
| |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <functional> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "public/cpp/fpdf_scopers.h" |
| #include "public/fpdf_transformpage.h" |
| #include "testing/test_support.h" |
| |
| using GetBoxInfoFunc = |
| std::function<bool(FPDF_PAGE, float*, float*, float*, float*)>; |
| |
| namespace { |
| |
| std::wstring ConvertToWString(const unsigned short* buf, |
| unsigned long buf_size) { |
| std::wstring result; |
| result.reserve(buf_size); |
| std::copy(buf, buf + buf_size, std::back_inserter(result)); |
| return result; |
| } |
| |
| void DumpBoxInfo(GetBoxInfoFunc func, |
| const char* box_type, |
| FPDF_PAGE page, |
| int page_idx) { |
| FS_RECTF rect; |
| bool ret = func(page, &rect.left, &rect.bottom, &rect.right, &rect.top); |
| if (!ret) { |
| printf("Page %d: No %s.\n", page_idx, box_type); |
| return; |
| } |
| printf("Page %d: %s: %0.2f %0.2f %0.2f %0.2f\n", page_idx, box_type, |
| rect.left, rect.bottom, rect.right, rect.top); |
| } |
| |
| } // namespace |
| |
| void DumpChildStructure(FPDF_STRUCTELEMENT child, int indent) { |
| static const size_t kBufSize = 1024; |
| unsigned short buf[kBufSize]; |
| unsigned long len = FPDF_StructElement_GetType(child, buf, kBufSize); |
| printf("%*s%ls", indent * 2, "", ConvertToWString(buf, len).c_str()); |
| |
| memset(buf, 0, sizeof(buf)); |
| len = FPDF_StructElement_GetTitle(child, buf, kBufSize); |
| if (len > 0) |
| printf(": '%ls'", ConvertToWString(buf, len).c_str()); |
| |
| memset(buf, 0, sizeof(buf)); |
| len = FPDF_StructElement_GetAltText(child, buf, kBufSize); |
| if (len > 0) |
| printf(" (%ls)", ConvertToWString(buf, len).c_str()); |
| printf("\n"); |
| |
| for (int i = 0; i < FPDF_StructElement_CountChildren(child); ++i) { |
| FPDF_STRUCTELEMENT sub_child = FPDF_StructElement_GetChildAtIndex(child, i); |
| // If the child is not an Element then this will return null. This can |
| // happen if the element is things like an object reference or a stream. |
| if (!sub_child) |
| continue; |
| |
| DumpChildStructure(sub_child, indent + 1); |
| } |
| } |
| |
| void DumpPageInfo(FPDF_PAGE page, int page_idx) { |
| DumpBoxInfo(&FPDFPage_GetMediaBox, "MediaBox", page, page_idx); |
| DumpBoxInfo(&FPDFPage_GetCropBox, "CropBox", page, page_idx); |
| DumpBoxInfo(&FPDFPage_GetBleedBox, "BleedBox", page, page_idx); |
| DumpBoxInfo(&FPDFPage_GetTrimBox, "TrimBox", page, page_idx); |
| DumpBoxInfo(&FPDFPage_GetArtBox, "ArtBox", page, page_idx); |
| } |
| |
| void DumpPageStructure(FPDF_PAGE page, int page_idx) { |
| ScopedFPDFStructTree tree(FPDF_StructTree_GetForPage(page)); |
| if (!tree) { |
| fprintf(stderr, "Failed to load struct tree for page %d\n", page_idx); |
| return; |
| } |
| |
| printf("Structure Tree for Page %d\n", page_idx); |
| for (int i = 0; i < FPDF_StructTree_CountChildren(tree.get()); ++i) { |
| FPDF_STRUCTELEMENT child = FPDF_StructTree_GetChildAtIndex(tree.get(), i); |
| if (!child) { |
| fprintf(stderr, "Failed to load child %d for page %d\n", i, page_idx); |
| continue; |
| } |
| DumpChildStructure(child, 0); |
| } |
| printf("\n\n"); |
| } |
| |
| void DumpMetaData(FPDF_DOCUMENT doc) { |
| constexpr const char* meta_tags[] = {"Title", "Author", "Subject", |
| "Keywords", "Creator", "Producer", |
| "CreationDate", "ModDate"}; |
| for (const char* meta_tag : meta_tags) { |
| char meta_buffer[4096]; |
| unsigned long len = |
| FPDF_GetMetaText(doc, meta_tag, meta_buffer, sizeof(meta_buffer)); |
| if (!len) |
| continue; |
| |
| auto* meta_string = reinterpret_cast<unsigned short*>(meta_buffer); |
| printf("%-12s = %ls (%lu bytes)\n", meta_tag, |
| GetPlatformWString(meta_string).c_str(), len); |
| } |
| } |