1 | //======================================================================== |
2 | // |
3 | // image-embedding.cc |
4 | // A test util to check ImageEmbeddingUtils::embed(). |
5 | // |
6 | // This file is licensed under the GPLv2 or later |
7 | // |
8 | // Copyright (C) 2021 Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net. |
9 | // Copyright (C) 2022 by Albert Astals Cid <aacid@kde.org> |
10 | // |
11 | //======================================================================== |
12 | |
13 | #include <config.h> |
14 | #include <cstdio> |
15 | #include <string> |
16 | |
17 | #include "utils/parseargs.h" |
18 | #include "goo/GooString.h" |
19 | #include "Object.h" |
20 | #include "Dict.h" |
21 | #include "PDFDoc.h" |
22 | #include "PDFDocFactory.h" |
23 | #include "ImageEmbeddingUtils.h" |
24 | |
25 | static int depth = 0; |
26 | static GooString colorSpace; |
27 | static GooString filter; |
28 | static bool smask = false; |
29 | static bool fail = false; |
30 | static bool printHelp = false; |
31 | |
32 | static const ArgDesc argDesc[] = { { .arg: "-depth" , .kind: argInt, .val: &depth, .size: 0, .usage: "XObject's property 'BitsPerComponent'" }, |
33 | { .arg: "-colorspace" , .kind: argGooString, .val: &colorSpace, .size: 0, .usage: "XObject's property 'ColorSpace'" }, |
34 | { .arg: "-filter" , .kind: argGooString, .val: &filter, .size: 0, .usage: "XObject's property 'Filter'" }, |
35 | { .arg: "-smask" , .kind: argFlag, .val: &smask, .size: 0, .usage: "SMask should exist" }, |
36 | { .arg: "-fail" , .kind: argFlag, .val: &fail, .size: 0, .usage: "the image embedding API is expected to fail" }, |
37 | { .arg: "-h" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
38 | { .arg: "-help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
39 | { .arg: "--help" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
40 | { .arg: "-?" , .kind: argFlag, .val: &printHelp, .size: 0, .usage: "print usage information" }, |
41 | {} }; |
42 | |
43 | int main(int argc, char *argv[]) |
44 | { |
45 | // Parse args. |
46 | const bool ok = parseArgs(args: argDesc, argc: &argc, argv); |
47 | if (!ok || (argc != 3) || printHelp) { |
48 | printUsage(program: argv[0], otherArgs: "PDF-FILE IMAGE-FILE" , args: argDesc); |
49 | return (printHelp) ? 0 : 1; |
50 | } |
51 | const GooString docPath(argv[1]); |
52 | const GooString imagePath(argv[2]); |
53 | |
54 | auto doc = std::unique_ptr<PDFDoc>(PDFDocFactory().createPDFDoc(uri: docPath)); |
55 | if (!doc->isOk()) { |
56 | fprintf(stderr, format: "Error opening input PDF file.\n" ); |
57 | return 1; |
58 | } |
59 | |
60 | // Embed an image. |
61 | Ref baseImageRef = ImageEmbeddingUtils::embed(xref: doc->getXRef(), imagePath: imagePath.toStr()); |
62 | if (baseImageRef == Ref::INVALID()) { |
63 | if (fail) { |
64 | return 0; |
65 | } else { |
66 | fprintf(stderr, format: "ImageEmbeddingUtils::embed() failed.\n" ); |
67 | return 1; |
68 | } |
69 | } |
70 | |
71 | // Save the updated PDF document. |
72 | // const GooString outputPathSuffix(".pdf"); |
73 | // const GooString outputPath = GooString(&imagePath, &outputPathSuffix); |
74 | // doc->saveAs(&outputPath, writeForceRewrite); |
75 | |
76 | // Check the base image. |
77 | Object baseImageObj = Object(baseImageRef).fetch(xref: doc->getXRef()); |
78 | Dict *baseImageDict = baseImageObj.streamGetDict(); |
79 | if (std::string("XObject" ) != baseImageDict->lookup(key: "Type" ).getName()) { |
80 | fprintf(stderr, format: "A problem with Type.\n" ); |
81 | return 1; |
82 | } |
83 | if (std::string("Image" ) != baseImageDict->lookup(key: "Subtype" ).getName()) { |
84 | fprintf(stderr, format: "A problem with Subtype.\n" ); |
85 | return 1; |
86 | } |
87 | if (depth > 0) { |
88 | if (baseImageDict->lookup(key: "BitsPerComponent" ).getInt() != depth) { |
89 | fprintf(stderr, format: "A problem with BitsPerComponent.\n" ); |
90 | return 1; |
91 | } |
92 | } |
93 | if (!colorSpace.toStr().empty()) { |
94 | if (colorSpace.cmp(sA: baseImageDict->lookup(key: "ColorSpace" ).getName()) != 0) { |
95 | fprintf(stderr, format: "A problem with ColorSpace.\n" ); |
96 | return 1; |
97 | } |
98 | } |
99 | if (!filter.toStr().empty()) { |
100 | if (filter.cmp(sA: baseImageDict->lookup(key: "Filter" ).getName()) != 0) { |
101 | fprintf(stderr, format: "A problem with Filter.\n" ); |
102 | return 1; |
103 | } |
104 | } |
105 | if (smask) { |
106 | Object maskObj = baseImageDict->lookup(key: "SMask" ); |
107 | if (!maskObj.isStream()) { |
108 | fprintf(stderr, format: "A problem with SMask.\n" ); |
109 | return 1; |
110 | } |
111 | } |
112 | return 0; |
113 | } |
114 | |