1 //========================================================================
2 //
3 // HtmlOutputDev.cc
4 //
5 // Copyright 1997-2002 Glyph & Cog, LLC
6 //
7 // Changed 1999-2000 by G.Ovtcharov
8 //
9 // Changed 2002 by Mikhail Kruk
10 //
11 //========================================================================
12
13 //========================================================================
14 //
15 // Modified under the Poppler project - http://poppler.freedesktop.org
16 //
17 // All changes made under the Poppler project to this file are licensed
18 // under GPL version 2 or later
19 //
20 // Copyright (C) 2005-2010 Albert Astals Cid <aacid@kde.org>
21 // Copyright (C) 2008 Kjartan Maraas <kmaraas@gnome.org>
22 // Copyright (C) 2008 Boris Toloknov <tlknv@yandex.ru>
23 // Copyright (C) 2008 Haruyuki Kawabe <Haruyuki.Kawabe@unisys.co.jp>
24 // Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
25 // Copyright (C) 2009 Warren Toomey <wkt@tuhs.org>
26 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
27 // Copyright (C) 2009 Reece Dunn <msclrhd@gmail.com>
28 // Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
29 // Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
30 // Copyright (C) 2010 OSSD CDAC Mumbai by Leena Chourey (leenac@cdacmumbai.in) and Onkar Potdar (onkar@cdacmumbai.in)
31 //
32 // To see a description of the changes please see the Changelog file that
33 // came with your tarball or type make ChangeLog if you are building from git
34 //
35 //========================================================================
36
37 #ifdef __GNUC__
38 #pragma implementation
39 #endif
40
41 #include "config.h"
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <stddef.h>
46 #include <ctype.h>
47 #include <math.h>
48 #include "goo/GooString.h"
49 #include "goo/GooList.h"
50 #include "UnicodeMap.h"
51 #include "goo/gmem.h"
52 #include "Error.h"
53 #include "GfxState.h"
54 #include "Page.h"
55 #include "PNGWriter.h"
56 #ifdef ENABLE_LIBJPEG
57 #include "DCTStream.h"
58 #endif
59 #include "GlobalParams.h"
60 #include "HtmlOutputDev.h"
61 #include "HtmlFonts.h"
62
63 int HtmlPage::pgNum=0;
64 int HtmlOutputDev::imgNum=1;
65 GooList *HtmlOutputDev::imgList=new GooList();
66
67 extern GBool complexMode;
68 extern GBool singleHtml;
69 extern GBool ignore;
70 extern GBool printCommands;
71 extern GBool printHtml;
72 extern GBool noframes;
73 extern GBool stout;
74 extern GBool xml;
75 extern GBool showHidden;
76 extern GBool noMerge;
77
basename(GooString * str)78 static GooString* basename(GooString* str){
79
80 char *p=str->getCString();
81 int len=str->getLength();
82 for (int i=len-1;i>=0;i--)
83 if (*(p+i)==SLASH)
84 return new GooString((p+i+1),len-i-1);
85 return new GooString(str);
86 }
87
88 #if 0
89 static GooString* Dirname(GooString* str){
90
91 char *p=str->getCString();
92 int len=str->getLength();
93 for (int i=len-1;i>=0;i--)
94 if (*(p+i)==SLASH)
95 return new GooString(p,i+1);
96 return new GooString();
97 }
98 #endif
99
100 //------------------------------------------------------------------------
101 // HtmlString
102 //------------------------------------------------------------------------
103
HtmlString(GfxState * state,double fontSize,HtmlFontAccu * fonts)104 HtmlString::HtmlString(GfxState *state, double fontSize, HtmlFontAccu* fonts) {
105 GfxFont *font;
106 double x, y;
107
108 state->transform(state->getCurX(), state->getCurY(), &x, &y);
109 if ((font = state->getFont())) {
110 double ascent = font->getAscent();
111 double descent = font->getDescent();
112 if( ascent > 1.05 ){
113 //printf( "ascent=%.15g is too high, descent=%.15g\n", ascent, descent );
114 ascent = 1.05;
115 }
116 if( descent < -0.4 ){
117 //printf( "descent %.15g is too low, ascent=%.15g\n", descent, ascent );
118 descent = -0.4;
119 }
120 yMin = y - ascent * fontSize;
121 yMax = y - descent * fontSize;
122 GfxRGB rgb;
123 state->getFillRGB(&rgb);
124 GooString *name = state->getFont()->getName();
125 if (!name) name = HtmlFont::getDefaultFont(); //new GooString("default");
126 HtmlFont hfont=HtmlFont(name, static_cast<int>(fontSize-1), rgb);
127 fontpos = fonts->AddFont(hfont);
128 } else {
129 // this means that the PDF file draws text without a current font,
130 // which should never happen
131 yMin = y - 0.95 * fontSize;
132 yMax = y + 0.35 * fontSize;
133 fontpos=0;
134 }
135 if (yMin == yMax) {
136 // this is a sanity check for a case that shouldn't happen -- but
137 // if it does happen, we want to avoid dividing by zero later
138 yMin = y;
139 yMax = y + 1;
140 }
141 col = 0;
142 text = NULL;
143 xRight = NULL;
144 link = NULL;
145 len = size = 0;
146 yxNext = NULL;
147 xyNext = NULL;
148 htext=new GooString();
149 dir = textDirUnknown;
150 }
151
152
~HtmlString()153 HtmlString::~HtmlString() {
154 gfree(text);
155 delete htext;
156 gfree(xRight);
157 }
158
addChar(GfxState * state,double x,double y,double dx,double dy,Unicode u)159 void HtmlString::addChar(GfxState *state, double x, double y,
160 double dx, double dy, Unicode u) {
161 if (dir == textDirUnknown) {
162 //dir = UnicodeMap::getDirection(u);
163 dir = textDirLeftRight;
164 }
165
166 if (len == size) {
167 size += 16;
168 text = (Unicode *)grealloc(text, size * sizeof(Unicode));
169 xRight = (double *)grealloc(xRight, size * sizeof(double));
170 }
171 text[len] = u;
172 if (len == 0) {
173 xMin = x;
174 }
175 xMax = xRight[len] = x + dx;
176 //printf("added char: %f %f xright = %f\n", x, dx, x+dx);
177 ++len;
178 }
179
endString()180 void HtmlString::endString()
181 {
182 if( dir == textDirRightLeft && len > 1 )
183 {
184 //printf("will reverse!\n");
185 for (int i = 0; i < len / 2; i++)
186 {
187 Unicode ch = text[i];
188 text[i] = text[len - i - 1];
189 text[len - i - 1] = ch;
190 }
191 }
192 }
193
194 //------------------------------------------------------------------------
195 // HtmlPage
196 //------------------------------------------------------------------------
197
HtmlPage(GBool rawOrder,char * imgExtVal)198 HtmlPage::HtmlPage(GBool rawOrder, char *imgExtVal) {
199 this->rawOrder = rawOrder;
200 curStr = NULL;
201 yxStrings = NULL;
202 xyStrings = NULL;
203 yxCur1 = yxCur2 = NULL;
204 fonts=new HtmlFontAccu();
205 links=new HtmlLinks();
206 pageWidth=0;
207 pageHeight=0;
208 fontsPageMarker = 0;
209 DocName=NULL;
210 firstPage = -1;
211 imgExt = new GooString(imgExtVal);
212 }
213
~HtmlPage()214 HtmlPage::~HtmlPage() {
215 clear();
216 if (DocName) delete DocName;
217 if (fonts) delete fonts;
218 if (links) delete links;
219 if (imgExt) delete imgExt;
220 }
221
updateFont(GfxState * state)222 void HtmlPage::updateFont(GfxState *state) {
223 GfxFont *font;
224 double *fm;
225 char *name;
226 int code;
227 double w;
228
229 // adjust the font size
230 fontSize = state->getTransformedFontSize();
231 if ((font = state->getFont()) && font->getType() == fontType3) {
232 // This is a hack which makes it possible to deal with some Type 3
233 // fonts. The problem is that it's impossible to know what the
234 // base coordinate system used in the font is without actually
235 // rendering the font. This code tries to guess by looking at the
236 // width of the character 'm' (which breaks if the font is a
237 // subset that doesn't contain 'm').
238 for (code = 0; code < 256; ++code) {
239 if ((name = ((Gfx8BitFont *)font)->getCharName(code)) &&
240 name[0] == 'm' && name[1] == '\0') {
241 break;
242 }
243 }
244 if (code < 256) {
245 w = ((Gfx8BitFont *)font)->getWidth(code);
246 if (w != 0) {
247 // 600 is a generic average 'm' width -- yes, this is a hack
248 fontSize *= w / 0.6;
249 }
250 }
251 fm = font->getFontMatrix();
252 if (fm[0] != 0) {
253 fontSize *= fabs(fm[3] / fm[0]);
254 }
255 }
256 }
257
beginString(GfxState * state,GooString * s)258 void HtmlPage::beginString(GfxState *state, GooString *s) {
259 curStr = new HtmlString(state, fontSize, fonts);
260 }
261
262
conv()263 void HtmlPage::conv(){
264 HtmlString *tmp;
265
266 int linkIndex = 0;
267 HtmlFont* h;
268 for(tmp=yxStrings;tmp;tmp=tmp->yxNext){
269 int pos=tmp->fontpos;
270 // printf("%d\n",pos);
271 h=fonts->Get(pos);
272
273 if (tmp->htext) delete tmp->htext;
274 tmp->htext=HtmlFont::simple(h,tmp->text,tmp->len);
275
276 if (links->inLink(tmp->xMin,tmp->yMin,tmp->xMax,tmp->yMax, linkIndex)){
277 tmp->link = links->getLink(linkIndex);
278 /*GooString *t=tmp->htext;
279 tmp->htext=links->getLink(k)->Link(tmp->htext);
280 delete t;*/
281 }
282 }
283
284 }
285
286
addChar(GfxState * state,double x,double y,double dx,double dy,double ox,double oy,Unicode * u,int uLen)287 void HtmlPage::addChar(GfxState *state, double x, double y,
288 double dx, double dy,
289 double ox, double oy, Unicode *u, int uLen) {
290 double x1, y1, w1, h1, dx2, dy2;
291 int n, i;
292 state->transform(x, y, &x1, &y1);
293 n = curStr->len;
294
295 // check that new character is in the same direction as current string
296 // and is not too far away from it before adding
297 //if ((UnicodeMap::getDirection(u[0]) != curStr->dir) ||
298 // XXX
299 if (
300 (n > 0 &&
301 fabs(x1 - curStr->xRight[n-1]) > 0.1 * (curStr->yMax - curStr->yMin))) {
302 endString();
303 beginString(state, NULL);
304 }
305 state->textTransformDelta(state->getCharSpace() * state->getHorizScaling(),
306 0, &dx2, &dy2);
307 dx -= dx2;
308 dy -= dy2;
309 state->transformDelta(dx, dy, &w1, &h1);
310 if (uLen != 0) {
311 w1 /= uLen;
312 h1 /= uLen;
313 }
314 for (i = 0; i < uLen; ++i) {
315 curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]);
316 }
317 }
318
endString()319 void HtmlPage::endString() {
320 HtmlString *p1, *p2;
321 double h, y1, y2;
322
323 // throw away zero-length strings -- they don't have valid xMin/xMax
324 // values, and they're useless anyway
325 if (curStr->len == 0) {
326 delete curStr;
327 curStr = NULL;
328 return;
329 }
330
331 curStr->endString();
332
333 #if 0 //~tmp
334 if (curStr->yMax - curStr->yMin > 20) {
335 delete curStr;
336 curStr = NULL;
337 return;
338 }
339 #endif
340
341 // insert string in y-major list
342 h = curStr->yMax - curStr->yMin;
343 y1 = curStr->yMin + 0.5 * h;
344 y2 = curStr->yMin + 0.8 * h;
345 if (rawOrder) {
346 p1 = yxCur1;
347 p2 = NULL;
348 } else if ((!yxCur1 ||
349 (y1 >= yxCur1->yMin &&
350 (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) &&
351 (!yxCur2 ||
352 (y1 < yxCur2->yMin ||
353 (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) {
354 p1 = yxCur1;
355 p2 = yxCur2;
356 } else {
357 for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) {
358 if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin))
359 break;
360 }
361 yxCur2 = p2;
362 }
363 yxCur1 = curStr;
364 if (p1)
365 p1->yxNext = curStr;
366 else
367 yxStrings = curStr;
368 curStr->yxNext = p2;
369 curStr = NULL;
370 }
371
strrstr(const char * s,const char * ss)372 static const char *strrstr( const char *s, const char *ss )
373 {
374 const char *p = strstr( s, ss );
375 for( const char *pp = p; pp != NULL; pp = strstr( p+1, ss ) ){
376 p = pp;
377 }
378 return p;
379 }
380
CloseTags(GooString * htext,GBool & finish_a,GBool & finish_italic,GBool & finish_bold)381 static void CloseTags( GooString *htext, GBool &finish_a, GBool &finish_italic, GBool &finish_bold )
382 {
383 const char *last_italic = finish_italic && ( finish_bold || finish_a ) ? strrstr( htext->getCString(), "<i>" ) : NULL;
384 const char *last_bold = finish_bold && ( finish_italic || finish_a ) ? strrstr( htext->getCString(), "<b>" ) : NULL;
385 const char *last_a = finish_a && ( finish_italic || finish_bold ) ? strrstr( htext->getCString(), "<a " ) : NULL;
386 if( finish_a && ( finish_italic || finish_bold ) && last_a > ( last_italic > last_bold ? last_italic : last_bold ) ){
387 htext->append("</a>", 4);
388 finish_a = false;
389 }
390 if( finish_italic && finish_bold && last_italic > last_bold ){
391 htext->append("</i>", 4);
392 finish_italic = false;
393 }
394 if( finish_bold )
395 htext->append("</b>", 4);
396 if( finish_italic )
397 htext->append("</i>", 4);
398 if( finish_a )
399 htext->append("</a>");
400 }
401
coalesce()402 void HtmlPage::coalesce() {
403 HtmlString *str1, *str2;
404 HtmlFont *hfont1, *hfont2;
405 double space, horSpace, vertSpace, vertOverlap;
406 GBool addSpace, addLineBreak;
407 int n, i;
408 double curX, curY;
409
410 #if 0 //~ for debugging
411 for (str1 = yxStrings; str1; str1 = str1->yxNext) {
412 printf("x=%f..%f y=%f..%f size=%2d '",
413 str1->xMin, str1->xMax, str1->yMin, str1->yMax,
414 (int)(str1->yMax - str1->yMin));
415 for (i = 0; i < str1->len; ++i) {
416 fputc(str1->text[i] & 0xff, stdout);
417 }
418 printf("'\n");
419 }
420 printf("\n------------------------------------------------------------\n\n");
421 #endif
422 str1 = yxStrings;
423
424 if( !str1 ) return;
425
426 //----- discard duplicated text (fake boldface, drop shadows)
427 if( !complexMode )
428 { /* if not in complex mode get rid of duplicate strings */
429 HtmlString *str3;
430 GBool found;
431 while (str1)
432 {
433 double size = str1->yMax - str1->yMin;
434 double xLimit = str1->xMin + size * 0.2;
435 found = gFalse;
436 for (str2 = str1, str3 = str1->yxNext;
437 str3 && str3->xMin < xLimit;
438 str2 = str3, str3 = str2->yxNext)
439 {
440 if (str3->len == str1->len &&
441 !memcmp(str3->text, str1->text, str1->len * sizeof(Unicode)) &&
442 fabs(str3->yMin - str1->yMin) < size * 0.2 &&
443 fabs(str3->yMax - str1->yMax) < size * 0.2 &&
444 fabs(str3->xMax - str1->xMax) < size * 0.2)
445 {
446 found = gTrue;
447 //printf("found duplicate!\n");
448 break;
449 }
450 }
451 if (found)
452 {
453 str2->xyNext = str3->xyNext;
454 str2->yxNext = str3->yxNext;
455 delete str3;
456 }
457 else
458 {
459 str1 = str1->yxNext;
460 }
461 }
462 } /*- !complexMode */
463
464 str1 = yxStrings;
465
466 hfont1 = getFont(str1);
467 if( hfont1->isBold() )
468 str1->htext->insert(0,"<b>",3);
469 if( hfont1->isItalic() )
470 str1->htext->insert(0,"<i>",3);
471 if( str1->getLink() != NULL ) {
472 GooString *ls = str1->getLink()->getLinkStart();
473 str1->htext->insert(0, ls);
474 delete ls;
475 }
476 curX = str1->xMin; curY = str1->yMin;
477
478 while (str1 && (str2 = str1->yxNext)) {
479 hfont2 = getFont(str2);
480 space = str1->yMax - str1->yMin;
481 horSpace = str2->xMin - str1->xMax;
482 addLineBreak = !noMerge && (fabs(str1->xMin - str2->xMin) < 0.4);
483 vertSpace = str2->yMin - str1->yMax;
484
485 //printf("coalesce %d %d %f? ", str1->dir, str2->dir, d);
486
487 if (str2->yMin >= str1->yMin && str2->yMin <= str1->yMax)
488 {
489 vertOverlap = str1->yMax - str2->yMin;
490 } else
491 if (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax)
492 {
493 vertOverlap = str2->yMax - str1->yMin;
494 } else
495 {
496 vertOverlap = 0;
497 }
498
499 if (
500 (
501 (
502 (
503 (rawOrder && vertOverlap > 0.5 * space)
504 ||
505 (!rawOrder && str2->yMin < str1->yMax)
506 ) &&
507 (horSpace > -0.5 * space && horSpace < space)
508 ) ||
509 (vertSpace >= 0 && vertSpace < 0.5 * space && addLineBreak)
510 ) &&
511 (!complexMode || (hfont1->isEqualIgnoreBold(*hfont2))) && // in complex mode fonts must be the same, in other modes fonts do not metter
512 str1->dir == str2->dir // text direction the same
513 )
514 {
515 // printf("yes\n");
516 n = str1->len + str2->len;
517 if ((addSpace = horSpace > 0.1 * space)) {
518 ++n;
519 }
520 if (addLineBreak) {
521 ++n;
522 }
523
524 str1->size = (n + 15) & ~15;
525 str1->text = (Unicode *)grealloc(str1->text,
526 str1->size * sizeof(Unicode));
527 str1->xRight = (double *)grealloc(str1->xRight,
528 str1->size * sizeof(double));
529 if (addSpace) {
530 str1->text[str1->len] = 0x20;
531 str1->htext->append(xml?" ":" ");
532 str1->xRight[str1->len] = str2->xMin;
533 ++str1->len;
534 }
535 if (addLineBreak) {
536 str1->text[str1->len] = '\n';
537 str1->htext->append("<br>");
538 str1->xRight[str1->len] = str2->xMin;
539 ++str1->len;
540 str1->yMin = str2->yMin;
541 str1->yMax = str2->yMax;
542 str1->xMax = str2->xMax;
543 int fontLineSize = hfont1->getLineSize();
544 int curLineSize = (int)(vertSpace + space);
545 if( curLineSize != fontLineSize )
546 {
547 HtmlFont *newfnt = new HtmlFont(*hfont1);
548 newfnt->setLineSize(curLineSize);
549 str1->fontpos = fonts->AddFont(*newfnt);
550 delete newfnt;
551 hfont1 = getFont(str1);
552 // we have to reget hfont2 because it's location could have
553 // changed on resize
554 hfont2 = getFont(str2);
555 }
556 }
557 for (i = 0; i < str2->len; ++i) {
558 str1->text[str1->len] = str2->text[i];
559 str1->xRight[str1->len] = str2->xRight[i];
560 ++str1->len;
561 }
562
563 /* fix <i>, <b> if str1 and str2 differ and handle switch of links */
564 HtmlLink *hlink1 = str1->getLink();
565 HtmlLink *hlink2 = str2->getLink();
566 bool switch_links = !hlink1 || !hlink2 || !hlink1->isEqualDest(*hlink2);
567 GBool finish_a = switch_links && hlink1 != NULL;
568 GBool finish_italic = hfont1->isItalic() && ( !hfont2->isItalic() || finish_a );
569 GBool finish_bold = hfont1->isBold() && ( !hfont2->isBold() || finish_a || finish_italic );
570 CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
571 if( switch_links && hlink2 != NULL ) {
572 GooString *ls = hlink2->getLinkStart();
573 str1->htext->append(ls);
574 delete ls;
575 }
576 if( ( !hfont1->isItalic() || finish_italic ) && hfont2->isItalic() )
577 str1->htext->append("<i>", 3);
578 if( ( !hfont1->isBold() || finish_bold ) && hfont2->isBold() )
579 str1->htext->append("<b>", 3);
580
581
582 str1->htext->append(str2->htext);
583 // str1 now contains href for link of str2 (if it is defined)
584 str1->link = str2->link;
585 hfont1 = hfont2;
586 if (str2->xMax > str1->xMax) {
587 str1->xMax = str2->xMax;
588 }
589 if (str2->yMax > str1->yMax) {
590 str1->yMax = str2->yMax;
591 }
592 str1->yxNext = str2->yxNext;
593 delete str2;
594 } else { // keep strings separate
595 // printf("no\n");
596 GBool finish_a = str1->getLink() != NULL;
597 GBool finish_bold = hfont1->isBold();
598 GBool finish_italic = hfont1->isItalic();
599 CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
600
601 str1->xMin = curX; str1->yMin = curY;
602 str1 = str2;
603 curX = str1->xMin; curY = str1->yMin;
604 hfont1 = hfont2;
605 if( hfont1->isBold() )
606 str1->htext->insert(0,"<b>",3);
607 if( hfont1->isItalic() )
608 str1->htext->insert(0,"<i>",3);
609 if( str1->getLink() != NULL ) {
610 GooString *ls = str1->getLink()->getLinkStart();
611 str1->htext->insert(0, ls);
612 delete ls;
613 }
614 }
615 }
616 str1->xMin = curX; str1->yMin = curY;
617
618 GBool finish_bold = hfont1->isBold();
619 GBool finish_italic = hfont1->isItalic();
620 GBool finish_a = str1->getLink() != NULL;
621 CloseTags( str1->htext, finish_a, finish_italic, finish_bold );
622
623 #if 0 //~ for debugging
624 for (str1 = yxStrings; str1; str1 = str1->yxNext) {
625 printf("x=%3d..%3d y=%3d..%3d size=%2d ",
626 (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax,
627 (int)(str1->yMax - str1->yMin));
628 printf("'%s'\n", str1->htext->getCString());
629 }
630 printf("\n------------------------------------------------------------\n\n");
631 #endif
632
633 }
634
dumpAsXML(FILE * f,int page)635 void HtmlPage::dumpAsXML(FILE* f,int page){
636 fprintf(f, "<page number=\"%d\" position=\"absolute\"", page);
637 fprintf(f," top=\"0\" left=\"0\" height=\"%d\" width=\"%d\">\n", pageHeight,pageWidth);
638
639 for(int i=fontsPageMarker;i < fonts->size();i++) {
640 GooString *fontCSStyle = fonts->CSStyle(i);
641 fprintf(f,"\t%s\n",fontCSStyle->getCString());
642 delete fontCSStyle;
643 }
644
645 GooString *str, *str1 = NULL;
646 for(HtmlString *tmp=yxStrings;tmp;tmp=tmp->yxNext){
647 if (tmp->htext){
648 str=new GooString(tmp->htext);
649 fprintf(f,"<text top=\"%d\" left=\"%d\" ",xoutRound(tmp->yMin),xoutRound(tmp->xMin));
650 fprintf(f,"width=\"%d\" height=\"%d\" ",xoutRound(tmp->xMax-tmp->xMin),xoutRound(tmp->yMax-tmp->yMin));
651 fprintf(f,"font=\"%d\">", tmp->fontpos);
652 str1=fonts->getCSStyle(tmp->fontpos, str);
653 fputs(str1->getCString(),f);
654 delete str;
655 delete str1;
656 fputs("</text>\n",f);
657 }
658 }
659 fputs("</page>\n",f);
660 }
661
662
dumpComplex(FILE * file,int page)663 void HtmlPage::dumpComplex(FILE *file, int page){
664 FILE* pageFile;
665 GooString* tmp;
666 char* htmlEncoding;
667
668 if( firstPage == -1 ) firstPage = page;
669
670 if( !noframes )
671 {
672 GooString* pgNum=GooString::fromInt(page);
673 tmp = new GooString(DocName);
674 if (!singleHtml){
675 tmp->append('-')->append(pgNum)->append(".html");
676 pageFile = fopen(tmp->getCString(), "w");
677 } else {
678 tmp->append("-html")->append(".html");
679 pageFile = fopen(tmp->getCString(), "a");
680 }
681 delete pgNum;
682 if (!pageFile) {
683 error(-1, "Couldn't open html file '%s'", tmp->getCString());
684 delete tmp;
685 return;
686 }
687
688 if (!singleHtml)
689 fprintf(pageFile,"%s\n<HTML>\n<HEAD>\n<TITLE>Page %d</TITLE>\n\n", DOCTYPE, page);
690 else
691 fprintf(pageFile,"%s\n<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n\n", DOCTYPE, tmp->getCString());
692
693 delete tmp;
694
695 htmlEncoding = HtmlOutputDev::mapEncodingToHtml
696 (globalParams->getTextEncodingName());
697 if (!singleHtml)
698 fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
699 else
700 fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n <br>\n", htmlEncoding);
701 }
702 else
703 {
704 pageFile = file;
705 fprintf(pageFile,"<!-- Page %d -->\n", page);
706 fprintf(pageFile,"<a name=\"%d\"></a>\n", page);
707 }
708
709 fprintf(pageFile,"<DIV style=\"position:relative;width:%d;height:%d;\">\n",
710 pageWidth, pageHeight);
711
712 tmp=basename(DocName);
713
714 fputs("<STYLE type=\"text/css\">\n<!--\n",pageFile);
715 for(int i=fontsPageMarker;i!=fonts->size();i++) {
716 GooString *fontCSStyle;
717 if (!singleHtml)
718 fontCSStyle = fonts->CSStyle(i);
719 else
720 fontCSStyle = fonts->CSStyle(i,page);
721 fprintf(pageFile,"\t%s\n",fontCSStyle->getCString());
722 delete fontCSStyle;
723 }
724
725 fputs("-->\n</STYLE>\n",pageFile);
726
727 if( !noframes )
728 {
729 fputs("</HEAD>\n<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n",pageFile);
730 }
731
732 if( !ignore )
733 {
734 fprintf(pageFile,
735 "<IMG width=\"%d\" height=\"%d\" src=\"%s%03d.%s\" alt=\"background image\">\n",
736 pageWidth, pageHeight, tmp->getCString(),
737 (page-firstPage+1), imgExt->getCString());
738 }
739
740 delete tmp;
741
742 GooString *str, *str1 = NULL;
743 for(HtmlString *tmp1=yxStrings;tmp1;tmp1=tmp1->yxNext){
744 if (tmp1->htext){
745 str=new GooString(tmp1->htext);
746 fprintf(pageFile,
747 "<DIV style=\"position:absolute;top:%d;left:%d\">",
748 xoutRound(tmp1->yMin),
749 xoutRound(tmp1->xMin));
750 fputs("<nobr>",pageFile);
751 if (!singleHtml)
752 str1=fonts->getCSStyle(tmp1->fontpos, str);
753 else
754 str1=fonts->getCSStyle(tmp1->fontpos, str, page);
755 fputs(str1->getCString(),pageFile);
756 delete str;
757 delete str1;
758 fputs("</nobr></DIV>\n",pageFile);
759 }
760 }
761
762 fputs("</DIV>\n", pageFile);
763
764 if( !noframes )
765 {
766 fputs("</BODY>\n</HTML>\n",pageFile);
767 fclose(pageFile);
768 }
769 }
770
771
dump(FILE * f,int pageNum)772 void HtmlPage::dump(FILE *f, int pageNum)
773 {
774 if (complexMode || singleHtml)
775 {
776 if (xml) dumpAsXML(f, pageNum);
777 if (!xml) dumpComplex(f, pageNum);
778 }
779 else
780 {
781 fprintf(f,"<A name=%d></a>",pageNum);
782 // Loop over the list of image names on this page
783 int listlen=HtmlOutputDev::imgList->getLength();
784 for (int i = 0; i < listlen; i++) {
785 GooString *fName= (GooString *)HtmlOutputDev::imgList->del(0);
786 fprintf(f,"<IMG src=\"%s\"><br>\n",fName->getCString());
787 delete fName;
788 }
789 HtmlOutputDev::imgNum=1;
790
791 GooString* str;
792 for(HtmlString *tmp=yxStrings;tmp;tmp=tmp->yxNext){
793 if (tmp->htext){
794 str=new GooString(tmp->htext);
795 fputs(str->getCString(),f);
796 delete str;
797 fputs("<br>\n",f);
798 }
799 }
800 fputs("<hr>\n",f);
801 }
802 }
803
804
805
clear()806 void HtmlPage::clear() {
807 HtmlString *p1, *p2;
808
809 if (curStr) {
810 delete curStr;
811 curStr = NULL;
812 }
813 for (p1 = yxStrings; p1; p1 = p2) {
814 p2 = p1->yxNext;
815 delete p1;
816 }
817 yxStrings = NULL;
818 xyStrings = NULL;
819 yxCur1 = yxCur2 = NULL;
820
821 if( !noframes )
822 {
823 delete fonts;
824 fonts=new HtmlFontAccu();
825 fontsPageMarker = 0;
826 }
827 else
828 {
829 fontsPageMarker = fonts->size();
830 }
831
832 delete links;
833 links=new HtmlLinks();
834
835
836 }
837
setDocName(char * fname)838 void HtmlPage::setDocName(char *fname){
839 DocName=new GooString(fname);
840 }
841
842 //------------------------------------------------------------------------
843 // HtmlMetaVar
844 //------------------------------------------------------------------------
845
HtmlMetaVar(char * _name,char * _content)846 HtmlMetaVar::HtmlMetaVar(char *_name, char *_content)
847 {
848 name = new GooString(_name);
849 content = new GooString(_content);
850 }
851
~HtmlMetaVar()852 HtmlMetaVar::~HtmlMetaVar()
853 {
854 delete name;
855 delete content;
856 }
857
toString()858 GooString* HtmlMetaVar::toString()
859 {
860 GooString *result = new GooString("<META name=\"");
861 result->append(name);
862 result->append("\" content=\"");
863 result->append(content);
864 result->append("\">");
865 return result;
866 }
867
868 //------------------------------------------------------------------------
869 // HtmlOutputDev
870 //------------------------------------------------------------------------
871
872 static char* HtmlEncodings[][2] = {
873 {"Latin1", "ISO-8859-1"},
874 {NULL, NULL}
875 };
876
877
mapEncodingToHtml(GooString * encoding)878 char* HtmlOutputDev::mapEncodingToHtml(GooString* encoding)
879 {
880 char* enc = encoding->getCString();
881 for(int i = 0; HtmlEncodings[i][0] != NULL; i++)
882 {
883 if( strcmp(enc, HtmlEncodings[i][0]) == 0 )
884 {
885 return HtmlEncodings[i][1];
886 }
887 }
888 return enc;
889 }
890
doFrame(int firstPage)891 void HtmlOutputDev::doFrame(int firstPage){
892 GooString* fName=new GooString(Docname);
893 char* htmlEncoding;
894 fName->append(".html");
895
896 if (!(fContentsFrame = fopen(fName->getCString(), "w"))){
897 error(-1, "Couldn't open html file '%s'", fName->getCString());
898 delete fName;
899 return;
900 }
901
902 delete fName;
903
904 fName=basename(Docname);
905 fputs(DOCTYPE_FRAMES, fContentsFrame);
906 fputs("\n<HTML>",fContentsFrame);
907 fputs("\n<HEAD>",fContentsFrame);
908 fprintf(fContentsFrame,"\n<TITLE>%s</TITLE>",docTitle->getCString());
909 htmlEncoding = mapEncodingToHtml(globalParams->getTextEncodingName());
910 fprintf(fContentsFrame, "\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
911 dumpMetaVars(fContentsFrame);
912 fprintf(fContentsFrame, "</HEAD>\n");
913 fputs("<FRAMESET cols=\"100,*\">\n",fContentsFrame);
914 fprintf(fContentsFrame,"<FRAME name=\"links\" src=\"%s_ind.html\">\n",fName->getCString());
915 fputs("<FRAME name=\"contents\" src=",fContentsFrame);
916 if (complexMode)
917 fprintf(fContentsFrame,"\"%s-%d.html\"",fName->getCString(), firstPage);
918 else
919 fprintf(fContentsFrame,"\"%ss.html\"",fName->getCString());
920
921 fputs(">\n</FRAMESET>\n</HTML>\n",fContentsFrame);
922
923 delete fName;
924 fclose(fContentsFrame);
925 }
926
HtmlOutputDev(char * fileName,char * title,char * author,char * keywords,char * subject,char * date,char * extension,GBool rawOrder,int firstPage,GBool outline)927 HtmlOutputDev::HtmlOutputDev(char *fileName, char *title,
928 char *author, char *keywords, char *subject, char *date,
929 char *extension,
930 GBool rawOrder, int firstPage, GBool outline)
931 {
932 char *htmlEncoding;
933
934 fContentsFrame = NULL;
935 docTitle = new GooString(title);
936 pages = NULL;
937 dumpJPEG=gTrue;
938 //write = gTrue;
939 this->rawOrder = rawOrder;
940 this->doOutline = outline;
941 ok = gFalse;
942 imgNum=1;
943 //this->firstPage = firstPage;
944 //pageNum=firstPage;
945 // open file
946 needClose = gFalse;
947 pages = new HtmlPage(rawOrder, extension);
948
949 glMetaVars = new GooList();
950 glMetaVars->append(new HtmlMetaVar("generator", "pdftohtml 0.36"));
951 if( author ) glMetaVars->append(new HtmlMetaVar("author", author));
952 if( keywords ) glMetaVars->append(new HtmlMetaVar("keywords", keywords));
953 if( date ) glMetaVars->append(new HtmlMetaVar("date", date));
954 if( subject ) glMetaVars->append(new HtmlMetaVar("subject", subject));
955
956 maxPageWidth = 0;
957 maxPageHeight = 0;
958
959 pages->setDocName(fileName);
960 Docname=new GooString (fileName);
961
962 // for non-xml output (complex or simple) with frames generate the left frame
963 if(!xml && !noframes)
964 {
965 if (!singleHtml)
966 {
967 GooString* left=new GooString(fileName);
968 left->append("_ind.html");
969
970 doFrame(firstPage);
971
972 if (!(fContentsFrame = fopen(left->getCString(), "w")))
973 {
974 error(-1, "Couldn't open html file '%s'", left->getCString());
975 delete left;
976 return;
977 }
978 delete left;
979 fputs(DOCTYPE, fContentsFrame);
980 fputs("<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n",fContentsFrame);
981
982 if (doOutline)
983 {
984 GooString *str = basename(Docname);
985 fprintf(fContentsFrame, "<A href=\"%s%s\" target=\"contents\">Outline</a><br>", str->getCString(), complexMode ? "-outline.html" : "s.html#outline");
986 delete str;
987 }
988 }
989 if (!complexMode)
990 { /* not in complex mode */
991
992 GooString* right=new GooString(fileName);
993 right->append("s.html");
994
995 if (!(page=fopen(right->getCString(),"w"))){
996 error(-1, "Couldn't open html file '%s'", right->getCString());
997 delete right;
998 return;
999 }
1000 delete right;
1001 fputs(DOCTYPE, page);
1002 fputs("<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n",page);
1003 }
1004 }
1005
1006 if (noframes) {
1007 if (stout) page=stdout;
1008 else {
1009 GooString* right=new GooString(fileName);
1010 if (!xml) right->append(".html");
1011 if (xml) right->append(".xml");
1012 if (!(page=fopen(right->getCString(),"w"))){
1013 error(-1, "Couldn't open html file '%s'", right->getCString());
1014 delete right;
1015 return;
1016 }
1017 delete right;
1018 }
1019
1020 htmlEncoding = mapEncodingToHtml(globalParams->getTextEncodingName());
1021 if (xml)
1022 {
1023 fprintf(page, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", htmlEncoding);
1024 fputs("<!DOCTYPE pdf2xml SYSTEM \"pdf2xml.dtd\">\n\n", page);
1025 fputs("<pdf2xml>\n",page);
1026 }
1027 else
1028 {
1029 fprintf(page,"%s\n<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n",
1030 DOCTYPE, docTitle->getCString());
1031
1032 fprintf(page, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", htmlEncoding);
1033
1034 dumpMetaVars(page);
1035 fprintf(page,"</HEAD>\n");
1036 fprintf(page,"<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n");
1037 }
1038 }
1039 ok = gTrue;
1040 }
1041
~HtmlOutputDev()1042 HtmlOutputDev::~HtmlOutputDev() {
1043 HtmlFont::clear();
1044
1045 delete Docname;
1046 delete docTitle;
1047
1048 deleteGooList(glMetaVars, HtmlMetaVar);
1049
1050 if (fContentsFrame){
1051 fputs("</BODY>\n</HTML>\n",fContentsFrame);
1052 fclose(fContentsFrame);
1053 }
1054 if (xml) {
1055 fputs("</pdf2xml>\n",page);
1056 fclose(page);
1057 } else
1058 if ( !complexMode || xml || noframes )
1059 {
1060 fputs("</BODY>\n</HTML>\n",page);
1061 fclose(page);
1062 }
1063 if (pages)
1064 delete pages;
1065 }
1066
startPage(int pageNum,GfxState * state)1067 void HtmlOutputDev::startPage(int pageNum, GfxState *state) {
1068 #if 0
1069 if (mode&&!xml){
1070 if (write){
1071 write=gFalse;
1072 GooString* fname=Dirname(Docname);
1073 fname->append("image.log");
1074 if((tin=fopen(getFileNameFromPath(fname->getCString(),fname->getLength()),"w"))==NULL){
1075 printf("Error : can not open %s",fname);
1076 exit(1);
1077 }
1078 delete fname;
1079 // if(state->getRotation()!=0)
1080 // fprintf(tin,"ROTATE=%d rotate %d neg %d neg translate\n",state->getRotation(),state->getX1(),-state->getY1());
1081 // else
1082 fprintf(tin,"ROTATE=%d neg %d neg translate\n",state->getX1(),state->getY1());
1083 }
1084 }
1085 #endif
1086
1087 this->pageNum = pageNum;
1088 GooString *str=basename(Docname);
1089 pages->clear();
1090 if(!noframes)
1091 {
1092 if (fContentsFrame)
1093 {
1094 if (complexMode)
1095 fprintf(fContentsFrame,"<A href=\"%s-%d.html\"",str->getCString(),pageNum);
1096 else
1097 fprintf(fContentsFrame,"<A href=\"%ss.html#%d\"",str->getCString(),pageNum);
1098 fprintf(fContentsFrame," target=\"contents\" >Page %d</a><br>\n",pageNum);
1099 }
1100 }
1101
1102 pages->pageWidth=static_cast<int>(state->getPageWidth());
1103 pages->pageHeight=static_cast<int>(state->getPageHeight());
1104
1105 delete str;
1106 }
1107
1108
endPage()1109 void HtmlOutputDev::endPage() {
1110 Links *linksList = docPage->getLinks(catalog);
1111 for (int i = 0; i < linksList->getNumLinks(); ++i)
1112 {
1113 doProcessLink(linksList->getLink(i));
1114 }
1115 delete linksList;
1116
1117 pages->conv();
1118 pages->coalesce();
1119 pages->dump(page, pageNum);
1120
1121 // I don't yet know what to do in the case when there are pages of different
1122 // sizes and we want complex output: running ghostscript many times
1123 // seems very inefficient. So for now I'll just use last page's size
1124 maxPageWidth = pages->pageWidth;
1125 maxPageHeight = pages->pageHeight;
1126
1127 //if(!noframes&&!xml) fputs("<br>\n", fContentsFrame);
1128 if(!stout && !globalParams->getErrQuiet()) printf("Page-%d\n",(pageNum));
1129 }
1130
updateFont(GfxState * state)1131 void HtmlOutputDev::updateFont(GfxState *state) {
1132 pages->updateFont(state);
1133 }
1134
beginString(GfxState * state,GooString * s)1135 void HtmlOutputDev::beginString(GfxState *state, GooString *s) {
1136 pages->beginString(state, s);
1137 }
1138
endString(GfxState * state)1139 void HtmlOutputDev::endString(GfxState *state) {
1140 pages->endString();
1141 }
1142
drawChar(GfxState * state,double x,double y,double dx,double dy,double originX,double originY,CharCode code,int,Unicode * u,int uLen)1143 void HtmlOutputDev::drawChar(GfxState *state, double x, double y,
1144 double dx, double dy,
1145 double originX, double originY,
1146 CharCode code, int /*nBytes*/, Unicode *u, int uLen)
1147 {
1148 if ( !showHidden && (state->getRender() & 3) == 3) {
1149 return;
1150 }
1151 pages->addChar(state, x, y, dx, dy, originX, originY, u, uLen);
1152 }
1153
drawImageMask(GfxState * state,Object * ref,Stream * str,int width,int height,GBool invert,GBool interpolate,GBool inlineImg)1154 void HtmlOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1155 int width, int height, GBool invert,
1156 GBool interpolate, GBool inlineImg) {
1157
1158 if (ignore||complexMode) {
1159 OutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
1160 return;
1161 }
1162
1163 FILE *f1;
1164 int c;
1165
1166 int x0, y0; // top left corner of image
1167 int w0, h0, w1, h1; // size of image
1168 double xt, yt, wt, ht;
1169 GBool rotate, xFlip, yFlip;
1170
1171 // get image position and size
1172 state->transform(0, 0, &xt, &yt);
1173 state->transformDelta(1, 1, &wt, &ht);
1174 if (wt > 0) {
1175 x0 = xoutRound(xt);
1176 w0 = xoutRound(wt);
1177 } else {
1178 x0 = xoutRound(xt + wt);
1179 w0 = xoutRound(-wt);
1180 }
1181 if (ht > 0) {
1182 y0 = xoutRound(yt);
1183 h0 = xoutRound(ht);
1184 } else {
1185 y0 = xoutRound(yt + ht);
1186 h0 = xoutRound(-ht);
1187 }
1188 state->transformDelta(1, 0, &xt, &yt);
1189 rotate = fabs(xt) < fabs(yt);
1190 if (rotate) {
1191 w1 = h0;
1192 h1 = w0;
1193 xFlip = ht < 0;
1194 yFlip = wt > 0;
1195 } else {
1196 w1 = w0;
1197 h1 = h0;
1198 xFlip = wt < 0;
1199 yFlip = ht > 0;
1200 }
1201
1202 // dump JPEG file
1203 if (dumpJPEG && str->getKind() == strDCT) {
1204 GooString *fName=new GooString(Docname);
1205 fName->append("-");
1206 GooString *pgNum=GooString::fromInt(pageNum);
1207 GooString *imgnum=GooString::fromInt(imgNum);
1208 // open the image file
1209 fName->append(pgNum)->append("_")->append(imgnum)->append(".jpg");
1210 delete pgNum;
1211 delete imgnum;
1212
1213 ++imgNum;
1214 if (!(f1 = fopen(fName->getCString(), "wb"))) {
1215 error(-1, "Couldn't open image file '%s'", fName->getCString());
1216 delete fName;
1217 return;
1218 }
1219
1220 // initialize stream
1221 str = ((DCTStream *)str)->getRawStream();
1222 str->reset();
1223
1224 // copy the stream
1225 while ((c = str->getChar()) != EOF)
1226 fputc(c, f1);
1227
1228 fclose(f1);
1229
1230 if (fName) imgList->append(fName);
1231 }
1232 else {
1233 OutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
1234 }
1235 }
1236
drawImage(GfxState * state,Object * ref,Stream * str,int width,int height,GfxImageColorMap * colorMap,GBool interpolate,int * maskColors,GBool inlineImg)1237 void HtmlOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1238 int width, int height, GfxImageColorMap *colorMap,
1239 GBool interpolate, int *maskColors, GBool inlineImg) {
1240
1241 if (ignore||complexMode) {
1242 OutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate,
1243 maskColors, inlineImg);
1244 return;
1245 }
1246
1247 FILE *f1;
1248 int c;
1249
1250 int x0, y0; // top left corner of image
1251 int w0, h0, w1, h1; // size of image
1252 double xt, yt, wt, ht;
1253 GBool rotate, xFlip, yFlip;
1254
1255 // get image position and size
1256 state->transform(0, 0, &xt, &yt);
1257 state->transformDelta(1, 1, &wt, &ht);
1258 if (wt > 0) {
1259 x0 = xoutRound(xt);
1260 w0 = xoutRound(wt);
1261 } else {
1262 x0 = xoutRound(xt + wt);
1263 w0 = xoutRound(-wt);
1264 }
1265 if (ht > 0) {
1266 y0 = xoutRound(yt);
1267 h0 = xoutRound(ht);
1268 } else {
1269 y0 = xoutRound(yt + ht);
1270 h0 = xoutRound(-ht);
1271 }
1272 state->transformDelta(1, 0, &xt, &yt);
1273 rotate = fabs(xt) < fabs(yt);
1274 if (rotate) {
1275 w1 = h0;
1276 h1 = w0;
1277 xFlip = ht < 0;
1278 yFlip = wt > 0;
1279 } else {
1280 w1 = w0;
1281 h1 = h0;
1282 xFlip = wt < 0;
1283 yFlip = ht > 0;
1284 }
1285
1286
1287 /*if( !globalParams->getErrQuiet() )
1288 printf("image stream of kind %d\n", str->getKind());*/
1289 // dump JPEG file
1290 if (dumpJPEG && str->getKind() == strDCT) {
1291 GooString *fName=new GooString(Docname);
1292 fName->append("-");
1293 GooString *pgNum= GooString::fromInt(pageNum);
1294 GooString *imgnum= GooString::fromInt(imgNum);
1295
1296 // open the image file
1297 fName->append(pgNum)->append("_")->append(imgnum)->append(".jpg");
1298 delete pgNum;
1299 delete imgnum;
1300
1301 ++imgNum;
1302
1303 if (!(f1 = fopen(fName->getCString(), "wb"))) {
1304 error(-1, "Couldn't open image file '%s'", fName->getCString());
1305 delete fName;
1306 return;
1307 }
1308
1309 // initialize stream
1310 str = ((DCTStream *)str)->getRawStream();
1311 str->reset();
1312
1313 // copy the stream
1314 while ((c = str->getChar()) != EOF)
1315 fputc(c, f1);
1316
1317 fclose(f1);
1318
1319 if (fName) imgList->append(fName);
1320 }
1321 else {
1322 #ifdef ENABLE_LIBPNG
1323 // Dump the image as a PNG file. Much of the PNG code
1324 // comes from an example by Guillaume Cottenceau.
1325 Guchar *p;
1326 GfxRGB rgb;
1327 png_byte *row = (png_byte *) malloc(3 * width); // 3 bytes/pixel: RGB
1328 png_bytep *row_pointer= &row;
1329
1330 // Create the image filename
1331 GooString *fName=new GooString(Docname);
1332 fName->append("-");
1333 GooString *pgNum= GooString::fromInt(pageNum);
1334 GooString *imgnum= GooString::fromInt(imgNum);
1335 fName->append(pgNum)->append("_")->append(imgnum)->append(".png");
1336 delete pgNum;
1337 delete imgnum;
1338
1339 // Open the image file
1340 if (!(f1 = fopen(fName->getCString(), "wb"))) {
1341 error(-1, "Couldn't open image file '%s'", fName->getCString());
1342 delete fName;
1343 return;
1344 }
1345
1346 PNGWriter *writer = new PNGWriter();
1347 // TODO can we calculate the resolution of the image?
1348 if (!writer->init(f1, width, height, 72, 72)) {
1349 delete writer;
1350 fclose(f1);
1351 return;
1352 }
1353
1354 // Initialize the image stream
1355 ImageStream *imgStr = new ImageStream(str, width,
1356 colorMap->getNumPixelComps(), colorMap->getBits());
1357 imgStr->reset();
1358
1359 // For each line...
1360 for (int y = 0; y < height; y++) {
1361
1362 // Convert into a PNG row
1363 p = imgStr->getLine();
1364 for (int x = 0; x < width; x++) {
1365 colorMap->getRGB(p, &rgb);
1366 // Write the RGB pixels into the row
1367 row[3*x]= colToByte(rgb.r);
1368 row[3*x+1]= colToByte(rgb.g);
1369 row[3*x+2]= colToByte(rgb.b);
1370 p += colorMap->getNumPixelComps();
1371 }
1372
1373 if (!writer->writeRow(row_pointer)) {
1374 delete writer;
1375 fclose(f1);
1376 return;
1377 }
1378 }
1379
1380 writer->close();
1381 delete writer;
1382 fclose(f1);
1383
1384 free(row);
1385 imgList->append(fName);
1386 ++imgNum;
1387 imgStr->close();
1388 delete imgStr;
1389 #else
1390 OutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate,
1391 maskColors, inlineImg);
1392 #endif
1393 }
1394 }
1395
1396
1397
doProcessLink(Link * link)1398 void HtmlOutputDev::doProcessLink(Link* link){
1399 double _x1,_y1,_x2,_y2;
1400 int x1,y1,x2,y2;
1401
1402 link->getRect(&_x1,&_y1,&_x2,&_y2);
1403 cvtUserToDev(_x1,_y1,&x1,&y1);
1404
1405 cvtUserToDev(_x2,_y2,&x2,&y2);
1406
1407
1408 GooString* _dest=getLinkDest(link,catalog);
1409 HtmlLink t((double) x1,(double) y2,(double) x2,(double) y1,_dest);
1410 pages->AddLink(t);
1411 delete _dest;
1412 }
1413
getLinkDest(Link * link,Catalog * catalog)1414 GooString* HtmlOutputDev::getLinkDest(Link *link,Catalog* catalog){
1415 char *p;
1416 switch(link->getAction()->getKind())
1417 {
1418 case actionGoTo:
1419 {
1420 GooString* file=basename(Docname);
1421 int page=1;
1422 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1423 LinkDest *dest=NULL;
1424 if (ha->getDest()!=NULL)
1425 dest=ha->getDest()->copy();
1426 else if (ha->getNamedDest()!=NULL)
1427 dest=catalog->findDest(ha->getNamedDest());
1428
1429 if (dest){
1430 if (dest->isPageRef()){
1431 Ref pageref=dest->getPageRef();
1432 page=catalog->findPage(pageref.num,pageref.gen);
1433 }
1434 else {
1435 page=dest->getPageNum();
1436 }
1437
1438 delete dest;
1439
1440 GooString *str=GooString::fromInt(page);
1441 /* complex simple
1442 frames file-4.html files.html#4
1443 noframes file.html#4 file.html#4
1444 */
1445 if (noframes)
1446 {
1447 file->append(".html#");
1448 file->append(str);
1449 }
1450 else
1451 {
1452 if( complexMode )
1453 {
1454 file->append("-");
1455 file->append(str);
1456 file->append(".html");
1457 }
1458 else
1459 {
1460 file->append("s.html#");
1461 file->append(str);
1462 }
1463 }
1464
1465 if (printCommands) printf(" link to page %d ",page);
1466 delete str;
1467 return file;
1468 }
1469 else
1470 {
1471 return new GooString();
1472 }
1473 }
1474 case actionGoToR:
1475 {
1476 LinkGoToR *ha=(LinkGoToR *) link->getAction();
1477 LinkDest *dest=NULL;
1478 int page=1;
1479 GooString *file=new GooString();
1480 if (ha->getFileName()){
1481 delete file;
1482 file=new GooString(ha->getFileName()->getCString());
1483 }
1484 if (ha->getDest()!=NULL) dest=ha->getDest()->copy();
1485 if (dest&&file){
1486 if (!(dest->isPageRef())) page=dest->getPageNum();
1487 delete dest;
1488
1489 if (printCommands) printf(" link to page %d ",page);
1490 if (printHtml){
1491 p=file->getCString()+file->getLength()-4;
1492 if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")){
1493 file->del(file->getLength()-4,4);
1494 file->append(".html");
1495 }
1496 file->append('#');
1497 file->append(GooString::fromInt(page));
1498 }
1499 }
1500 if (printCommands && file) printf("filename %s\n",file->getCString());
1501 return file;
1502 }
1503 case actionURI:
1504 {
1505 LinkURI *ha=(LinkURI *) link->getAction();
1506 GooString* file=new GooString(ha->getURI()->getCString());
1507 // printf("uri : %s\n",file->getCString());
1508 return file;
1509 }
1510 case actionLaunch:
1511 {
1512 LinkLaunch *ha=(LinkLaunch *) link->getAction();
1513 GooString* file=new GooString(ha->getFileName()->getCString());
1514 if (printHtml) {
1515 p=file->getCString()+file->getLength()-4;
1516 if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")){
1517 file->del(file->getLength()-4,4);
1518 file->append(".html");
1519 }
1520 if (printCommands) printf("filename %s",file->getCString());
1521
1522 return file;
1523
1524 }
1525 }
1526 default:
1527 return new GooString();
1528 }
1529 }
1530
dumpMetaVars(FILE * file)1531 void HtmlOutputDev::dumpMetaVars(FILE *file)
1532 {
1533 GooString *var;
1534
1535 for(int i = 0; i < glMetaVars->getLength(); i++)
1536 {
1537 HtmlMetaVar *t = (HtmlMetaVar*)glMetaVars->get(i);
1538 var = t->toString();
1539 fprintf(file, "%s\n", var->getCString());
1540 delete var;
1541 }
1542 }
1543
dumpDocOutline(Catalog * catalog)1544 GBool HtmlOutputDev::dumpDocOutline(Catalog* catalog)
1545 {
1546 FILE * output = NULL;
1547 GBool bClose = gFalse;
1548
1549 if (!ok || xml)
1550 return gFalse;
1551
1552 Object *outlines = catalog->getOutline();
1553 if (!outlines->isDict())
1554 return gFalse;
1555
1556 if (!complexMode && !xml)
1557 {
1558 output = page;
1559 }
1560 else if (complexMode && !xml)
1561 {
1562 if (noframes)
1563 {
1564 output = page;
1565 fputs("<hr>\n", output);
1566 }
1567 else
1568 {
1569 GooString *str = Docname->copy();
1570 str->append("-outline.html");
1571 output = fopen(str->getCString(), "w");
1572 if (output == NULL)
1573 return gFalse;
1574 delete str;
1575 bClose = gTrue;
1576 fputs("<HTML>\n<HEAD>\n<TITLE>Document Outline</TITLE>\n</HEAD>\n<BODY>\n", output);
1577 }
1578 }
1579
1580 GBool done = newOutlineLevel(output, outlines, catalog);
1581 if (done && !complexMode)
1582 fputs("<hr>\n", output);
1583
1584 if (bClose)
1585 {
1586 fputs("</BODY>\n</HTML>\n", output);
1587 fclose(output);
1588 }
1589 return done;
1590 }
1591
newOutlineLevel(FILE * output,Object * node,Catalog * catalog,int level)1592 GBool HtmlOutputDev::newOutlineLevel(FILE *output, Object *node, Catalog* catalog, int level)
1593 {
1594 Object curr, next;
1595 GBool atLeastOne = gFalse;
1596
1597 if (node->dictLookup("First", &curr)->isDict()) {
1598 if (level == 1)
1599 {
1600 fputs("<A name=\"outline\"></a>", output);
1601 fputs("<h1>Document Outline</h1>\n", output);
1602 }
1603 fputs("<ul>",output);
1604 do {
1605 // get title, give up if not found
1606 Object title;
1607 if (curr.dictLookup("Title", &title)->isNull()) {
1608 title.free();
1609 break;
1610 }
1611 GooString *titleStr = new GooString(title.getString());
1612 title.free();
1613
1614 // get corresponding link
1615 // Note: some code duplicated from HtmlOutputDev::getLinkDest().
1616 GooString *linkName = NULL;;
1617 Object dest;
1618 if (!curr.dictLookup("Dest", &dest)->isNull()) {
1619 LinkGoTo *link = new LinkGoTo(&dest);
1620 LinkDest *linkdest=NULL;
1621 if (link->getDest()!=NULL)
1622 linkdest=link->getDest()->copy();
1623 else if (link->getNamedDest()!=NULL)
1624 linkdest=catalog->findDest(link->getNamedDest());
1625
1626 delete link;
1627 if (linkdest) {
1628 int page;
1629 if (linkdest->isPageRef()) {
1630 Ref pageref=linkdest->getPageRef();
1631 page=catalog->findPage(pageref.num,pageref.gen);
1632 } else {
1633 page=linkdest->getPageNum();
1634 }
1635 delete linkdest;
1636
1637 /* complex simple
1638 frames file-4.html files.html#4
1639 noframes file.html#4 file.html#4
1640 */
1641 linkName=basename(Docname);
1642 GooString *str=GooString::fromInt(page);
1643 if (noframes) {
1644 linkName->append(".html#");
1645 linkName->append(str);
1646 } else {
1647 if( complexMode ) {
1648 linkName->append("-");
1649 linkName->append(str);
1650 linkName->append(".html");
1651 } else {
1652 linkName->append("s.html#");
1653 linkName->append(str);
1654 }
1655 }
1656 delete str;
1657 }
1658 }
1659 dest.free();
1660
1661 fputs("<li>",output);
1662 if (linkName)
1663 fprintf(output,"<A href=\"%s\">", linkName->getCString());
1664 fputs(titleStr->getCString(),output);
1665 if (linkName) {
1666 fputs("</A>",output);
1667 delete linkName;
1668 }
1669 fputs("\n",output);
1670 delete titleStr;
1671 atLeastOne = gTrue;
1672
1673 newOutlineLevel(output, &curr, catalog, level+1);
1674 curr.dictLookup("Next", &next);
1675 curr.free();
1676 curr = next;
1677 } while(curr.isDict());
1678 fputs("</ul>",output);
1679 }
1680 curr.free();
1681
1682 return atLeastOne;
1683 }
1684