2
* Copyright (C) 2009 Canonical Ltd.
3
* Author: Robert Ancell <robert.ancell@canonical.com>
5
* This program is free software: you can redistribute it and/or modify it under
6
* the terms of the GNU General Public License as published by the Free Software
7
* Foundation, either version 3 of the License, or (at your option) any later
8
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
18
#include <gdk-pixbuf/gdk-pixbuf.h>
19
#include <cairo/cairo-pdf.h>
20
#include <cairo/cairo-ps.h>
36
static guint signals[LAST_SIGNAL] = { 0, };
42
gboolean needs_saving;
45
G_DEFINE_TYPE (Book, book, G_TYPE_OBJECT);
51
return g_object_new (BOOK_TYPE, NULL);
56
book_clear (Book *book)
59
for (iter = book->priv->pages; iter; iter = iter->next) {
60
Page *page = iter->data;
61
g_object_unref (page);
63
g_list_free (book->priv->pages);
64
book->priv->pages = NULL;
65
g_signal_emit (book, signals[CLEARED], 0);
70
page_changed_cb (Page *page, Book *book)
72
book_set_needs_saving (book, TRUE);
77
book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection scan_direction)
81
page = page_new (width, height, dpi, scan_direction);
82
g_signal_connect (page, "pixels-changed", G_CALLBACK (page_changed_cb), book);
83
g_signal_connect (page, "crop-changed", G_CALLBACK (page_changed_cb), book);
85
book->priv->pages = g_list_append (book->priv->pages, page);
87
g_signal_emit (book, signals[PAGE_ADDED], 0, page);
89
book_set_needs_saving (book, TRUE);
96
book_move_page (Book *book, Page *page, gint location)
98
book->priv->pages = g_list_remove (book->priv->pages, page);
99
book->priv->pages = g_list_insert (book->priv->pages, page, location);
101
g_signal_emit (book, signals[REORDERED], 0, page);
103
book_set_needs_saving (book, TRUE);
108
book_delete_page (Book *book, Page *page)
110
g_signal_handlers_disconnect_by_func (page, page_changed_cb, book);
112
g_signal_emit (book, signals[PAGE_REMOVED], 0, page);
114
book->priv->pages = g_list_remove (book->priv->pages, page);
115
g_object_unref (page);
117
book_set_needs_saving (book, TRUE);
122
book_get_n_pages (Book *book)
124
return g_list_length (book->priv->pages);
129
book_get_page (Book *book, gint page_number)
132
page_number = g_list_length (book->priv->pages) + page_number;
133
return g_list_nth_data (book->priv->pages, page_number);
138
book_get_page_index (Book *book, Page *page)
140
return g_list_index (book->priv->pages, page);
145
make_indexed_file (const gchar *uri, gint i)
147
gchar *basename, *suffix, *indexed_uri;
151
return g_file_new_for_uri (uri);
153
basename = g_path_get_basename (uri);
154
suffix = g_strrstr (basename, ".");
157
indexed_uri = g_strdup_printf ("%.*s-%d%s", (int) (strlen (uri) - strlen (suffix)), uri, i, suffix);
159
indexed_uri = g_strdup_printf ("%s-%d", uri, i);
162
file = g_file_new_for_uri (indexed_uri);
163
g_free (indexed_uri);
170
book_save_multi_file (Book *book, const gchar *type, GFile *file, GError **error)
173
gboolean result = TRUE;
177
uri = g_file_get_uri (file);
178
for (iter = book->priv->pages, i = 0; iter && result; iter = iter->next, i++) {
179
Page *page = iter->data;
182
file = make_indexed_file (uri, i);
183
result = page_save (page, type, file, error);
184
g_object_unref (file);
193
save_ps_pdf_surface (cairo_surface_t *surface, GdkPixbuf *image, gdouble dpi)
197
context = cairo_create (surface);
199
cairo_scale (context, 72.0 / dpi, 72.0 / dpi);
200
gdk_cairo_set_source_pixbuf (context, image, 0, 0);
201
cairo_pattern_set_filter (cairo_get_source (context), CAIRO_FILTER_BEST);
202
cairo_paint (context);
204
cairo_destroy (context);
208
static cairo_status_t
209
write_cairo_data (GFileOutputStream *stream, unsigned char *data, unsigned int length)
212
GError *error = NULL;
214
result = g_output_stream_write_all (G_OUTPUT_STREAM (stream), data, length, NULL, NULL, &error);
217
g_warning ("Error writing data: %s", error->message);
218
g_error_free (error);
221
return result ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR;
226
book_save_ps (Book *book, GFile *file, GError **error)
228
GFileOutputStream *stream;
230
cairo_surface_t *surface;
232
stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
236
surface = cairo_ps_surface_create_for_stream ((cairo_write_func_t) write_cairo_data,
239
for (iter = book->priv->pages; iter; iter = iter->next) {
240
Page *page = iter->data;
241
double width, height;
244
image = page_get_image (page, TRUE);
246
width = gdk_pixbuf_get_width (image) * 72.0 / page_get_dpi (page);
247
height = gdk_pixbuf_get_height (image) * 72.0 / page_get_dpi (page);
248
cairo_ps_surface_set_size (surface, width, height);
249
save_ps_pdf_surface (surface, image, page_get_dpi (page));
250
cairo_surface_show_page (surface);
252
g_object_unref (image);
255
cairo_surface_destroy (surface);
257
g_object_unref (stream);
267
GList *object_offsets;
268
GFileOutputStream *stream;
273
pdf_writer_new (GFileOutputStream *stream)
276
writer = g_malloc0 (sizeof (PDFWriter));
277
writer->stream = g_object_ref (stream);
283
pdf_writer_free (PDFWriter *writer)
285
g_object_unref (writer->stream);
286
g_list_free (writer->object_offsets);
292
pdf_write (PDFWriter *writer, const unsigned char *data, size_t length)
294
g_output_stream_write_all (G_OUTPUT_STREAM (writer->stream), data, length, NULL, NULL, NULL);
295
writer->offset += length;
300
pdf_printf (PDFWriter *writer, const char *format, ...)
305
va_start (args, format);
306
string = g_strdup_vprintf (format, args);
308
pdf_write (writer, (unsigned char *)string, strlen (string));
315
pdf_start_object (PDFWriter *writer)
318
writer->object_offsets = g_list_append (writer->object_offsets, GINT_TO_POINTER (writer->offset));
319
return writer->n_objects;
324
compress_zlib (guchar *data, size_t length, size_t *n_written)
329
out_data = g_malloc (sizeof (guchar) * length);
331
stream.zalloc = Z_NULL;
332
stream.zfree = Z_NULL;
333
stream.opaque = Z_NULL;
334
if (deflateInit (&stream, Z_BEST_COMPRESSION) != Z_OK)
337
stream.next_in = data;
338
stream.avail_in = length;
339
stream.next_out = out_data;
340
stream.avail_out = length;
341
while (stream.avail_in > 0) {
342
if (deflate (&stream, Z_FINISH) == Z_STREAM_ERROR)
346
deflateEnd (&stream);
348
if (stream.avail_in > 0) {
353
*n_written = length - stream.avail_out;
359
static void jpeg_init_cb (struct jpeg_compress_struct *info) {}
360
static boolean jpeg_empty_cb (struct jpeg_compress_struct *info) { return TRUE; }
361
static void jpeg_term_cb (struct jpeg_compress_struct *info) {}
364
compress_jpeg (GdkPixbuf *image, size_t *n_written)
366
struct jpeg_compress_struct info;
367
struct jpeg_error_mgr jerr;
368
struct jpeg_destination_mgr dest_mgr;
374
info.err = jpeg_std_error (&jerr);
375
jpeg_create_compress (&info);
377
pixels = gdk_pixbuf_get_pixels (image);
378
info.image_width = gdk_pixbuf_get_width (image);
379
info.image_height = gdk_pixbuf_get_height (image);
380
info.input_components = 3;
381
info.in_color_space = JCS_RGB; /* TODO: JCS_GRAYSCALE? */
382
jpeg_set_defaults (&info);
384
max_length = info.image_width * info.image_height * info.input_components;
385
data = g_malloc (sizeof (guchar) * max_length);
386
dest_mgr.next_output_byte = data;
387
dest_mgr.free_in_buffer = max_length;
388
dest_mgr.init_destination = jpeg_init_cb;
389
dest_mgr.empty_output_buffer = jpeg_empty_cb;
390
dest_mgr.term_destination = jpeg_term_cb;
391
info.dest = &dest_mgr;
393
jpeg_start_compress (&info, TRUE);
394
for (r = 0; r < info.image_height; r++) {
396
row[0] = pixels + r * gdk_pixbuf_get_rowstride (image);
397
jpeg_write_scanlines (&info, row, 1);
399
jpeg_finish_compress (&info);
400
*n_written = max_length - dest_mgr.free_in_buffer;
402
jpeg_destroy_compress (&info);
409
book_save_pdf (Book *book, GFile *file, GError **error)
411
GFileOutputStream *stream;
413
int catalog_number, pages_number, info_number;
417
stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
421
writer = pdf_writer_new (stream);
422
g_object_unref (stream);
425
pdf_printf (writer, "%%PDF-1.3\n");
428
catalog_number = pdf_start_object (writer);
429
pdf_printf (writer, "%d 0 obj\n", catalog_number);
430
pdf_printf (writer, "<<\n");
431
pdf_printf (writer, "/Type /Catalog\n");
432
pdf_printf (writer, "/Pages %d 0 R\n", catalog_number + 1);
433
pdf_printf (writer, ">>\n");
434
pdf_printf (writer, "endobj\n");
437
pdf_printf (writer, "\n");
438
pages_number = pdf_start_object (writer);
439
pdf_printf (writer, "%d 0 obj\n", pages_number);
440
pdf_printf (writer, "<<\n");
441
pdf_printf (writer, "/Type /Pages\n");
442
pdf_printf (writer, "/Kids [");
443
for (i = 0; i < book_get_n_pages (book); i++) {
444
pdf_printf (writer, " %d 0 R", pages_number + 1 + (i*3));
446
pdf_printf (writer, " ]\n");
447
pdf_printf (writer, "/Count %d\n", book_get_n_pages (book));
448
pdf_printf (writer, ">>\n");
449
pdf_printf (writer, "endobj\n");
451
for (i = 0; i < book_get_n_pages (book); i++) {
452
int number, width, height, depth;
453
size_t data_length, compressed_length;
456
guchar *pixels, *data, *compressed_data;
458
const gchar *color_space, *filter = NULL;
459
float page_width, page_height;
461
page = book_get_page (book, i);
462
image = page_get_image (page, TRUE);
463
width = gdk_pixbuf_get_width (image);
464
height = gdk_pixbuf_get_height (image);
465
pixels = gdk_pixbuf_get_pixels (image);
466
page_width = width * 72. / page_get_dpi (page);
467
page_height = height * 72. / page_get_dpi (page);
469
if (page_is_color (page)) {
473
color_space = "DeviceRGB";
474
data_length = height * width * 3 + 1;
475
data = g_malloc (sizeof (guchar) * data_length);
476
for (row = 0; row < height; row++) {
478
guchar *in_line, *out_line;
480
in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
481
out_line = data + row * width * 3;
482
for (x = 0; x < width; x++) {
483
guchar *in_p = in_line + x*3;
484
guchar *out_p = out_line + x*3;
492
else if (page_get_depth (page) == 2) {
493
int row, shift_count = 6;
497
color_space = "DeviceGray";
498
data_length = height * ((width * 2 + 7) / 8);
499
data = g_malloc (sizeof (guchar) * data_length);
502
for (row = 0; row < height; row++) {
506
/* Pad to the next line */
507
if (shift_count != 6) {
513
in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
514
for (x = 0; x < width; x++) {
515
guchar *in_p = in_line + x*3;
517
write_ptr[0] |= 3 << shift_count;
518
else if (in_p[0] >= 128)
519
write_ptr[0] |= 2 << shift_count;
520
else if (in_p[0] >= 64)
521
write_ptr[0] |= 1 << shift_count;
522
if (shift_count == 0) {
532
else if (page_get_depth (page) == 1) {
533
int row, mask = 0x80;
537
color_space = "DeviceGray";
538
data_length = height * ((width + 7) / 8);
539
data = g_malloc (sizeof (guchar) * data_length);
542
for (row = 0; row < height; row++) {
546
/* Pad to the next line */
553
in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
554
for (x = 0; x < width; x++) {
555
guchar *in_p = in_line + x*3;
557
write_ptr[0] |= mask;
571
color_space = "DeviceGray";
572
data_length = height * width + 1;
573
data = g_malloc (sizeof (guchar) * data_length);
574
for (row = 0; row < height; row++) {
576
guchar *in_line, *out_line;
578
in_line = pixels + row * gdk_pixbuf_get_rowstride (image);
579
out_line = data + row * width;
580
for (x = 0; x < width; x++) {
581
guchar *in_p = in_line + x*3;
582
guchar *out_p = out_line + x;
590
compressed_data = compress_zlib (data, data_length, &compressed_length);
591
if (compressed_data) {
592
/* Try if JPEG compression is better */
597
jpeg_data = compress_jpeg (image, &jpeg_length);
598
if (jpeg_length < compressed_length) {
599
filter = "DCTDecode";
601
g_free (compressed_data);
603
data_length = jpeg_length;
608
filter = "FlateDecode";
610
data = compressed_data;
611
data_length = compressed_length;
616
pdf_printf (writer, "\n");
617
number = pdf_start_object (writer);
618
pdf_printf (writer, "%d 0 obj\n", number);
619
pdf_printf (writer, "<<\n");
620
pdf_printf (writer, "/Type /Page\n");
621
pdf_printf (writer, "/Parent %d 0 R\n", pages_number);
622
pdf_printf (writer, "/Resources << /XObject << /Im%d %d 0 R >> >>\n", i, number+1);
623
pdf_printf (writer, "/MediaBox [ 0 0 %.2f %.2f ]\n", page_width, page_height);
624
pdf_printf (writer, "/Contents %d 0 R\n", number+2);
625
pdf_printf (writer, ">>\n");
626
pdf_printf (writer, "endobj\n");
629
pdf_printf (writer, "\n");
630
number = pdf_start_object (writer);
631
pdf_printf (writer, "%d 0 obj\n", number);
632
pdf_printf (writer, "<<\n");
633
pdf_printf (writer, "/Type /XObject\n");
634
pdf_printf (writer, "/Subtype /Image\n");
635
pdf_printf (writer, "/Width %d\n", width);
636
pdf_printf (writer, "/Height %d\n", height);
637
pdf_printf (writer, "/ColorSpace /%s\n", color_space);
638
pdf_printf (writer, "/BitsPerComponent %d\n", depth);
639
pdf_printf (writer, "/Length %d\n", data_length);
641
pdf_printf (writer, "/Filter /%s\n", filter);
642
pdf_printf (writer, ">>\n");
643
pdf_printf (writer, "stream\n");
644
pdf_write (writer, data, data_length);
646
pdf_printf (writer, "\n");
647
pdf_printf (writer, "endstream\n");
648
pdf_printf (writer, "endobj\n");
651
command = g_strdup_printf ("q\n"
654
"Q", page_width, page_height, i);
655
pdf_printf (writer, "\n");
656
number = pdf_start_object (writer);
657
pdf_printf (writer, "%d 0 obj\n", number);
658
pdf_printf (writer, "<<\n");
659
pdf_printf (writer, "/Length %d\n", strlen (command) + 1);
660
pdf_printf (writer, ">>\n");
661
pdf_printf (writer, "stream\n");
662
pdf_write (writer, (unsigned char *)command, strlen (command));
663
pdf_printf (writer, "\n");
664
pdf_printf (writer, "endstream\n");
665
pdf_printf (writer, "endobj\n");
668
g_object_unref (image);
672
pdf_printf (writer, "\n");
673
info_number = pdf_start_object (writer);
674
pdf_printf (writer, "%d 0 obj\n", info_number);
675
pdf_printf (writer, "<<\n");
676
pdf_printf (writer, "/Creator (Simple Scan " VERSION ")\n");
677
pdf_printf (writer, ">>\n");
678
pdf_printf (writer, "endobj\n");
680
/* Cross-reference table */
681
xref_offset = writer->offset;
682
pdf_printf (writer, "xref\n");
683
pdf_printf (writer, "1 %d\n", writer->n_objects);
685
for (link = writer->object_offsets; link != NULL; link = link->next) {
686
int offset = GPOINTER_TO_INT (link->data);
687
pdf_printf (writer, "%010d 0000 n\n", offset);
691
pdf_printf (writer, "trailer\n");
692
pdf_printf (writer, "<<\n");
693
pdf_printf (writer, "/Size %d\n", writer->n_objects);
694
pdf_printf (writer, "/Info %d 0 R\n", info_number);
695
pdf_printf (writer, "/Root %d 0 R\n", catalog_number);
696
pdf_printf (writer, ">>\n");
697
pdf_printf (writer, "startxref\n");
698
pdf_printf (writer, "%d\n", xref_offset);
699
pdf_printf (writer, "%%%%EOF\n");
701
pdf_writer_free (writer);
708
book_save (Book *book, const gchar *type, GFile *file, GError **error)
710
gboolean result = FALSE;
712
if (strcmp (type, "jpeg") == 0)
713
result = book_save_multi_file (book, "jpeg", file, error);
714
else if (strcmp (type, "png") == 0)
715
result = book_save_multi_file (book, "png", file, error);
716
else if (strcmp (type, "tiff") == 0)
717
result = book_save_multi_file (book, "tiff", file, error);
718
else if (strcmp (type, "ps") == 0)
719
result = book_save_ps (book, file, error);
720
else if (strcmp (type, "pdf") == 0)
721
result = book_save_pdf (book, file, error);
728
book_set_needs_saving (Book *book, gboolean needs_saving)
730
gboolean needed_saving = book->priv->needs_saving;
731
book->priv->needs_saving = needs_saving;
732
if (needed_saving != needs_saving)
733
g_object_notify (G_OBJECT (book), "needs-saving");
738
book_get_needs_saving (Book *book)
740
return book->priv->needs_saving;
745
book_set_property (GObject *object,
752
self = BOOK (object);
755
case PROP_NEEDS_SAVING:
756
book_set_needs_saving (self, g_value_get_boolean (value));
759
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
766
book_get_property (GObject *object,
773
self = BOOK (object);
776
case PROP_NEEDS_SAVING:
777
g_value_set_boolean (value, book_get_needs_saving (self));
780
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
787
book_finalize (GObject *object)
789
Book *book = BOOK (object);
791
G_OBJECT_CLASS (book_parent_class)->finalize (object);
796
book_class_init (BookClass *klass)
798
GObjectClass *object_class = G_OBJECT_CLASS (klass);
800
object_class->get_property = book_get_property;
801
object_class->set_property = book_set_property;
802
object_class->finalize = book_finalize;
804
g_object_class_install_property (object_class,
806
g_param_spec_boolean ("needs-saving",
808
"TRUE if this book needs saving",
812
signals[PAGE_ADDED] =
813
g_signal_new ("page-added",
814
G_TYPE_FROM_CLASS (klass),
816
G_STRUCT_OFFSET (BookClass, page_added),
818
g_cclosure_marshal_VOID__OBJECT,
819
G_TYPE_NONE, 1, page_get_type ());
820
signals[PAGE_REMOVED] =
821
g_signal_new ("page-removed",
822
G_TYPE_FROM_CLASS (klass),
824
G_STRUCT_OFFSET (BookClass, page_removed),
826
g_cclosure_marshal_VOID__OBJECT,
827
G_TYPE_NONE, 1, page_get_type ());
829
g_signal_new ("reordered",
830
G_TYPE_FROM_CLASS (klass),
832
G_STRUCT_OFFSET (BookClass, reordered),
834
g_cclosure_marshal_VOID__VOID,
837
g_signal_new ("cleared",
838
G_TYPE_FROM_CLASS (klass),
840
G_STRUCT_OFFSET (BookClass, cleared),
842
g_cclosure_marshal_VOID__VOID,
845
g_type_class_add_private (klass, sizeof (BookPrivate));
850
book_init (Book *book)
852
book->priv = G_TYPE_INSTANCE_GET_PRIVATE (book, BOOK_TYPE, BookPrivate);