2
* This file is part of the apvlv package
3
* Copyright (C) <2008> <Alf>
5
* Contact: Alf <naihe2010@gmail.com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
/* @CFILE ApvlvFile.cpp xxxxxxxxxxxxxxxxxxxxxxxxxx.
24
* Author: Alf <naihe2010@gmail.com>
26
/* @date Created: 2009/11/20 19:38:30 Alf*/
28
#include "ApvlvFile.hpp"
29
#include "ApvlvUtil.hpp"
30
#include "ApvlvView.hpp"
33
#define LIBUMD_ENABLE_GTK
45
#define MAX(a,b) ((a) > (b) ? (a) : (b))
48
ApvlvFile::ApvlvFile (const char *filename, bool check)
56
ApvlvFile::~ApvlvFile ()
65
ApvlvFile *ApvlvFile::newfile (const char *filename, bool check)
67
ApvlvFile *file = NULL;
68
static const char *type_phrase[] =
76
for (i = 0; i < 3; ++ i)
78
if (strcasecmp (filename + strlen (filename) - strlen (type_phrase[i]),
87
debug ("not a valid file: %s, treate as a PDF file", filename);
96
file = new ApvlvPDF (filename);
100
file = new ApvlvUMD (filename);
104
file = new ApvlvDJVU (filename);
121
ApvlvPDF::ApvlvPDF (const char *filename, bool check):ApvlvFile (filename,
128
|| g_file_test (filename, G_FILE_TEST_IS_REGULAR) == FALSE
130
g_locale_from_utf8 (filename, -1, NULL, NULL, NULL)) == NULL)
132
gView->errormessage ("filename error: %s",
133
filename ? filename : "No name");
134
throw std::bad_alloc ();
139
int rt = stat (wfilename, &sbuf);
142
gView->errormessage ("Can't stat the PDF file: %s.", filename);
143
throw std::bad_alloc ();
145
filelen = sbuf.st_size;
147
if (mRawdata != NULL && mRawdataSize < filelen)
153
if (mRawdata == NULL)
155
mRawdata = new char[filelen];
156
mRawdataSize = filelen;
159
ifstream ifs (wfilename, ios::binary);
162
ifs.read (mRawdata, filelen);
168
GError *error = NULL;
169
mDoc = poppler_document_new_from_data (mRawdata, filelen, NULL, &error);
171
if (mDoc == NULL && error && error->code == POPPLER_ERROR_ENCRYPTED)
173
GtkWidget *dia = gtk_message_dialog_new (NULL,
174
GTK_DIALOG_DESTROY_WITH_PARENT,
175
GTK_MESSAGE_QUESTION,
176
GTK_BUTTONS_OK_CANCEL,
177
"%s", error->message);
178
g_error_free (error);
181
GtkWidget *entry = gtk_entry_new ();
182
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
183
gtk_entry_set_invisible_char (GTK_ENTRY (entry), '*');
184
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dia)->vbox), entry, TRUE,
186
gtk_widget_show (entry);
188
int ret = gtk_dialog_run (GTK_DIALOG (dia));
189
if (ret == GTK_RESPONSE_OK)
191
gchar *ans = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));
195
poppler_document_new_from_data (mRawdata, filelen, ans,
200
gtk_widget_destroy (dia);
205
throw std::bad_alloc ();
209
ApvlvPDF::~ApvlvPDF ()
213
g_object_unref (mDoc);
217
bool ApvlvPDF::writefile (const char *filename)
219
debug ("write %p to %s", this, filename);
220
gchar *path = absolutepath (filename);
223
debug ("filename error: %s", filename);
227
GError *error = NULL;
228
gchar *uri = g_filename_to_uri (path, NULL, &error);
230
if (uri == NULL && error)
232
debug ("%d: %s", error->code, error->message);
236
if (mDoc && uri != NULL)
238
gboolean ret = poppler_document_save (mDoc, uri, NULL);
239
debug ("write pdf: %p to %s, return %d", mDoc, uri, ret);
241
return ret == TRUE ? true : false;
246
bool ApvlvPDF::pagesize (int pn, int rot, double *x, double *y)
248
PopplerPage *page = poppler_document_get_page (mDoc, pn);
251
if (rot == 90 || rot == 270)
253
poppler_page_get_size (page, y, x);
257
poppler_page_get_size (page, x, y);
264
int ApvlvPDF::pagesum ()
266
return mDoc ? poppler_document_get_n_pages (mDoc) : 0;
269
ApvlvPoses *ApvlvPDF::pagesearch (int pn, const char *str, bool reverse)
271
PopplerPage *page = poppler_document_get_page (mDoc, pn);
277
// debug ("search %s", str);
279
GList *list = poppler_page_find_text (page, str);
287
list = g_list_reverse (list);
290
ApvlvPoses *poses = new ApvlvPoses;
291
for (GList * tmp = list; tmp != NULL; tmp = g_list_next (tmp))
293
PopplerRectangle *rect = (PopplerRectangle *) tmp->data;
294
// debug ("results: %f-%f,%f-%f", rect->x1, rect->x2, rect->y1,
296
ApvlvPos pos = { rect->x1, rect->x2, rect->y1, rect->y2 };
297
poses->push_back (pos);
303
bool ApvlvPDF::pagetext (int pn, int x1, int y1, int x2, int y2, char **out)
305
PopplerPage *page = poppler_document_get_page (mDoc, pn);
306
#if POPPLER_CHECK_VERSION(0, 15, 1)
307
PopplerRectangle rect = { x1, y2, x2, y1 };
308
*out = poppler_page_get_selected_text (page, POPPLER_SELECTION_WORD, &rect);
310
PopplerRectangle rect = { x1, y1, x2, y2 };
311
*out = poppler_page_get_text (page, POPPLER_SELECTION_WORD, &rect);
320
bool ApvlvPDF::render (int pn, int ix, int iy, double zm, int rot,
321
GdkPixbuf * pix, char *buffer)
325
if ((tpage = poppler_document_get_page (mDoc, pn)) == NULL)
327
debug ("no this page: %d", pn);
331
poppler_page_render_to_pixbuf (tpage, 0, 0, ix, iy, zm, rot, pix);
335
bool ApvlvPDF::pageselectsearch (int pn, int ix, int iy,
336
double zm, int rot, GdkPixbuf * pix,
337
char *buffer, int sel, ApvlvPoses * poses)
339
ApvlvPos rect = (*poses)[sel];
341
// Caculate the correct position
342
//debug ("pagex: %f, pagey: %f, x1: %f, y1: %f, x2: %f, y2: %f", pagex, pagey, rect->x1, rect->y1, rect->x2, rect->y2);
343
gint x1 = MAX (rect.x1 * zm + 0.5, 0);
344
gint x2 = MAX (rect.x2 * zm - 0.5, 1);
345
gint y1 = MAX ((iy - rect.y2 * zm) + 0.5, 0);
346
gint y2 = MAX ((iy - rect.y1 * zm) - 0.5, 1);
347
//debug ("x1: %d, y1: %d, x2: %d, y2: %d", x1, y1, x2, y2);
349
// heightlight the selection
350
for (gint y = y1; y < y2; y++)
352
for (gint x = x1; x < x2; x++)
354
gint p = (gint) (y * ix * 3 + (x * 3));
355
buffer[p + 0] = 0xff - buffer[p + 0];
356
buffer[p + 1] = 0xff - buffer[p + 0];
357
buffer[p + 2] = 0xff - buffer[p + 0];
361
// change the back color of the selection
362
for (ApvlvPoses::const_iterator itr = poses->begin ();
363
itr != poses->end (); itr++)
365
// Caculate the correct position
366
x1 = (gint) (itr->x1 * zm);
367
x2 = (gint) (itr->x2 * zm);
368
y1 = (gint) (iy - itr->y2 * zm);
369
y2 = (gint) (iy - itr->y1 * zm);
371
for (gint y = y1; y < y2; y++)
373
for (gint x = x1; x < x2; x++)
375
gint p = (gint) (y * 3 * ix + (x * 3));
376
buffer[p + 0] = 0xff - buffer[p + 0];
377
buffer[p + 1] = 0xff - buffer[p + 0];
378
buffer[p + 2] = 0xff - buffer[p + 0];
386
ApvlvLinks *ApvlvPDF::getlinks (int pn)
388
PopplerPage *page = poppler_document_get_page (mDoc, pn);
389
GList *list = poppler_page_get_link_mapping (page);
395
ApvlvLinks *links = new ApvlvLinks;
397
for (GList * tmp = list; tmp != NULL; tmp = g_list_next (tmp))
399
PopplerLinkMapping *map = (PopplerLinkMapping *) tmp->data;
402
PopplerAction *act = map->action;
403
if (act && *(PopplerActionType *) act == POPPLER_ACTION_GOTO_DEST)
405
PopplerDest *pd = ((PopplerActionGotoDest *) act)->dest;
406
if (pd->type == POPPLER_DEST_NAMED)
408
PopplerDest *destnew = poppler_document_find_dest (mDoc,
412
ApvlvLink link = { "", destnew->page_num - 1 };
413
links->insert (links->begin (), link);
414
poppler_dest_free (destnew);
419
ApvlvLink link = { "", pd->page_num - 1 };
420
links->insert (links->begin (), link);
429
ApvlvFileIndex *ApvlvPDF::new_index ()
433
debug ("file %p has index: %p, return", this, mIndex);
437
PopplerIndexIter *itr = poppler_index_iter_new (mDoc);
444
mIndex = new ApvlvFileIndex;
445
walk_poppler_index_iter (mIndex, itr);
446
poppler_index_iter_free (itr);
451
void ApvlvPDF::free_index (ApvlvFileIndex * index)
456
bool ApvlvPDF::walk_poppler_index_iter (ApvlvFileIndex * titr,
457
PopplerIndexIter * iter)
463
ApvlvFileIndex *index = NULL;
465
PopplerAction *act = poppler_index_iter_get_action (iter);
468
if (*(PopplerActionType *) act == POPPLER_ACTION_GOTO_DEST)
470
PopplerActionGotoDest *pagd = (PopplerActionGotoDest *) act;
471
if (pagd->dest->type == POPPLER_DEST_NAMED)
473
PopplerDest *destnew = poppler_document_find_dest (mDoc,
480
pn = destnew->page_num - 1;
481
poppler_dest_free (destnew);
483
index = new ApvlvFileIndex;
488
index = new ApvlvFileIndex;
489
index->page = pagd->dest->page_num - 1;
495
index->title = pagd->title;
496
titr->children.push_back (*index);
498
index = &(titr->children[titr->children.size () - 1]);
499
debug ("titr: %p, index: %p", titr, index);
502
poppler_action_free (act);
505
PopplerIndexIter *child = poppler_index_iter_get_child (iter);
508
bool chas = walk_poppler_index_iter (has ? index : titr, child);
509
has = has ? has : chas;
510
poppler_index_iter_free (child);
513
while (poppler_index_iter_next (iter));
517
bool ApvlvPDF::pageprint (int pn, cairo_t * cr)
522
PopplerPage *page = poppler_document_get_page (mDoc, pn);
525
poppler_page_render_for_printing (page, cr);
536
void handle_ddjvu_messages (ddjvu_context_t * ctx, int wait)
538
const ddjvu_message_t *msg;
540
ddjvu_message_wait (ctx);
541
while ((msg = ddjvu_message_peek (ctx)))
543
debug ("tag: %d", msg->m_any.tag);
544
switch (msg->m_any.tag)
555
ddjvu_message_pop (ctx);
560
ApvlvDJVU::ApvlvDJVU (const char *filename, bool check):ApvlvFile (filename,
564
mContext = ddjvu_context_create ("apvlv");
567
mDoc = ddjvu_document_create_by_filename (mContext, filename, FALSE);
572
if (ddjvu_document_get_type (mDoc) == DDJVU_DOCTYPE_SINGLEPAGE)
574
debug ("djvu type: %d", ddjvu_document_get_type (mDoc));
579
ddjvu_document_release (mDoc);
581
ddjvu_context_release (mContext);
583
throw std::bad_alloc (); */
588
ddjvu_context_release (mContext);
590
throw std::bad_alloc ();
593
throw std::bad_alloc ();
597
ApvlvDJVU::~ApvlvDJVU ()
602
ddjvu_context_release (mContext);
607
ddjvu_document_release (mDoc);
612
bool ApvlvDJVU::writefile (const char *filename)
615
FILE *fp = fopen (filename, "wb");
618
ddjvu_job_t *job = ddjvu_document_save (mDoc, fp, 0, NULL);
619
while (!ddjvu_job_done (job))
621
handle_ddjvu_messages (mContext, TRUE);
632
bool ApvlvDJVU::pagesize (int pn, int rot, double *x, double *y)
636
ddjvu_pageinfo_t info[1];
637
while ((t = ddjvu_document_get_pageinfo (mDoc, 0, info)) < DDJVU_JOB_OK)
639
handle_ddjvu_messages (mContext, true);
642
if (t == DDJVU_JOB_OK)
646
debug ("djvu page 1: %f-%f", *x, *y);
654
int ApvlvDJVU::pagesum ()
657
return mDoc ? ddjvu_document_get_pagenum (mDoc) : 0;
663
bool ApvlvDJVU::render (int pn, int ix, int iy, double zm, int rot,
664
GdkPixbuf * pix, char *buffer)
669
if ((tpage = ddjvu_page_create_by_pageno (mDoc, pn)) == NULL)
671
debug ("no this page: %d", pn);
675
ddjvu_rect_t prect[1] = { {0, 0, ix, iy}
677
ddjvu_rect_t rrect[1] = { {0, 0, ix, iy}
679
ddjvu_format_t *format =
680
ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, NULL);
681
ddjvu_format_set_row_order (format, TRUE);
684
while (retry <= 20 && ddjvu_page_render
685
(tpage, DDJVU_RENDER_COLOR, prect, rrect, format, 3 * ix,
686
(char *) buffer) == FALSE)
689
debug ("fender failed, retry %d", ++retry);
698
bool ApvlvDJVU::pageselectsearch (int pn, int ix, int iy, double zm,
699
int rot, GdkPixbuf * pix, char *buffer,
700
int sel, ApvlvPoses * poses)
705
ApvlvPoses *ApvlvDJVU::pagesearch (int pn, const char *str, bool reverse)
710
ApvlvLinks *ApvlvDJVU::getlinks (int pn)
715
bool ApvlvDJVU::pagetext (int pn, int x1, int y1, int x2, int y2,
721
ApvlvFileIndex *ApvlvDJVU::new_index ()
726
void ApvlvDJVU::free_index (ApvlvFileIndex * index)
730
bool ApvlvDJVU::pageprint (int pn, cairo_t * cr)
735
ApvlvUMD::ApvlvUMD (const char *filename, bool check):ApvlvFile (filename,
739
gchar * lname = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
742
mUmd = umd_new_from_file (lname);
747
mUmd = umd_new_from_file (filename);
752
throw std::bad_alloc ();
755
throw std::bad_alloc ();
759
ApvlvUMD::~ApvlvUMD ()
769
bool ApvlvUMD::writefile (const char *filename)
772
if (umd_write_file (mUmd, filename) == 0)
782
bool ApvlvUMD::pagesize (int pn, int rot, double *x, double *y)
787
page = umd_get_nth_page (mUmd, pn);
791
umd_page_get_size (page, &ix, &iy);
802
int ApvlvUMD::pagesum ()
805
return mUmd ? umd_get_page_n (mUmd) : 0;
811
bool ApvlvUMD::render (int pn, int ix, int iy, double zm, int rot,
812
GdkPixbuf * pix, char *buffer)
817
page = umd_get_nth_page (mUmd, pn);
820
umd_page_render (page, 0, 0, ix, iy, zm, rot, (unsigned char *) buffer, 3 * ix);
829
bool ApvlvUMD::pageselectsearch (int pn, int ix, int iy, double zm,
830
int rot, GdkPixbuf * pix, char *buffer,
831
int sel, ApvlvPoses * poses)
836
ApvlvPoses *ApvlvUMD::pagesearch (int pn, const char *str, bool reverse)
841
ApvlvLinks *ApvlvUMD::getlinks (int pn)
846
bool ApvlvUMD::pagetext (int pn, int x1, int y1, int x2, int y2,
852
ApvlvFileIndex *ApvlvUMD::new_index ()
857
debug ("file %p has index: %p, return", this, mIndex);
861
int cpt_n = umd_get_chapter_n (mUmd);
868
mIndex = new ApvlvFileIndex;
873
umd_chapter_t * chapter = umd_get_nth_chapter (mUmd, i);
878
inx.title = chapter->title;
879
inx.page = chapter->page_index;
881
mIndex->children.push_back (inx);
883
free (chapter->title);
884
free (chapter->content);
895
void ApvlvUMD::free_index (ApvlvFileIndex * index)
902
bool ApvlvUMD::pageprint (int pn, cairo_t * cr)