Initial commit

This commit is contained in:
Andy Teijelo Pérez 2016-07-18 13:26:04 -04:00
commit 7e93fcbde4
3 changed files with 224 additions and 0 deletions

73
.gitignore vendored Normal file
View file

@ -0,0 +1,73 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

6
CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
project(pdfrender)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_compile_options(${PROJECT_NAME} PRIVATE -g -std=c++11)
target_link_libraries(${PROJECT_NAME} poppler-cpp pthread boost_program_options)

145
main.cpp Normal file
View file

@ -0,0 +1,145 @@
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include <future>
#include <regex>
#include <boost/program_options.hpp>
#include <poppler/cpp/poppler-page.h>
#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-page-renderer.h>
using namespace std;
using namespace poppler;
namespace po = boost::program_options;
int dpi = 75;
string inputpdf;
string output;
int threads = thread::hardware_concurrency();
void render_page(document *doc, int pageno, const string& fmt) {
page *p = doc->create_page(pageno);
page_renderer r;
image img = r.render_page(p);
vector<char> buf(1024);
int size = snprintf(&buf[0], buf.size(), fmt.c_str(), pageno);
if (size >= buf.size()) {
buf.reserve(size + 1);
snprintf(&buf[0], buf.size(), fmt.c_str(), pageno);
}
img.save(&buf[0], "JPEG", dpi);
}
void render_pages(document *doc, int first, int last, int step, const string& fmt) {
for (int p=first; p<=last; p+=step) {
render_page(doc, p, fmt);
}
}
bool validate_output(const string& output)
{
if (output.empty()) {
cout << "Output format must be specified" << endl;
return false;
}
regex fmt_regex(R"(%(?:0(\d+))?d)");
auto beg = sregex_iterator(output.begin(), output.end(), fmt_regex);
auto end = sregex_iterator();
int matches = distance(beg, end);
if (matches < 1) {
cout << "Output format must contain %d or %0<padding>d" << endl;
return false;
}
if (matches > 1) {
cout << "Output format must contain only one %d or %0<padding>d" << endl;
return false;
}
auto m = *beg;
if (!(m[1].str().empty())) {
int padding = 0;
try {
padding = stoi(m[1].str());
} catch (...) {
cout << "error: invalid interger value for padding: " << m[1].str() << endl;
return false;
}
if (padding > 10) {
cout << "error: padding is too large: " << m[1].str() << endl;
return false;
}
}
return true;
}
void parse_args(int argc, char *argv[])
{
po::options_description opts(string("Usage: ") + argv[0] + " [options] input.pdf\nOptions:");
opts.add_options()
("help,h", "prints this message")
("output,o", po::value<string>(&output),
"output format; must contain exactly one instance of %d or "
"%0<padding>d where <padding> is an integer for the page number; "
"padding, if used, will always be with zeros")
("dpi", po::value<int>(&dpi)->default_value(75),
"render at the specified dpi")
("threads,t", po::value<int>(&threads),
"use this many threads to render; by default, uses "
"the result of std::thread::hardware_concurrency()")
;
po::options_description hidden("Hidden");
hidden.add_options()
("input", po::value<string>(&inputpdf))
;
po::options_description allopts("");
allopts.add(opts).add(hidden);
po::positional_options_description pos;
pos.add("input", 1);
po::variables_map vm;
po::store(
po::command_line_parser(argc, argv)
.options(allopts)
.positional(pos)
.run(),
vm
);
po::notify(vm);
if (inputpdf.empty() || vm.count("help")) {
cout << opts;
exit(1);
}
if (!validate_output(output)) {
cout << "See " << argv[0] << " -h for more info" << endl;
exit(1);
}
}
int main(int argc, char *argv[])
{
parse_args(argc, argv);
document *doc = document::load_from_file(inputpdf);
vector<future<void>> futures;
int pagecount = doc->pages();
for (int i = 1; i <= threads; i++) {
futures.push_back(
async(launch::async,
render_pages, doc, i, pagecount, threads, output
)
);
}
}