Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

print: Use Poppler to render pages to print #366

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
apt-get update
apt-get upgrade -y
apt-get build-dep -y xdg-desktop-portal-gtk
apt-get install -y libpoppler-glib-dev

- uses: actions/checkout@v2

Expand Down
6 changes: 5 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,14 @@ if test x$enable_lockdown = xyes; then
fi
AM_CONDITIONAL([BUILD_LOCKDOWN],[test "$enable_lockdown" = "yes"])

PKG_CHECK_MODULES(GTK, [xdg-desktop-portal >= 1.5 glib-2.0 >= 2.44 gio-unix-2.0 gtk+-3.0 >= 3.14 gtk+-unix-print-3.0])
PKG_CHECK_MODULES(GTK, [xdg-desktop-portal >= 1.5 glib-2.0 >= 2.44 gio-unix-2.0 gtk+-3.0 >= 3.14 gtk+-unix-print-3.0 ])
ThierryHFR marked this conversation as resolved.
Show resolved Hide resolved
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)

PKG_CHECK_MODULES(POPPLER, [ gtk+-3.0 >= 3.14 gio-unix-2.0 poppler >= 0.16.7 poppler-glib >= 0.16.7 ])
AC_SUBST(POPPLER_CFLAGS)
AC_SUBST(POPPLER_LIBS)

PKG_CHECK_MODULES(GTK_X11, gtk+-x11-3.0,
have_gtk_x11=yes, have_gtk_x11=no)
if test "$have_gtk_x11" = "yes"; then
Expand Down
12 changes: 12 additions & 0 deletions src/Makefile.am.inc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ EXTRA_DIST += \

libexec_PROGRAMS = \
xdg-desktop-portal-gtk \
pdftoraw \
Copy link
Member

@TingPing TingPing Jan 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets ensure this never conflicts with anybody else, so maybe put it in a subdirectory, but xdg-desktop-portal-gtk already existed.

I think $libexec/xdg-desktop-portal-gtk-utils/pdftoraw is fine.

$(NULL)

xdg_desktop_portal_gtk_SOURCES = \
Expand Down Expand Up @@ -285,3 +286,14 @@ testappchooser_SOURCES = \
nodist_testappchooser_SOURCES = \
src/resources.c \
$(NULL)

pdftoraw_SOURCES = \
src/pdftoraw.c \
$(NULL)

pdftoraw_LDADD = $(BASE_LIBS) $(POPPLER_LIBS) -lm
pdftoraw_CFLAGS = $(BASE_CFLAGS) $(POPPLER_CFLAGS)
pdftoraw_CPPFLAGS = \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
$(NULL)
189 changes: 189 additions & 0 deletions src/pdftoraw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright (C) 2021 Thierry HUCHARD <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <gio/gio.h>
#include <poppler.h>
#include <gdk/gdk.h>

#define DPI 150.0

static struct option long_options[] = {
{"file", required_argument, 0, 'f' },
{"pages", no_argument, 0, 'p' },
{"test", no_argument, 0, 't' },
{"width", required_argument, 0, 'w' },
{"height", required_argument, 0, 'W' },
{"raw", required_argument, 0, 'r' },
{"help", no_argument, 0, 'h' },
{0, 0, 0, 0 }
};

static void
print_usage(void) {
printf("Usage:\tpdftoraw --filename=<filename> --raw=<num-page>\n");
printf("\tpdftoraw --filename=<filename> --pages\n");
printf("\tpdftoraw --filename=<filename> --width=<num-page>\n");
printf("\tpdftoraw --filename=<filename> --height=<num-page>\n");
printf("\tpdftoraw --help\n");
}

static int
pdf_number_pages_get(PopplerDocument *doc)
{
return poppler_document_get_n_pages(doc);
}

static unsigned char*
pdf_page_raw_get(PopplerDocument *doc,
int page_nr)
{
cairo_surface_t *s = NULL;
cairo_t *cr = NULL;
unsigned char *data = NULL;
GdkPixbuf *pix = NULL;
double width = 0;
double height = 0;
int w = 0;
int h = 0;

PopplerPage *page = poppler_document_get_page(doc, page_nr);
TingPing marked this conversation as resolved.
Show resolved Hide resolved
poppler_page_get_size(page, &width, &height);
width = DPI * width / 72.0;
TingPing marked this conversation as resolved.
Show resolved Hide resolved
height = DPI * height / 72.0;
w = (int)ceil(width);
h = (int)ceil(height);
s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
cr = cairo_create(s);
TingPing marked this conversation as resolved.
Show resolved Hide resolved
cairo_scale (cr, DPI/72.0, DPI/72.0);
cairo_save (cr);
poppler_page_render_for_printing(page, cr);
cairo_restore (cr);
pix = gdk_pixbuf_get_from_surface(s, 0, 0, w, h);
g_object_unref(page);
TingPing marked this conversation as resolved.
Show resolved Hide resolved
data = gdk_pixbuf_get_pixels (pix);
TingPing marked this conversation as resolved.
Show resolved Hide resolved
fwrite(data, 1, (w * h * 4), stdout);
return data;
}

static int
pdf_page_width_get(PopplerDocument *doc,
int page_nr)
{
double width = 0;
int w = 0;

PopplerPage *page = poppler_document_get_page(doc, page_nr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g_autoptr()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/pdftoraw.c:114:15: error: unknown type name 'PopplerPage_autoptr'
  114 |     g_autoptr(PopplerPage) page = NULL;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by 2c6c067

poppler_page_get_size(page, &width, NULL);
width = DPI * width / 72.0;
w = (int)ceil(width);
g_object_unref(page);
return w;
}

static int
pdf_page_height_get(PopplerDocument *doc,
int page_nr)
{
double height = 0;
int h = 0;

PopplerPage *page = poppler_document_get_page(doc, page_nr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g_autoptr()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/pdftoraw.c:114:15: error: unknown type name 'PopplerPage_autoptr'
  114 |     g_autoptr(PopplerPage) page = NULL;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by 2c6c067

poppler_page_get_size(page, NULL, &height);
height = DPI * height / 72.0;
h = (int)ceil(height);
g_object_unref(page);
return h;
}

int
main(int argc, char **argv)
{
PopplerDocument *doc = NULL;
GError *err = NULL;
ThierryHFR marked this conversation as resolved.
Show resolved Hide resolved
GFile *in = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

g_autoptr() all of these.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/pdftoraw.c:150:15: error: unknown type name 'PopplerDocument_autoptr'
  150 |     g_autoptr(PopplerDocument) doc = NULL;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For GFile, Fixed by 10e290f

Copy link
Member

@TingPing TingPing Jan 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. It is possible to define this with:

G_DEFINE_AUTOPTR_CLEANUP_FUNC (PopplerDocument, g_object_unref);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still leak some poppler objects, so this is a good idea throughout I think.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by 2c6c067

char *filename = NULL;
int long_index =0;
int page = 0;
int opt= 0;
int test = 0, raw = 0, npages = 0, width = 0, height = 0;

while ((opt = getopt_long(argc, argv,"f:tpw:W:r:h",
TingPing marked this conversation as resolved.
Show resolved Hide resolved
long_options, &long_index )) != -1) {
switch (opt) {
case 'f' :
filename = strdup(optarg);
break;
case 't' :
test = 1;
break;
case 'p' :
npages = 1;
break;
case 'w' : page = atoi(optarg);
width = 1;
break;
case 'W' : page = atoi(optarg);
height = 1;
break;
case 'r' : page = atoi(optarg);
raw = 1;
break;
default: print_usage();
exit(EXIT_FAILURE);
}
}
if (filename == NULL) {
print_usage();
exit(EXIT_FAILURE);
}
in = g_file_new_for_path(filename);
doc = poppler_document_new_from_gfile(in, NULL, NULL, &err);
if (err)
{
g_error_free(err);
g_object_unref(in);
exit(EXIT_FAILURE);
}

if (test == 1) {
printf("1");
}
else if (raw == 1) {
pdf_page_raw_get(doc, page);
}
else if (npages == 1) {
printf("%d", pdf_number_pages_get(doc));
}
else if (width == 1) {
printf("%d", pdf_page_width_get(doc, page));
}
else if (height == 1) {
printf("%d", pdf_page_height_get(doc, page));
}
else {
TingPing marked this conversation as resolved.
Show resolved Hide resolved
print_usage();
exit(EXIT_FAILURE);
}
g_object_unref(doc);
return 0;
}

Loading