~ubuntu-branches/ubuntu/precise/simple-scan/precise

« back to all changes in this revision

Viewing changes to .pc/03-blank_pdf.patch/src/book.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-11-03 15:20:08 UTC
  • mfrom: (1.1.24 upstream)
  • Revision ID: james.westby@ubuntu.com-20101103152008-kb8f4qzvzkfnocbq
Tags: 2.32.0.1-0ubuntu1
* New upstream release
* debian/patches/02-render_bug.patch:
* debian/patches/03-blank_pdf.patch:
* debian/patches/04-crop-area.patch:
* debian/patches/05-brother3-grayscale.patch:
  - Applied upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2009 Canonical Ltd.
3
 
 * Author: Robert Ancell <robert.ancell@canonical.com>
4
 
 * 
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
9
 
 * license.
10
 
 */
11
 
 
12
 
#include <stdio.h>
13
 
#include <string.h>
14
 
#include <math.h>
15
 
#include <zlib.h>
16
 
#include <jpeglib.h>
17
 
#include <gdk/gdk.h>
18
 
#include <gdk-pixbuf/gdk-pixbuf.h>
19
 
#include <cairo/cairo-pdf.h>
20
 
#include <cairo/cairo-ps.h>
21
 
 
22
 
#include "book.h"
23
 
 
24
 
enum {
25
 
    PROP_0,
26
 
    PROP_NEEDS_SAVING
27
 
};
28
 
 
29
 
enum {
30
 
    PAGE_ADDED,
31
 
    PAGE_REMOVED,
32
 
    REORDERED,
33
 
    CLEARED,
34
 
    LAST_SIGNAL
35
 
};
36
 
static guint signals[LAST_SIGNAL] = { 0, };
37
 
 
38
 
struct BookPrivate
39
 
{
40
 
    GList *pages;
41
 
  
42
 
    gboolean needs_saving;
43
 
};
44
 
 
45
 
G_DEFINE_TYPE (Book, book, G_TYPE_OBJECT);
46
 
 
47
 
 
48
 
Book *
49
 
book_new ()
50
 
{
51
 
    return g_object_new (BOOK_TYPE, NULL);
52
 
}
53
 
 
54
 
 
55
 
void
56
 
book_clear (Book *book)
57
 
{
58
 
    GList *iter;
59
 
    for (iter = book->priv->pages; iter; iter = iter->next) {
60
 
        Page *page = iter->data;
61
 
        g_object_unref (page);
62
 
    }
63
 
    g_list_free (book->priv->pages);
64
 
    book->priv->pages = NULL;
65
 
    g_signal_emit (book, signals[CLEARED], 0);
66
 
}
67
 
 
68
 
 
69
 
static void
70
 
page_changed_cb (Page *page, Book *book)
71
 
{
72
 
    book_set_needs_saving (book, TRUE);
73
 
}
74
 
 
75
 
 
76
 
Page *
77
 
book_append_page (Book *book, gint width, gint height, gint dpi, ScanDirection scan_direction)
78
 
{
79
 
    Page *page;
80
 
 
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);
84
 
 
85
 
    book->priv->pages = g_list_append (book->priv->pages, page);
86
 
 
87
 
    g_signal_emit (book, signals[PAGE_ADDED], 0, page);
88
 
  
89
 
    book_set_needs_saving (book, TRUE);
90
 
 
91
 
    return page;
92
 
}
93
 
 
94
 
 
95
 
void
96
 
book_move_page (Book *book, Page *page, gint location)
97
 
{
98
 
    book->priv->pages = g_list_remove (book->priv->pages, page);
99
 
    book->priv->pages = g_list_insert (book->priv->pages, page, location);
100
 
 
101
 
    g_signal_emit (book, signals[REORDERED], 0, page);
102
 
 
103
 
    book_set_needs_saving (book, TRUE);
104
 
}
105
 
 
106
 
 
107
 
void
108
 
book_delete_page (Book *book, Page *page)
109
 
{
110
 
    g_signal_handlers_disconnect_by_func (page, page_changed_cb, book);
111
 
 
112
 
    g_signal_emit (book, signals[PAGE_REMOVED], 0, page);
113
 
 
114
 
    book->priv->pages = g_list_remove (book->priv->pages, page);
115
 
    g_object_unref (page);
116
 
 
117
 
    book_set_needs_saving (book, TRUE);
118
 
}
119
 
 
120
 
 
121
 
gint
122
 
book_get_n_pages (Book *book)
123
 
{
124
 
    return g_list_length (book->priv->pages);    
125
 
}
126
 
 
127
 
 
128
 
Page *
129
 
book_get_page (Book *book, gint page_number)
130
 
{
131
 
    if (page_number < 0)
132
 
        page_number = g_list_length (book->priv->pages) + page_number;
133
 
    return g_list_nth_data (book->priv->pages, page_number);
134
 
}
135
 
 
136
 
 
137
 
gint
138
 
book_get_page_index (Book *book, Page *page)
139
 
{
140
 
     return g_list_index (book->priv->pages, page);
141
 
}
142
 
 
143
 
 
144
 
static GFile *
145
 
make_indexed_file (const gchar *uri, gint i)
146
 
{
147
 
    gchar *basename, *suffix, *indexed_uri;
148
 
    GFile *file;
149
 
 
150
 
    if (i == 0)
151
 
        return g_file_new_for_uri (uri);
152
 
 
153
 
    basename = g_path_get_basename (uri);
154
 
    suffix = g_strrstr (basename, ".");
155
 
 
156
 
    if (suffix)
157
 
        indexed_uri = g_strdup_printf ("%.*s-%d%s", (int) (strlen (uri) - strlen (suffix)), uri, i, suffix);
158
 
    else
159
 
        indexed_uri = g_strdup_printf ("%s-%d", uri, i);
160
 
    g_free (basename);
161
 
 
162
 
    file = g_file_new_for_uri (indexed_uri);
163
 
    g_free (indexed_uri);
164
 
 
165
 
    return file;
166
 
}
167
 
 
168
 
 
169
 
static gboolean
170
 
book_save_multi_file (Book *book, const gchar *type, GFile *file, GError **error)
171
 
{
172
 
    GList *iter;
173
 
    gboolean result = TRUE;
174
 
    gint i;
175
 
    gchar *uri;
176
 
 
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;
180
 
        GFile *file;
181
 
 
182
 
        file = make_indexed_file (uri, i);
183
 
        result = page_save (page, type, file, error);
184
 
        g_object_unref (file);
185
 
    }
186
 
    g_free (uri);
187
 
   
188
 
    return result;
189
 
}
190
 
 
191
 
 
192
 
static void
193
 
save_ps_pdf_surface (cairo_surface_t *surface, GdkPixbuf *image, gdouble dpi)
194
 
{
195
 
    cairo_t *context;
196
 
    
197
 
    context = cairo_create (surface);
198
 
 
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);
203
 
 
204
 
    cairo_destroy (context);
205
 
}
206
 
 
207
 
 
208
 
static cairo_status_t
209
 
write_cairo_data (GFileOutputStream *stream, unsigned char *data, unsigned int length)
210
 
{
211
 
    gboolean result;
212
 
    GError *error = NULL;
213
 
 
214
 
    result = g_output_stream_write_all (G_OUTPUT_STREAM (stream), data, length, NULL, NULL, &error);
215
 
    
216
 
    if (error) {
217
 
        g_warning ("Error writing data: %s", error->message);
218
 
        g_error_free (error);
219
 
    }
220
 
 
221
 
    return result ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR;
222
 
}
223
 
 
224
 
 
225
 
static gboolean
226
 
book_save_ps (Book *book, GFile *file, GError **error)
227
 
{
228
 
    GFileOutputStream *stream;
229
 
    GList *iter;
230
 
    cairo_surface_t *surface;
231
 
 
232
 
    stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
233
 
    if (!stream)
234
 
        return FALSE;
235
 
 
236
 
    surface = cairo_ps_surface_create_for_stream ((cairo_write_func_t) write_cairo_data,
237
 
                                                  stream, 0, 0);
238
 
 
239
 
    for (iter = book->priv->pages; iter; iter = iter->next) {
240
 
        Page *page = iter->data;
241
 
        double width, height;
242
 
        GdkPixbuf *image;
243
 
 
244
 
        image = page_get_image (page, TRUE);
245
 
 
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);
251
 
        
252
 
        g_object_unref (image);
253
 
    }
254
 
 
255
 
    cairo_surface_destroy (surface);
256
 
 
257
 
    g_object_unref (stream);
258
 
 
259
 
    return TRUE;
260
 
}
261
 
 
262
 
 
263
 
typedef struct
264
 
{
265
 
    int offset;
266
 
    int n_objects;
267
 
    GList *object_offsets;
268
 
    GFileOutputStream *stream;
269
 
} PDFWriter;
270
 
 
271
 
 
272
 
static PDFWriter *
273
 
pdf_writer_new (GFileOutputStream *stream)
274
 
{
275
 
    PDFWriter *writer;
276
 
    writer = g_malloc0 (sizeof (PDFWriter));
277
 
    writer->stream = g_object_ref (stream);
278
 
    return writer;
279
 
}
280
 
 
281
 
 
282
 
static void
283
 
pdf_writer_free (PDFWriter *writer)
284
 
{
285
 
    g_object_unref (writer->stream);
286
 
    g_list_free (writer->object_offsets);
287
 
    g_free (writer);
288
 
}
289
 
 
290
 
 
291
 
static void
292
 
pdf_write (PDFWriter *writer, const unsigned char *data, size_t length)
293
 
{
294
 
    g_output_stream_write_all (G_OUTPUT_STREAM (writer->stream), data, length, NULL, NULL, NULL);
295
 
    writer->offset += length;
296
 
}
297
 
 
298
 
 
299
 
static void
300
 
pdf_printf (PDFWriter *writer, const char *format, ...)
301
 
{
302
 
    va_list args;
303
 
    gchar *string;
304
 
 
305
 
    va_start (args, format);
306
 
    string = g_strdup_vprintf (format, args);
307
 
    va_end (args);
308
 
    pdf_write (writer, (unsigned char *)string, strlen (string));
309
 
 
310
 
    g_free (string);
311
 
}
312
 
 
313
 
 
314
 
static int
315
 
pdf_start_object (PDFWriter *writer)
316
 
{
317
 
    writer->n_objects++;
318
 
    writer->object_offsets = g_list_append (writer->object_offsets, GINT_TO_POINTER (writer->offset));
319
 
    return writer->n_objects;
320
 
}
321
 
 
322
 
 
323
 
static guchar *
324
 
compress_zlib (guchar *data, size_t length, size_t *n_written)
325
 
{
326
 
    z_stream stream;
327
 
    guchar *out_data;
328
 
 
329
 
    out_data = g_malloc (sizeof (guchar) * length);
330
 
 
331
 
    stream.zalloc = Z_NULL;
332
 
    stream.zfree = Z_NULL;
333
 
    stream.opaque = Z_NULL;
334
 
    if (deflateInit (&stream, Z_BEST_COMPRESSION) != Z_OK)
335
 
        return NULL;
336
 
 
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)
343
 
            break;
344
 
    }
345
 
 
346
 
    deflateEnd (&stream);
347
 
 
348
 
    if (stream.avail_in > 0) {
349
 
        g_free (out_data);
350
 
        return NULL;
351
 
    }
352
 
 
353
 
    *n_written = length - stream.avail_out;
354
 
 
355
 
    return out_data;
356
 
}
357
 
 
358
 
 
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) {}
362
 
 
363
 
static guchar *
364
 
compress_jpeg (GdkPixbuf *image, size_t *n_written)
365
 
{
366
 
    struct jpeg_compress_struct info;
367
 
    struct jpeg_error_mgr jerr;
368
 
    struct jpeg_destination_mgr dest_mgr;
369
 
    int r;
370
 
    guchar *pixels;
371
 
    guchar *data;
372
 
    size_t max_length;
373
 
 
374
 
    info.err = jpeg_std_error (&jerr);
375
 
    jpeg_create_compress (&info);
376
 
 
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);
383
 
 
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;
392
 
 
393
 
    jpeg_start_compress (&info, TRUE);
394
 
    for (r = 0; r < info.image_height; r++) {
395
 
        JSAMPROW row[1];
396
 
        row[0] = pixels + r * gdk_pixbuf_get_rowstride (image);
397
 
        jpeg_write_scanlines (&info, row, 1);
398
 
    }
399
 
    jpeg_finish_compress (&info);
400
 
    *n_written = max_length - dest_mgr.free_in_buffer;
401
 
 
402
 
    jpeg_destroy_compress (&info);
403
 
 
404
 
    return data;
405
 
}
406
 
 
407
 
 
408
 
static gboolean
409
 
book_save_pdf (Book *book, GFile *file, GError **error)
410
 
{
411
 
    GFileOutputStream *stream;
412
 
    PDFWriter *writer;
413
 
    int catalog_number, pages_number, info_number;
414
 
    int xref_offset;
415
 
    int i;
416
 
 
417
 
    stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error);
418
 
    if (!stream)
419
 
        return FALSE;
420
 
 
421
 
    writer = pdf_writer_new (stream);
422
 
    g_object_unref (stream);
423
 
 
424
 
    /* Header */
425
 
    pdf_printf (writer, "%%PDF-1.3\n");
426
 
  
427
 
    /* Catalog */
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");
435
 
 
436
 
    /* Pages */
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));
445
 
    }
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");
450
 
 
451
 
    for (i = 0; i < book_get_n_pages (book); i++) {
452
 
        int number, width, height, depth;
453
 
        size_t data_length, compressed_length;
454
 
        Page *page;
455
 
        GdkPixbuf *image;
456
 
        guchar *pixels, *data, *compressed_data;
457
 
        gchar *command;
458
 
        const gchar *color_space, *filter = NULL;
459
 
        float page_width, page_height;
460
 
 
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);
468
 
 
469
 
        if (page_is_color (page)) {
470
 
            int row;
471
 
 
472
 
            depth = 8;
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++) {
477
 
                int x;
478
 
                guchar *in_line, *out_line;
479
 
 
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;
485
 
 
486
 
                    out_p[0] = in_p[0];
487
 
                    out_p[1] = in_p[1];
488
 
                    out_p[2] = in_p[2];
489
 
                }
490
 
            }
491
 
        }
492
 
        else if (page_get_depth (page) == 2) {
493
 
            int row, shift_count = 6;
494
 
            guchar *write_ptr;
495
 
 
496
 
            depth = 2;
497
 
            color_space = "DeviceGray";
498
 
            data_length = height * ((width * 2 + 7) / 8);
499
 
            data = g_malloc (sizeof (guchar) * data_length);
500
 
            write_ptr = data;
501
 
            write_ptr[0] = 0;
502
 
            for (row = 0; row < height; row++) {
503
 
                int x;
504
 
                guchar *in_line;
505
 
 
506
 
                /* Pad to the next line */
507
 
                if (shift_count != 6) {
508
 
                    write_ptr++;
509
 
                    write_ptr[0] = 0;                   
510
 
                    shift_count = 6;
511
 
                }
512
 
 
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;
516
 
                    if (in_p[0] >= 192)
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) {
523
 
                        write_ptr++;
524
 
                        write_ptr[0] = 0;
525
 
                        shift_count = 6;
526
 
                    }
527
 
                    else
528
 
                        shift_count -= 2;
529
 
                }
530
 
            }
531
 
        }
532
 
        else if (page_get_depth (page) == 1) {
533
 
            int row, mask = 0x80;
534
 
            guchar *write_ptr;
535
 
 
536
 
            depth = 1;
537
 
            color_space = "DeviceGray";
538
 
            data_length = height * ((width + 7) / 8);
539
 
            data = g_malloc (sizeof (guchar) * data_length);
540
 
            write_ptr = data;
541
 
            write_ptr[0] = 0;
542
 
            for (row = 0; row < height; row++) {
543
 
                int x;
544
 
                guchar *in_line;
545
 
 
546
 
                /* Pad to the next line */
547
 
                if (mask != 0x80) {
548
 
                    write_ptr++;
549
 
                    write_ptr[0] = 0;
550
 
                    mask = 0x80;
551
 
                }
552
 
 
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;
556
 
                    if (in_p[0] != 0)
557
 
                        write_ptr[0] |= mask;
558
 
                    mask >>= 1;
559
 
                    if (mask == 0) {
560
 
                        write_ptr++;
561
 
                        write_ptr[0] = 0;
562
 
                        mask = 0x80;
563
 
                    }
564
 
                }
565
 
            }
566
 
        }
567
 
        else {
568
 
            int row;
569
 
 
570
 
            depth = 8;
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++) {
575
 
                int x;
576
 
                guchar *in_line, *out_line;
577
 
 
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;
583
 
 
584
 
                    out_p[0] = in_p[0];
585
 
                }
586
 
            }
587
 
        }
588
 
 
589
 
        /* Compress data */
590
 
        compressed_data = compress_zlib (data, data_length, &compressed_length);
591
 
        if (compressed_data) {
592
 
            /* Try if JPEG compression is better */
593
 
            if (depth > 1) {
594
 
                guchar *jpeg_data;
595
 
                size_t jpeg_length;
596
 
 
597
 
                jpeg_data = compress_jpeg (image, &jpeg_length);
598
 
                if (jpeg_length < compressed_length) {
599
 
                    filter = "DCTDecode";
600
 
                    g_free (data);
601
 
                    g_free (compressed_data);
602
 
                    data = jpeg_data;
603
 
                    data_length = jpeg_length;
604
 
                }
605
 
            }
606
 
 
607
 
            if (!filter) {
608
 
                filter = "FlateDecode";
609
 
                g_free (data);
610
 
                data = compressed_data;
611
 
                data_length = compressed_length;
612
 
            }
613
 
        }
614
 
 
615
 
        /* Page */
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");
627
 
 
628
 
        /* Page image */
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);
640
 
        if (filter)
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);
645
 
        g_free (data);
646
 
        pdf_printf (writer, "\n");
647
 
        pdf_printf (writer, "endstream\n");
648
 
        pdf_printf (writer, "endobj\n");      
649
 
 
650
 
        /* Page contents */
651
 
        command = g_strdup_printf ("q\n"
652
 
                                   "%f 0 0 %f 0 0 cm\n"
653
 
                                   "/Im%d Do\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");
666
 
        g_free (command);
667
 
                  
668
 
        g_object_unref (image);
669
 
    }
670
 
  
671
 
    /* Info */
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");
679
 
 
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);
684
 
    GList *link;
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);
688
 
    }
689
 
 
690
 
    /* Trailer */
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");
700
 
  
701
 
    pdf_writer_free (writer);
702
 
 
703
 
    return TRUE;
704
 
}
705
 
 
706
 
 
707
 
gboolean
708
 
book_save (Book *book, const gchar *type, GFile *file, GError **error)
709
 
{
710
 
    gboolean result = FALSE;
711
 
 
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);
722
 
 
723
 
    return result;
724
 
}
725
 
 
726
 
 
727
 
void
728
 
book_set_needs_saving (Book *book, gboolean needs_saving)
729
 
{
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");
734
 
}
735
 
 
736
 
 
737
 
gboolean
738
 
book_get_needs_saving (Book *book)
739
 
{
740
 
    return book->priv->needs_saving;
741
 
}
742
 
 
743
 
 
744
 
static void
745
 
book_set_property (GObject      *object,
746
 
                   guint         prop_id,
747
 
                   const GValue *value,
748
 
                   GParamSpec   *pspec)
749
 
{
750
 
    Book *self;
751
 
 
752
 
    self = BOOK (object);
753
 
 
754
 
    switch (prop_id) {
755
 
    case PROP_NEEDS_SAVING:
756
 
        book_set_needs_saving (self, g_value_get_boolean (value));
757
 
        break;
758
 
    default:
759
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
760
 
        break;
761
 
    }
762
 
}
763
 
 
764
 
 
765
 
static void
766
 
book_get_property (GObject    *object,
767
 
                   guint       prop_id,
768
 
                   GValue     *value,
769
 
                   GParamSpec *pspec)
770
 
{
771
 
    Book *self;
772
 
 
773
 
    self = BOOK (object);
774
 
 
775
 
    switch (prop_id) {
776
 
    case PROP_NEEDS_SAVING:
777
 
        g_value_set_boolean (value, book_get_needs_saving (self));
778
 
        break;
779
 
    default:
780
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
781
 
        break;
782
 
    }
783
 
}
784
 
 
785
 
 
786
 
static void
787
 
book_finalize (GObject *object)
788
 
{
789
 
    Book *book = BOOK (object);
790
 
    book_clear (book);
791
 
    G_OBJECT_CLASS (book_parent_class)->finalize (object);
792
 
}
793
 
 
794
 
 
795
 
static void
796
 
book_class_init (BookClass *klass)
797
 
{
798
 
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
799
 
 
800
 
    object_class->get_property = book_get_property;
801
 
    object_class->set_property = book_set_property;
802
 
    object_class->finalize = book_finalize;
803
 
 
804
 
    g_object_class_install_property (object_class,
805
 
                                     PROP_NEEDS_SAVING,
806
 
                                     g_param_spec_boolean ("needs-saving",
807
 
                                                           "needs-saving",
808
 
                                                           "TRUE if this book needs saving",
809
 
                                                           FALSE,
810
 
                                                           G_PARAM_READWRITE));
811
 
 
812
 
    signals[PAGE_ADDED] =
813
 
        g_signal_new ("page-added",
814
 
                      G_TYPE_FROM_CLASS (klass),
815
 
                      G_SIGNAL_RUN_LAST,
816
 
                      G_STRUCT_OFFSET (BookClass, page_added),
817
 
                      NULL, NULL,
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),
823
 
                      G_SIGNAL_RUN_LAST,
824
 
                      G_STRUCT_OFFSET (BookClass, page_removed),
825
 
                      NULL, NULL,
826
 
                      g_cclosure_marshal_VOID__OBJECT,
827
 
                      G_TYPE_NONE, 1, page_get_type ());
828
 
    signals[REORDERED] =
829
 
        g_signal_new ("reordered",
830
 
                      G_TYPE_FROM_CLASS (klass),
831
 
                      G_SIGNAL_RUN_LAST,
832
 
                      G_STRUCT_OFFSET (BookClass, reordered),
833
 
                      NULL, NULL,
834
 
                      g_cclosure_marshal_VOID__VOID,
835
 
                      G_TYPE_NONE, 0);
836
 
    signals[CLEARED] =
837
 
        g_signal_new ("cleared",
838
 
                      G_TYPE_FROM_CLASS (klass),
839
 
                      G_SIGNAL_RUN_LAST,
840
 
                      G_STRUCT_OFFSET (BookClass, cleared),
841
 
                      NULL, NULL,
842
 
                      g_cclosure_marshal_VOID__VOID,
843
 
                      G_TYPE_NONE, 0);
844
 
 
845
 
    g_type_class_add_private (klass, sizeof (BookPrivate));
846
 
}
847
 
 
848
 
 
849
 
static void
850
 
book_init (Book *book)
851
 
{
852
 
    book->priv = G_TYPE_INSTANCE_GET_PRIVATE (book, BOOK_TYPE, BookPrivate);
853
 
}