blob: a93796d0b49e140d78bec8700cb718a3ab1a53a8 [file]
//========================================================================
//
// image-embedding.cc
// A test util to check ImageEmbeddingUtils::embed().
//
// This file is licensed under the GPLv2 or later
//
// Copyright (C) 2021 Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net.
// Copyright (C) 2022 by Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2026 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
//
//========================================================================
#include <config.h>
#include <cstdio>
#include <string>
#include "utils/parseargs.h"
#include "goo/GooString.h"
#include "Object.h"
#include "Dict.h"
#include "PDFDoc.h"
#include "PDFDocFactory.h"
#include "ImageEmbeddingUtils.h"
static int depth = 0;
static GooString colorSpace;
static GooString filter;
static bool smask = false;
static bool fail = false;
static bool printHelp = false;
static const ArgDesc argDesc[] = { { .arg = "-depth", .kind = argInt, .val = &depth, .size = 0, .usage = "XObject's property 'BitsPerComponent'" },
{ .arg = "-colorspace", .kind = argGooString, .val = &colorSpace, .size = 0, .usage = "XObject's property 'ColorSpace'" },
{ .arg = "-filter", .kind = argGooString, .val = &filter, .size = 0, .usage = "XObject's property 'Filter'" },
{ .arg = "-smask", .kind = argFlag, .val = &smask, .size = 0, .usage = "SMask should exist" },
{ .arg = "-fail", .kind = argFlag, .val = &fail, .size = 0, .usage = "the image embedding API is expected to fail" },
{ .arg = "-h", .kind = argFlag, .val = &printHelp, .size = 0, .usage = "print usage information" },
{ .arg = "-help", .kind = argFlag, .val = &printHelp, .size = 0, .usage = "print usage information" },
{ .arg = "--help", .kind = argFlag, .val = &printHelp, .size = 0, .usage = "print usage information" },
{ .arg = "-?", .kind = argFlag, .val = &printHelp, .size = 0, .usage = "print usage information" },
{} };
int main(int argc, char *argv[])
{
// Parse args.
const bool ok = parseArgs(argDesc, &argc, argv);
if (!ok || (argc != 3) || printHelp) {
printUsage(argv[0], "PDF-FILE IMAGE-FILE", argDesc);
return printHelp ? 0 : 1;
}
const GooString docPath(argv[1]);
const GooString imagePath(argv[2]);
auto doc = std::unique_ptr<PDFDoc>(PDFDocFactory().createPDFDoc(docPath));
if (!doc->isOk()) {
fprintf(stderr, "Error opening input PDF file.\n");
return 1;
}
// Embed an image.
Ref baseImageRef = ImageEmbeddingUtils::embed(doc->getXRef(), imagePath.toStr());
if (baseImageRef == Ref::INVALID()) {
if (fail) {
return 0;
}
fprintf(stderr, "ImageEmbeddingUtils::embed() failed.\n");
return 1;
}
// Save the updated PDF document.
// const GooString outputPathSuffix(".pdf");
// const GooString outputPath = GooString(&imagePath, &outputPathSuffix);
// doc->saveAs(&outputPath, writeForceRewrite);
// Check the base image.
Object baseImageObj = Object(baseImageRef).fetch(doc->getXRef());
Dict *baseImageDict = baseImageObj.streamGetDict();
if (std::string("XObject") != baseImageDict->lookup("Type").getName()) {
fprintf(stderr, "A problem with Type.\n");
return 1;
}
if (std::string("Image") != baseImageDict->lookup("Subtype").getName()) {
fprintf(stderr, "A problem with Subtype.\n");
return 1;
}
if (depth > 0) {
if (baseImageDict->lookup("BitsPerComponent").getInt() != depth) {
fprintf(stderr, "A problem with BitsPerComponent.\n");
return 1;
}
}
if (!colorSpace.toStr().empty()) {
if (colorSpace.compare(baseImageDict->lookup("ColorSpace").getName()) != 0) {
fprintf(stderr, "A problem with ColorSpace.\n");
return 1;
}
}
if (!filter.toStr().empty()) {
if (filter.compare(baseImageDict->lookup("Filter").getName()) != 0) {
fprintf(stderr, "A problem with Filter.\n");
return 1;
}
}
if (smask) {
Object maskObj = baseImageDict->lookup("SMask");
if (!maskObj.isStream()) {
fprintf(stderr, "A problem with SMask.\n");
return 1;
}
}
return 0;
}