Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/*
* Copyright (C) 2013-2021 Global Graphics Software Ltd. All rights reserved
*
* Simple sample application for object-based separations using the JawsMako APIs.
*/
#include <algorithm>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <deque>
#include <wctype.h>
#include <jawsmako/jawsmako.h>
#include <jawsmako/xpsoutput.h>
#include <jawsmako/pdfinput.h>
#include <jawsmako/ijpdsinput.h>
#include <jawsmako/separator.h>
#include <edl/edlversion.h>
#include <edl/iabort.h>
using namespace JawsMako;
using namespace EDL;
// Print usage
static void usage(const String &argv0)
{
std::wcerr << L"Usage: " << argv0 << L" [ -ver ] <source file> <output file>"; // required arguments
std::wcerr << L" [ .pdf|.xps|.pcl|.pxl ]"; // optional arguments for input (must be specified before all the other parameters)
// fallback file format if unable to be worked out from the input file name
std::wcerr << L" [ [-outputparams] parameter=value parameter=value ... ]"; // all the other parameters
std::wcerr << L" [ -inputparams parameter=value parameter=value ... ]" << std::endl;
std::wcerr << L" [ -makoinitparams parameter=value parameter=value ... ]" << std::endl;
std::wcerr << L"Where: " << std::endl;
std::wcerr << L" -ver Displays the Mako version number" << std::endl; // optional argument
std::wcerr << L" -makoinitparams Starts a list of mako intial parameters " << std::endl; // optional argument
std::wcerr << L" -inputparams Starts a list of input parameters " << std::endl; // optional argument
std::wcerr << L" -outputparams Starts a list of output parameters " << std::endl; // optional argument
std::wcerr << L"The -makoinitparams, -inputparams, and -outputparams series can be in any order " << std::endl; // optional argument
std::wcerr << L" but by default the first series is for the output" << std::endl; // optional argument
}
// Determine the associated format for a given path from the file extension
static eFileFormat formatFromPath(const String &path)
{
// Get the extension in lower case
if (path.size() < 3)
{
// Cannot determine the extension if there isn't one!
std::string message("Cannot determine file extension for path ");
message += StringToU8String(path).c_str();
throw std::length_error(message);
}
size_t extensionPosition = path.find_last_of('.');
if (extensionPosition != String::npos)
{
String extension = path.substr(extensionPosition);
std::transform(extension.begin(), extension.end(), extension.begin(), towlower);
if (extension == L".xps")
return eFFXPS;
else if (extension == L".pdf")
return eFFPDF;
else if (extension == L".svg")
return eFFSVG;
else if (extension == L".ps")
return eFFPS;
else if (extension == L".eps")
return eFFEPS;
else if (extension == L".pcl")
return eFFPCL5;
else if (extension == L".pxl")
return eFFPCLXL;
else if (extension == L".ijp")
return eFFIJPDS;
}
std::string message("Unsupported file type for path ");
message += StringToU8String(path).c_str();
throw std::invalid_argument(message);
}
void buildPropertiesMap (std::map<std::string, std::string> &props, std::deque<String> &paramList)
{
while (paramList.size () > 0)
{
// Split at the first equals sign
U8String keyValuePair = StringToU8String (String (paramList.front ()));
paramList.pop_front ();
U8String keyStr;
U8String valueStr;
size_t equalsPos = keyValuePair.find('=');
if (equalsPos == U8String::npos)
{
keyStr = keyValuePair;
valueStr = "";
}
else
{
keyStr = keyValuePair.substr(0, equalsPos);
valueStr = keyValuePair.substr(equalsPos + 1);
}
props [keyStr.c_str ()] = valueStr.c_str ();
}
}
void applyParameters (IInputPtr &input, std::deque<String> &paramList)
{
while (paramList.size () > 0)
{
// Split at the first equals sign
U8String keyValuePair = StringToU8String (String (paramList.front ()));
paramList.pop_front ();
EDLSysString keyStr;
EDLSysString valueStr;
size_t equalsPos = keyValuePair.find('=');
if (equalsPos == U8String::npos)
{
keyStr = keyValuePair;
valueStr = "";
}
else
{
keyStr = keyValuePair.substr(0, equalsPos);
valueStr = keyValuePair.substr(equalsPos + 1);
}
EDLSysString keyStrLower = keyStr;
std::transform (keyStrLower.begin (), keyStrLower.end (), keyStrLower.begin (), ::tolower);
if (keyStrLower == "inputpassword")
{
IPDFInputPtr pdfInput = obj2IPDFInput (input);
if (pdfInput)
pdfInput->setPassword (valueStr);
}
else
{
// Set the input parameter
input->setParameter (keyStr, valueStr);
}
}
}
void applyParameters (IOutputPtr &output, std::deque<String> &paramList)
{
while (paramList.size () > 0)
{
// Split at the first equals sign
U8String keyValuePair = StringToU8String (String (paramList.front ()));
paramList.pop_front ();
EDLSysString keyStr;
EDLSysString valueStr;
size_t equalsPos = keyValuePair.find('=');
if (equalsPos == U8String::npos)
{
keyStr = keyValuePair;
valueStr = "";
}
else
{
keyStr = keyValuePair.substr(0, equalsPos);
valueStr = keyValuePair.substr(equalsPos + 1);
}
// Set the output parameter
output->setParameter (keyStr, valueStr);
}
}
std::string trim(const std::string &s)
{
if (s.length () == 0)
return s;
auto start = s.begin();
while (start != s.end() && std::isspace(*start)) {
start++;
}
auto end = s.end();
do {
end--;
} while (std::distance(start, end) > 0 && std::isspace(*end));
return std::string(start, end + 1);
}
void expandArgFileToQueue (const char *argFilename, std::deque<String> &paramList)
{
std::string line;
std::ifstream infile (argFilename);
String str;
while (std::getline (infile, line))
{
line = trim (line);
if (line.length () > 0)
{
str = U8StringToString (U8String (line.c_str ()));
paramList.push_back (str);
}
}
}
#ifdef _WIN32
int wmain(int argc, wchar_t *argv[])
#else
int main(int argc, char *argv[])
#endif
{
try
{
String progName;
String paramStr;
String paramStrLower;
std::deque<String> expandedParams;
#ifdef _WIN32
progName = argv [0];
#else
progName = U8StringToString (U8String (argv [0]));
#endif
// See if there are any optional arguments that modify how the harness behaves
for (int i= 1; i < argc; i++)
{
#ifdef _WIN32
paramStr = argv [i];
#else
paramStr = U8StringToString (U8String (argv [i]));
#endif
if ((paramStr.length () > 1) && (paramStr [0] == '@'))
{
U8String argFilename = StringToU8String (paramStr);
expandArgFileToQueue (argFilename.c_str () + 1, expandedParams);
}
else
expandedParams.push_back (paramStr);
}
std::map<std::string, std::string> makoInitProps;
std::deque<String> makoInitParams;
std::deque<String> inputParams;
std::deque<String> outputParams;
std::deque<String> progParamList;
std::deque<String> *params = &outputParams;
while (expandedParams.size () > 0)
{
paramStr = expandedParams.front ();
expandedParams.pop_front ();
paramStrLower = paramStr;
std::transform (paramStrLower.begin (), paramStrLower.end (), paramStrLower.begin (), ::tolower);
// Look for optional arguments
if (paramStrLower.compare (L"-ver") == 0)
{
// Dump Mako version string
String verStr = EDLSysStringToEDLString (EDLProductNameWithVersion);
std::wcout << verStr << std::endl;
}
else if (progParamList.size () < 2)
{
/* not an option, it's a filename */
progParamList.push_back (paramStr);
}
else if ((progParamList.size () == 2) && (paramStr [0] == '.'))
{
/* it's the optional 3rd parameter which is the file extension override for the input file */
progParamList.push_back (paramStr);
}
else if (paramStrLower.compare (L"-makoinitparams") == 0)
{
params = &makoInitParams;
}
else if (paramStrLower.compare (L"-inputparams") == 0)
{
params = &inputParams;
}
else if (paramStrLower.compare (L"-outputparams") == 0)
{
params = &outputParams;
}
else if (paramStrLower [0] == '-')
{
// It starts with a - but we don't recognize it so it's an invalid option
std::wcerr << L"Unknown option : " << paramStr << std::endl;
usage (progName);
return 1;
}
else
{
String inputPassword = paramStrLower.substr (0, 14);
if (inputPassword.compare (L"inputpassword=") == 0)
{
inputParams.push_back (paramStr);
}
else
{
/* it's a parameter, it can't be a filename or an optional file extension override
* because we already handled it earlier
*/
params->push_back (paramStr);
}
}
}
// There should be at least two arguments; a source file and a destination file.
if (progParamList.size () < 2)
{
usage (progName);
return 1;
}
// Most JawsMako APIs can take UTF8 or Wide Character paths.
// To keep this cross-platform example simple, we'll use wchars in both cases.
String inputFilePath;
eFileFormat inputFileFormat;
String outputFilePath;
eFileFormat outputFileFormat;
/* First parameter is the input file path */
inputFilePath = progParamList.front ();
progParamList.pop_front ();
/* Second parameter is the output file path */
outputFilePath = progParamList.front ();
progParamList.pop_front ();
/* Optional 3rd parameter is the extension for the input file
* format
*/
if (progParamList.size () > 0)
{
inputFileFormat = formatFromPath (progParamList.front ());
progParamList.pop_front ();
}
else
{
inputFileFormat = formatFromPath (inputFilePath);
}
outputFileFormat = formatFromPath (outputFilePath);
buildPropertiesMap (makoInitProps, makoInitParams);
// Create our JawsMako instance.
// Currently only one instance is allowed at any one time.
IJawsMakoPtr jawsMako = IJawsMako::create("", "", CTemporaryStoreParameters(), makoInitProps);
IJawsMako::enableAllFeatures(jawsMako);
IAbortPtr abort = IAbort::create ();
IProgressTickPtr progressTick;
IProgressMonitorPtr progressMonitor = IProgressMonitor::create (progressTick, abort);
// We use the file extensions to determine formats unless it is specified otherwise
// by the first optional argument.
// Any combination of PDF, XPS, PCL5 or PCLXL input, and
// PDF, XPS, PCL5, PCLXL or PostScript output is supported.
// Declare our input and output pointers
IInputPtr input;
IOutputPtr output;
input = IInput::create(jawsMako, inputFileFormat, progressMonitor);
// Create our output and set optional parameters
output = IOutput::create(jawsMako, outputFileFormat, abort);
IIJPDSInputPtr ijpInput = obj2IIJPDSInput (input);
if (ijpInput)
{
size_t found = inputFilePath.rfind (L".");
if (std::string::npos != found)
{
EDLSysString resourceDir = StringToU8String (inputFilePath.substr (0, found));
ijpInput->setParameter ("ResourceDirectory", resourceDir);
}
}
IXPSOutputPtr xpsOutput = obj2IXPSOutput(output);
if (xpsOutput)
{
xpsOutput->setTargetColorSpace(IDOMColorSpacesRGB::create(jawsMako));
}
applyParameters (input, inputParams);
applyParameters (output, outputParams);
// Create the separator
ISeparatorPtr separator = ISeparator::create(jawsMako);
// A brush for the label. Let's make it black in DeviceGray
IDOMBrushPtr solidBrush = IDOMSolidColorBrush::create(jawsMako, IDOMColor::create(jawsMako, IDOMColorSpacesGray::create(jawsMako), 1.0f, 0.0f));
// Pick a font
IDOMFontPtr font;
uint32 fontIndex = 0;
font = jawsMako->findFont("Arial", fontIndex);
// Get the assembly from the input.
IDocumentAssemblyPtr assembly = input->open(inputFilePath);
// Get the document from the assembly
IDocumentPtr document = assembly->getDocument();
// Crate a new document for the output
IDocumentAssemblyPtr sepAssembly = IDocumentAssembly::create(jawsMako);
IDocumentPtr sepDocument = IDocument::create(jawsMako);
sepAssembly->appendDocument(sepDocument);
// Create an output writer
auto writer = IOutput::create(jawsMako, eFFPDF)->openWriter(sepAssembly, outputFilePath);
writer->beginDocument(sepDocument);
// For each page of the source document
for (uint32 pageIndex = 0; pageIndex < document->getNumPages(); pageIndex++)
{
std::wcout << "Page " << pageIndex + 1 << L":" << std::endl;
IPagePtr page = document->getPage(pageIndex);
separator->separate(page->getContent());
for (uint32 sepIndex = 0; sepIndex < separator->getNumSeparations(); sepIndex++)
{
IDOMFixedPagePtr sepContent;
U8String sepName;
separator->getSeparation(sepIndex, sepContent, sepName);
std::wcout << " Adding separation page for " << U8StringToString(sepName) << std::endl;
// Create the glyphs for the label
IDOMGlyphsPtr glyphs = IDOMGlyphs::create(jawsMako, U8StringToString(sepName), 24, FPoint(10.0, 30.0), solidBrush, font, fontIndex);
// Add to the page
sepContent->appendChild(glyphs);
IPagePtr sepPage = IPage::create(jawsMako);
sepPage->setContent(sepContent);
writer->writePage(sepPage);
}
}
// Write to the output
std::wcout << "Writing output file... " << std::endl;
writer->endDocument();
writer->finish();
}
catch (IError &e)
{
String errorFormatString = getEDLErrorString(e.getErrorCode());
std::wcerr << L"Exception thrown: " << e.getErrorDescription(errorFormatString) << std::endl;
#ifdef _WIN32
// On windows, the return code allows larger numbers, and we can return the error code
return e.getErrorCode();
#else
// On other platforms, the exit code is masked to the low 8 bits. So here we just return
// a fixed value.
return 1;
#endif
}
catch (std::exception &e)
{
std::wcerr << L"std::exception thrown: " << e.what() << std::endl;
return 1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment