source: trunk/Lucide/SOURCE/plugins/lupoppler/lupoppler.cpp @ 31

Last change on this file since 31 was 31, checked in by Eugene Romanenko, 15 years ago

Use libjpeg for poppler, instead of internal decoder. Looks like libjpeg little bit faster.

File size: 41.1 KB
Line 
1
2/*
3 *  This file was generated by the SOM Compiler.
4 *  Generated using:
5 *     SOM incremental update: 2.24
6 */
7
8
9/*
10 *  This file was generated by the SOM Compiler and Emitter Framework.
11 *  Generated using template emitter:
12 *      SOM Emitter emitxtm: 2.23.1.9
13 */
14
15#ifndef SOM_Module_lupoppler_Source
16#define SOM_Module_lupoppler_Source
17#endif
18#define LuPopplerDocument_Class_Source
19
20#include "lupoppler.xih"
21
22#include <goo\GooString.h>
23#include <goo\GooList.h>
24#include <splash\SplashBitmap.h>
25#include <UGooString.h>
26#include <GlobalParams.h>
27#include <ErrorCodes.h>
28#include <PDFDoc.h>
29#include <SplashOutputDev.h>
30#include <TextOutputDev.h>
31#include <PSOutputDev.h>
32#include <FontInfo.h>
33#include <Outline.h>
34#include <UnicodeMap.h>
35#include <Gfx.h>
36#include <Link.h>
37
38#define INCL_DOS
39#include <os2.h>
40
41#include <vector>
42using namespace std;
43#include <time.h>
44#include "cpconv.h"
45
46typedef vector<LuRectangle> RectList;
47
48
49unsigned _System LibMain( unsigned hmod, unsigned termination )
50{
51    if ( termination ) {
52        /* DLL is detaching from process */
53    } else {
54        /* DLL is attaching to process */
55    }
56    return( 1 );
57}
58
59
60extern "C" LuDocument * _System createObject()
61{
62    return new LuPopplerDocument;
63}
64
65extern "C" char * _System getSupportedExtensions()
66{
67    return "PDF";
68}
69
70extern "C" char * _System getDescription()
71{
72    return "PDF plugin, based on poppler library.";
73}
74
75
76class PopplerPage
77{
78    public:
79
80        Page *page;
81        TextOutputDev *text_dev;
82        Gfx *gfx;
83
84        PopplerPage();
85        ~PopplerPage();
86};
87
88PopplerPage::PopplerPage()
89{
90    page = NULL;
91    text_dev = NULL;
92    gfx = NULL;
93}
94
95PopplerPage::~PopplerPage()
96{
97    delete text_dev;
98    delete gfx;
99}
100
101
102class PopplerDocument
103{
104    public:
105
106        PDFDoc *doc;
107        SplashOutputDev *output_dev;
108        PopplerPage *pages;
109        char *text;
110        HMTX mutex;
111
112        PopplerDocument();
113        ~PopplerDocument();
114};
115
116PopplerDocument::PopplerDocument()
117{
118    doc        = NULL;
119    output_dev = NULL;
120    pages      = NULL;
121    text       = NULL;
122    mutex      = NULLHANDLE;
123    DosCreateMutexSem( NULL, &mutex, 0, FALSE );
124}
125
126PopplerDocument::~PopplerDocument()
127{
128    delete [] pages;
129    delete doc;
130    delete output_dev;
131    delete text;
132    DosCloseMutexSem( mutex );
133}
134
135
136static char *newstrdup( const char *s )
137{
138    if ( s == NULL ) {
139        return NULL;
140    }
141    char *temp = new char[ strlen( s ) + 1 ];
142    strcpy( temp, s );
143    return temp;
144}
145
146static char *somstrdup( const char *s )
147{
148    if ( s == NULL ) {
149        return NULL;
150    }
151    char *temp = (char *)SOMMalloc( strlen( s ) + 1 );
152    strcpy( temp, s );
153    return temp;
154}
155
156
157SOM_Scope short  SOMLINK getBpp(LuPopplerDocument *somSelf,  Environment *ev)
158{
159    return 4;
160}
161
162SOM_Scope boolean  SOMLINK isScalable(LuPopplerDocument *somSelf,
163                                       Environment *ev)
164{
165    return TRUE;
166}
167
168
169SOM_Scope boolean  SOMLINK isRotable(LuPopplerDocument *somSelf,
170                                      Environment *ev)
171{
172    return TRUE;
173}
174
175
176SOM_Scope long  SOMLINK getPageCount(LuPopplerDocument *somSelf,
177                                      Environment *ev)
178{
179    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
180    return ((PopplerDocument *)somThis->data)->doc->getNumPages();
181}
182
183
184SOM_Scope void  SOMLINK getPageSize(LuPopplerDocument *somSelf,
185                                    Environment *ev, long pagenum,
186                                    double* width, double* height)
187{
188    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
189
190    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
191
192    double page_width, page_height;
193    int rotate = page->getRotate();
194    if ( rotate == 90 || rotate == 270 ) {
195        page_height = page->getCropWidth();
196        page_width = page->getCropHeight();
197    } else {
198        page_width = page->getCropWidth();
199        page_height = page->getCropHeight();
200    }
201
202    if ( width != NULL ) {
203        *width = page_width;
204    }
205    if ( height != NULL ) {
206        *height = page_height;
207    }
208}
209
210
211static void copy_page_to_pixbuf( Environment *ev, SplashBitmap *bitmap, LuPixbuf *pixbuf )
212{
213    int splash_width, splash_height, splash_rowstride;
214    int pixbuf_rowstride, pixbuf_height, pixbuf_width;
215    int height, width, rowstride;
216    char *pixbuf_data, *dst, *src;
217
218    SplashColorPtr color_ptr = bitmap->getDataPtr();
219
220    splash_width = bitmap->getWidth();
221    splash_height = bitmap->getHeight();
222    splash_rowstride = bitmap->getRowSize();
223
224    //somPrintf( "splash_width: %d   splash_height: %d   splash_rowstride: %d\n",
225    //            splash_width, splash_height, splash_rowstride );
226
227    pixbuf_data = (char *)pixbuf->getDataPtr( ev );
228    pixbuf_width = pixbuf->getWidth( ev );
229    pixbuf_height = pixbuf->getHeight( ev );
230    pixbuf_rowstride = pixbuf->getRowSize( ev );
231
232    width = __min( splash_width, pixbuf_width );
233    height = __min( splash_height, pixbuf_height );
234    rowstride = __min( splash_rowstride, pixbuf_rowstride );
235
236    int i, j;
237    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
238    {
239        dst = pixbuf_data + i * pixbuf_rowstride;
240        src = ((char *)color_ptr) + j * splash_rowstride;
241        memcpy( dst, src, rowstride );
242    }
243
244    // test
245    //memcpy( pixbuf_data, color_ptr, pixbuf->getDataLen( ev ) );
246}
247
248
249SOM_Scope void  SOMLINK renderPageToPixbuf(LuPopplerDocument *somSelf,
250                                            Environment *ev,
251                                           long pagenum, long src_x,
252                                           long src_y, long src_width,
253                                           long src_height, double scale,
254                                           long rotation, LuPixbuf* pixbuf)
255{
256    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
257    PopplerDocument *document = (PopplerDocument *)somThis->data;
258    Page *page = document->pages[ pagenum ].page;
259
260    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
261        return;
262    }
263
264    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
265
266    page->displaySlice( document->output_dev,
267                72.0 * scale, 72.0 * scale,
268                rotation,
269                gFalse, /* useMediaBox */
270                gTrue, /* Crop */
271                src_x, src_y,
272                src_width, src_height,
273                NULL, /* links */
274                document->doc->getCatalog() );
275
276    DosReleaseMutexSem( document->mutex );
277
278    copy_page_to_pixbuf( ev, document->output_dev->getBitmap(), pixbuf );
279}
280
281
282SOM_Scope boolean  SOMLINK isAsynchRenderingSupported(LuPopplerDocument *somSelf,
283                                                       Environment *ev)
284{
285    return TRUE;
286}
287
288
289struct asynchCallbackData
290{
291    Environment      *ev;
292    LuPixbuf         *pixbuf;
293    SplashBitmap     *bitmap;
294    void             *fndata;
295    _asynchCallbackFn fnd;
296    _asynchCallbackFn fna;
297    long              tmr;
298    bool              forceDraw;
299    long              delay;
300};
301
302static GBool abortCheckCbk( void *data )
303{
304    long now;
305    asynchCallbackData *cd = (asynchCallbackData *)data;
306    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &now, sizeof( long ) );
307    long dist = ( now - cd->tmr );
308    if ( ( dist > cd->delay ) || cd->forceDraw ) {
309        copy_page_to_pixbuf( cd->ev, cd->bitmap, cd->pixbuf );
310        cd->fnd( cd->fndata );
311        cd->tmr = now;
312        cd->delay += 100;
313    }
314    return (GBool)cd->fna( cd->fndata );
315}
316
317SOM_Scope void  SOMLINK renderPageToPixbufAsynch(LuPopplerDocument *somSelf,
318                                                  Environment *ev,
319                                                 long pagenum,
320                                                 long src_x,
321                                                 long src_y,
322                                                 long src_width,
323                                                 long src_height,
324                                                 double scale,
325                                                 long rotation,
326                                                 LuPixbuf* pixbuf,
327                                                 LuDocument_asynchCallbackFn fnd,
328                                                 LuDocument_asynchCallbackFn fna,
329                                                 somToken fndata)
330{
331    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
332    PopplerDocument *document = (PopplerDocument *)somThis->data;
333    Page *page = document->pages[ pagenum ].page;
334
335    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
336        return;
337    }
338
339    asynchCallbackData acd;
340    acd.ev        = ev;
341    acd.pixbuf    = pixbuf;
342    acd.bitmap    = document->output_dev->getBitmap();
343    acd.fndata    = fndata;
344    acd.fnd       = (_asynchCallbackFn)fnd;
345    acd.fna       = (_asynchCallbackFn)fna;
346    acd.forceDraw = false;
347    acd.delay     = 200;
348    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &acd.tmr, sizeof( long ) );
349
350    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
351
352    //somPrintf( "src_x: %d, src_y: %d, src_width: %d, src_height: %d\n",
353    //           src_x, src_y, src_width, src_height );
354
355    page->displaySlice( document->output_dev,
356                72.0 * scale, 72.0 * scale,
357                rotation,
358                gFalse, /* useMediaBox */
359                gTrue, /* Crop */
360                src_x, src_y,
361                src_width, src_height,
362                NULL, /* links */
363                document->doc->getCatalog(),
364                abortCheckCbk, &acd );
365    DosReleaseMutexSem( document->mutex );
366
367    acd.forceDraw = true;
368    abortCheckCbk( &acd );
369}
370
371static TextOutputDev *get_text_output_dev( PopplerPage *page,
372                                           PopplerDocument *document )
373{
374    if ( page->text_dev == NULL )
375    {
376        DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
377        page->text_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
378
379        page->gfx = page->page->createGfx(page->text_dev,
380                          72.0, 72.0, 0,
381                          gFalse, /* useMediaBox */
382                          gTrue, /* Crop */
383                          -1, -1, -1, -1,
384                          NULL, /* links */
385                          document->doc->getCatalog(),
386                          NULL, NULL, NULL, NULL);
387
388        page->page->display( page->gfx );
389        page->text_dev->endPage();
390        DosReleaseMutexSem( document->mutex );
391    }
392
393    return page->text_dev;
394}
395
396
397SOM_Scope LuDocument_LuRectSequence*  SOMLINK getSelectionRectangles(LuPopplerDocument *somSelf,
398                                                                    Environment *ev,
399                                                                   long pagenum,
400                                                                   double scale,
401                                                                   LuRectangle* selection)
402{
403    LuDocument_LuRectSequence *rectangles = NULL;
404
405    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
406    PopplerDocument *document = (PopplerDocument *)somThis->data;
407    PopplerPage *page = &( document->pages[ pagenum ] );
408
409    TextOutputDev *text_dev = get_text_output_dev( page, document );
410
411    PDFRectangle poppler_selection;
412    poppler_selection.x1 = selection->x1;
413    poppler_selection.y1 = selection->y1;
414    poppler_selection.x2 = selection->x2;
415    poppler_selection.y2 = selection->y2;
416
417    GooList *list = text_dev->getSelectionRegion( &poppler_selection, scale );
418    int len = list->getLength();
419
420    if ( len > 0 )
421    {
422        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
423        rectangles->_maximum = len;
424        rectangles->_length = len;
425        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
426
427        for ( int i = 0; i < len; i++ )
428        {
429            PDFRectangle *selection_rect = (PDFRectangle *)list->get( i );
430            rectangles->_buffer[ i ].x1 = selection_rect->x1;
431            rectangles->_buffer[ i ].y1 = selection_rect->y1;
432            rectangles->_buffer[ i ].x2 = selection_rect->x2;
433            rectangles->_buffer[ i ].y2 = selection_rect->y2;
434            delete selection_rect;
435        }
436    }
437    delete list;
438
439    return rectangles;
440}
441
442
443SOM_Scope boolean  SOMLINK isHaveText(LuPopplerDocument *somSelf,
444                                      Environment *ev)
445{
446    return TRUE;
447}
448
449
450SOM_Scope string  SOMLINK getText(LuPopplerDocument *somSelf,
451                                   Environment *ev, long pagenum,
452                                  LuRectangle* selection)
453{
454    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
455
456    if ( selection == NULL ) {
457        return NULL;
458    }
459
460    PopplerDocument *document = (PopplerDocument *)somThis->data;
461    PopplerPage *page = &( document->pages[ pagenum ] );
462
463    TextOutputDev *text_dev = get_text_output_dev( page, document );
464
465    GooString *sel_text = new GooString;
466    char *result;
467    PDFRectangle pdf_selection;
468
469    pdf_selection.x1 = selection->x1;
470    pdf_selection.y1 = selection->y1;
471    pdf_selection.x2 = selection->x2;
472    pdf_selection.y2 = selection->y2;
473
474    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
475    sel_text = text_dev->getSelectionText( &pdf_selection );
476
477    delete document->text;
478    document->text = newstrdup( sel_text->getCString() );
479    delete sel_text;
480    DosReleaseMutexSem( document->mutex );
481
482    return document->text;
483}
484
485
486SOM_Scope boolean  SOMLINK isHaveLinks(LuPopplerDocument *somSelf,
487                                        Environment *ev)
488{
489    return TRUE;
490}
491
492
493static long find_dest_page( PDFDoc *doc, LinkDest *link_dest )
494{
495    long page_num = 0;
496
497    if ( link_dest == NULL ) {
498        return page_num;
499    }
500
501    if ( link_dest->isPageRef() )
502    {
503        Ref page_ref = link_dest->getPageRef();
504        page_num = doc->findPage( page_ref.num, page_ref.gen ) - 1;
505    }
506    else {
507        page_num = link_dest->getPageNum() - 1;
508    }
509
510    return page_num;
511}
512
513static void build_goto_dest( PDFDoc *doc, LuLink *evlink, LinkGoTo *link )
514{
515    LinkDest *link_dest;
516    UGooString *named_dest;
517
518    if ( !link->isOk() ) {
519        return;
520    }
521
522    link_dest = link->getDest();
523    named_dest = link->getNamedDest();
524
525    if ( link_dest != NULL ) {
526        evlink->page = find_dest_page( doc, link_dest );
527    } else if ( named_dest != NULL ) {
528        link_dest = doc->findDest( named_dest );
529        evlink->page = find_dest_page( doc, link_dest );
530        delete link_dest;
531    } else {
532        evlink->page = 0;
533    }
534}
535
536static void build_link( PDFDoc *doc, LuLink *evlink,
537                        const char *title, LinkAction *link_action )
538{
539    evlink->title = somstrdup( title );
540    evlink->uri = NULL;
541    evlink->type = LU_LINK_TYPE_TITLE;
542    evlink->page = 0;
543
544    if ( link_action == NULL ) {
545        return;
546    }
547
548    switch ( link_action->getKind() )
549    {
550        case actionGoTo:
551            {
552                evlink->type = LU_LINK_TYPE_PAGE;
553                LinkGoTo *lgt = dynamic_cast <LinkGoTo *> (link_action);
554                build_goto_dest( doc, evlink, lgt );
555            }
556            break;
557
558        case actionURI:
559            {
560                evlink->type = LU_LINK_TYPE_EXTERNAL_URI;
561                LinkURI *lu = dynamic_cast <LinkURI *> (link_action);
562                char *uri = lu->getURI()->getCString();
563                if ( uri != NULL ) {
564                    evlink->uri = somstrdup( uri );
565                }
566            }
567            break;
568    }
569}
570
571SOM_Scope LuDocument_LuLinkMapSequence*  SOMLINK getLinkMapping(LuPopplerDocument *somSelf,
572                                                                 Environment *ev,
573                                                                long pagenum)
574{
575    LuDocument_LuLinkMapSequence *mapping = NULL;
576
577    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
578    PopplerDocument *document = (PopplerDocument *)somThis->data;
579    PopplerPage *page = &( document->pages[ pagenum ] );
580
581    Object obj;
582    Links *links = new Links( page->page->getAnnots( &obj ),
583                            document->doc->getCatalog()->getBaseURI() );
584    obj.free();
585
586    if ( links == NULL ) {
587        return NULL;
588    }
589
590    double height = 0;
591    getPageSize( somSelf, ev, pagenum, NULL, &height );
592
593    int len = links->getNumLinks();
594
595    if ( len > 0 )
596    {
597        mapping = (LuDocument_LuLinkMapSequence *)SOMMalloc( sizeof( LuDocument_LuLinkMapSequence ) );
598        mapping->_maximum = len;
599        mapping->_length = len;
600        mapping->_buffer = (LuLinkMapping *)SOMMalloc( sizeof( LuLinkMapping ) * len );
601
602        for ( int i = 0; i < len; i++ )
603        {
604            Link *link = links->getLink( i );
605            LinkAction *link_action = link->getAction();
606            build_link( document->doc, &(mapping->_buffer[ i ].link), NULL, link_action );
607
608            link->getRect( &(mapping->_buffer[ i ].area.x1),
609                           &(mapping->_buffer[ i ].area.y1),
610                           &(mapping->_buffer[ i ].area.x2),
611                           &(mapping->_buffer[ i ].area.y2) );
612
613            mapping->_buffer[ i ].area.x1 -= page->page->getCropBox()->x1;
614            mapping->_buffer[ i ].area.x2 -= page->page->getCropBox()->x1;
615            mapping->_buffer[ i ].area.y1 -= page->page->getCropBox()->y1;
616            mapping->_buffer[ i ].area.y2 -= page->page->getCropBox()->y1;
617
618            double y1 = mapping->_buffer[ i ].area.y1;
619            double y2 = mapping->_buffer[ i ].area.y2;
620            mapping->_buffer[ i ].area.y1 = height - y2;
621            mapping->_buffer[ i ].area.y2 = height - y1;
622        }
623    }
624
625    return mapping;
626}
627
628
629SOM_Scope boolean  SOMLINK isSaveable(LuPopplerDocument *somSelf,
630                                       Environment *ev)
631{
632    return TRUE;
633}
634
635
636SOM_Scope boolean  SOMLINK saveAs(LuPopplerDocument *somSelf,
637                                   Environment *ev, string filename)
638{
639    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
640    PopplerDocument *document = (PopplerDocument *)somThis->data;
641
642    boolean retval = FALSE;
643
644    if ( filename != NULL ) {
645        retval = document->doc->saveAs( new GooString( filename ) );
646    }
647
648    return retval;
649}
650
651
652SOM_Scope boolean  SOMLINK isPSExportable(LuPopplerDocument *somSelf,
653                                           Environment *ev)
654{
655    return TRUE;
656}
657
658
659SOM_Scope void  SOMLINK exportToPS(LuPopplerDocument *somSelf,
660                                    Environment *ev, string filename,
661                                   long first_page, long last_page,
662                                   double width, double height,
663                                   boolean duplex)
664{
665    if ( filename == NULL ) {
666        return;
667    }
668    if ( last_page < first_page ) {
669        return;
670    }
671
672    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
673    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
674
675
676    PSOutputDev *out = new PSOutputDev( filename, doc->getXRef(),
677                                        doc->getCatalog(),
678                                        first_page + 1, last_page + 1,
679                                        psModePS, (int)width, (int)height,
680                                        duplex, 0, 0, 0, 0, gFalse );
681
682
683    for ( long i = first_page; i < last_page; i++ ) {
684        doc->displayPage( out, i + 1, 72.0, 72.0, 0, gFalse, gTrue, gFalse );
685    }
686
687    delete out;
688}
689
690
691SOM_Scope boolean  SOMLINK isHaveFontInfo(LuPopplerDocument *somSelf,
692                                           Environment *ev)
693{
694    return TRUE;
695}
696
697
698SOM_Scope LuDocument_LuFontInfoSequence*  SOMLINK getFontInfo(LuPopplerDocument *somSelf,
699                                                               Environment *ev)
700{
701    LuDocument_LuFontInfoSequence *fonts = NULL;
702
703    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
704    PopplerDocument *document = (PopplerDocument *)somThis->data;
705    PDFDoc *doc = document->doc;
706
707    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
708    FontInfoScanner *scanner = new FontInfoScanner( doc );
709    GooList *items = scanner->scan( doc->getNumPages() );
710    delete scanner;
711    DosReleaseMutexSem( document->mutex );
712
713    if ( items == NULL ) {
714        return NULL;
715    }
716
717    int len = items->getLength();
718
719    if ( len == 0 ) {
720        delete items;
721        return NULL;
722    }
723
724    fonts = (LuDocument_LuFontInfoSequence *)SOMMalloc( sizeof( LuDocument_LuFontInfoSequence ) );
725    fonts->_maximum = len;
726    fonts->_length = len;
727    fonts->_buffer = (LuFontInfo *)SOMMalloc( sizeof( LuFontInfo ) * len );
728
729    for ( int i = 0; i < len; i++ )
730    {
731        fonts->_buffer[i].name = NULL;
732        fonts->_buffer[i].type = NULL;
733        fonts->_buffer[i].embedded = NULL;
734
735        FontInfo *info = (FontInfo *)items->get( i );
736
737        // name
738        GooString *gnm = info->getName();
739        if ( gnm != NULL )
740        {
741            char *nm = gnm->getCString();
742            if ( info->getSubset() && ( nm != NULL ) )
743            {
744                while ( *nm && ( *nm != '+' ) ) {
745                    nm++;
746                }
747                if ( *nm ) {
748                    nm++;
749                }
750            }
751            if ( nm != NULL ) {
752                if ( *nm ) {
753                    fonts->_buffer[i].name = somstrdup( nm );
754                }
755            }
756        }
757
758        // type
759        char *t = "Unknown font type";
760        switch ( info->getType() )
761        {
762            case FontInfo::Type1:        t = "Type 1";          break;
763            case FontInfo::Type1C:       t = "Type 1C";         break;
764            case FontInfo::Type3:        t = "Type 3";          break;
765            case FontInfo::TrueType:     t = "TrueType";        break;
766            case FontInfo::CIDType0:     t = "Type 1 (CID)";    break;
767            case FontInfo::CIDType0C:    t = "Type 1C (CID)";   break;
768            case FontInfo::CIDTrueType:  t = "TrueType (CID)";  break;
769        }
770        fonts->_buffer[i].type = somstrdup( t );
771
772        // embedded
773        char *e = NULL;
774        if ( info->getEmbedded() ) {
775            if ( info->getSubset() ) {
776                e = "Embedded subset";
777            } else {
778                e = "Embedded";
779            }
780        } else {
781            e = "Not embedded";
782        }
783        fonts->_buffer[i].embedded = somstrdup( e );
784
785    }
786
787    return fonts;
788}
789
790
791SOM_Scope boolean  SOMLINK isHaveIndex(LuPopplerDocument *somSelf,
792                                        Environment *ev)
793{
794    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
795    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
796
797    Outline *outline = doc->getOutline();
798    if ( outline == NULL ) {
799        return FALSE;
800    }
801
802    GooList *items = outline->getItems();
803    if ( items == NULL ) {
804        return FALSE;
805    }
806
807    return TRUE;
808}
809
810static char *unicode_to_char( Unicode *unicode, int len )
811{
812    static UnicodeMap *uMap = NULL;
813    if ( uMap == NULL )
814    {
815        GooString *enc = new GooString( "UTF-8" );
816        uMap = globalParams->getUnicodeMap( enc );
817        uMap->incRefCnt();
818        delete enc;
819    }
820
821    GooString gstr;
822    char buf[8]; // 8 is enough for mapping an unicode char to a string
823    int i, n;
824
825    for ( i = 0; i < len; ++i ) {
826        n = uMap->mapUnicode( unicode[i], buf, sizeof( buf ) );
827        gstr.append( buf, n );
828    }
829
830    return newstrdup( gstr.getCString() );
831}
832
833static char *newstrFromUTF8( const char *s )
834{
835    unsigned blen = strlen( s ) + 1;
836    char *b = new char[ blen ];
837    memset( b, 0, blen );
838    char *bsav = b;
839    const char *from = s;
840    unsigned flen = strlen( s );
841    cnvUTF8ToSys( &from, &flen, &b, &blen );
842    return bsav;
843}
844
845static void add_item( Environment *ev, PDFDoc *doc, LuIndexNode *n, GooList *items )
846{
847    if ( items == NULL ) {
848        return;
849    }
850
851    int len = items->getLength();
852
853    for ( int i = 0; i < len; i++ )
854    {
855        OutlineItem *item = (OutlineItem *)items->get( i );
856        LinkAction *link_action = item->getAction();
857        LuLink evlink;
858        char *t1 = unicode_to_char( item->getTitle(), item->getTitleLength() );
859        char *t2 = newstrFromUTF8( t1 );
860        build_link( doc, &evlink, t2, link_action );
861        delete t2;
862        delete t1;
863        LuIndexNode *cn = new LuIndexNode( ev, &evlink );
864        n->addChild( ev, cn );
865
866        item->open();
867        if ( item->hasKids() )
868        {
869            GooList *citems = item->getKids();
870            add_item( ev, doc, cn, citems );
871        }
872    }
873}
874
875SOM_Scope LuIndexNode*  SOMLINK getIndex(LuPopplerDocument *somSelf,
876                                          Environment *ev)
877{
878    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
879    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
880
881    Outline *outline = doc->getOutline();
882    if ( outline == NULL ) {
883        return NULL;
884    }
885
886    GooList *items = outline->getItems();
887    if ( items == NULL ) {
888        return NULL;
889    }
890
891    LuIndexNode *root = new LuIndexNode( ev, NULL );
892    add_item( ev, doc, root, items );
893
894    return root;
895}
896
897
898static bool has_unicode_marker( GooString *string )
899{
900    return ( ( (string->getChar(0) & 0xff) == 0xfe ) &&
901             ( (string->getChar(1) & 0xff) == 0xff ) );
902}
903
904// return SOMMalloc'ed string
905static char *propcnv( GooString *s )
906{
907    if ( has_unicode_marker( s ) )
908    {
909        unsigned blen = s->getLength() * 2;
910        char *b = (char *)SOMMalloc( blen );
911        memset( b, 0, blen );
912        char *bsav = b;
913        const char *from = s->getCString() + 2;
914        unsigned flen = s->getLength() - 2;
915        cnvUniBEToSys( &from, &flen, &b, &blen );
916        return bsav;
917    }
918
919    return somstrdup( s->getCString() );
920}
921
922static time_t propToDate( const char *date_string )
923{
924    int year, mon, day, hour, min, sec;
925    int scanned_items;
926
927    // See PDF Reference 1.3, Section 3.8.2 for PDF Date representation
928    if ( ( date_string[0] == 'D' ) && ( date_string[1] == ':' ) ) {
929        date_string += 2;
930    }
931
932    // FIXME only year is mandatory; parse optional timezone offset
933    scanned_items = sscanf( date_string, "%4d%2d%2d%2d%2d%2d",
934                            &year, &mon, &day, &hour, &min, &sec);
935
936    if ( scanned_items != 6 ) {
937        return (time_t)(-1);
938    }
939
940    // Workaround for y2k bug in Distiller 3, hoping that it won't
941    // be used after y2.2k
942    if ( ( year < 1930 ) && ( strlen( date_string ) > 14 ) )
943    {
944        int century, years_since_1900;
945        scanned_items = sscanf( date_string, "%2d%3d%2d%2d%2d%2d%2d",
946                &century, &years_since_1900, &mon, &day, &hour, &min, &sec );
947
948        if ( scanned_items != 7 ) {
949            return (time_t)(-1);
950        }
951
952        year = century * 100 + years_since_1900;
953    }
954
955    struct tm time = { 0 };
956    time.tm_year  = year - 1900;
957    time.tm_mon   = mon - 1;
958    time.tm_mday  = day;
959    time.tm_hour  = hour;
960    time.tm_min   = min;
961    time.tm_sec   = sec;
962    time.tm_wday  = -1;
963    time.tm_yday  = -1;
964    time.tm_isdst = -1; // 0 = DST off, 1 = DST on, -1 = don't know
965
966    return mktime( &time );
967}
968
969static long convPageMode( Catalog::PageMode pageMode )
970{
971    switch ( pageMode )
972    {
973        case Catalog::pageModeThumbs:
974            return LU_DOCUMENT_MODE_USE_THUMBS;
975        case Catalog::pageModeFullScreen:
976            return LU_DOCUMENT_MODE_FULL_SCREEN;
977        case Catalog::pageModeOC:
978            return LU_DOCUMENT_MODE_USE_OC;
979        case Catalog::pageModeAttach:
980            return LU_DOCUMENT_MODE_USE_ATTACHMENTS;
981        case Catalog::pageModeNone:
982            return LU_DOCUMENT_MODE_NONE;
983    }
984
985    return -1;
986}
987
988static long convLayout( Catalog::PageLayout pageLayout )
989{
990    switch ( pageLayout )
991    {
992        case Catalog::pageLayoutSinglePage:
993            return LU_DOCUMENT_LAYOUT_SINGLE_PAGE;
994        case Catalog::pageLayoutOneColumn:
995            return LU_DOCUMENT_LAYOUT_ONE_COLUMN;
996        case Catalog::pageLayoutTwoColumnLeft:
997            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
998        case Catalog::pageLayoutTwoColumnRight:
999            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
1000        case Catalog::pageLayoutTwoPageLeft:
1001            return LU_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
1002        case Catalog::pageLayoutTwoPageRight:
1003            return LU_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
1004    }
1005    return -1;
1006}
1007
1008SOM_Scope LuDocumentInfo*  SOMLINK getDocumentInfo(LuPopplerDocument *somSelf,
1009                                                    Environment *ev)
1010{
1011    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1012    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
1013
1014    LuDocumentInfo *info = (LuDocumentInfo *)SOMMalloc( sizeof( LuDocumentInfo ) );
1015    memset( info, 0, sizeof( LuDocumentInfo ) );
1016
1017    Object objdict;
1018    doc->getDocInfo( &objdict );
1019    if ( objdict.isDict() )
1020    {
1021        Dict *d = objdict.getDict();
1022        Object obj;
1023
1024        if ( d->lookup( "Title", &obj )->isString() ) {
1025            info->title = propcnv( obj.getString() );
1026            info->fields_mask |= LU_DOCUMENT_INFO_TITLE;
1027        }
1028        obj.free();
1029        if ( d->lookup( "Author", &obj )->isString() ) {
1030            info->author = propcnv( obj.getString() );
1031            info->fields_mask |= LU_DOCUMENT_INFO_AUTHOR;
1032        }
1033        obj.free();
1034        if ( d->lookup( "Subject", &obj )->isString() ) {
1035            info->subject = propcnv( obj.getString() );
1036            info->fields_mask |= LU_DOCUMENT_INFO_SUBJECT;
1037        }
1038        obj.free();
1039        if ( d->lookup( "Keywords", &obj )->isString() ) {
1040            info->keywords = propcnv( obj.getString() );
1041            info->fields_mask |= LU_DOCUMENT_INFO_KEYWORDS;
1042        }
1043        obj.free();
1044        if ( d->lookup( "Creator", &obj )->isString() ) {
1045            info->creator = propcnv( obj.getString() );
1046            info->fields_mask |= LU_DOCUMENT_INFO_CREATOR;
1047        }
1048        obj.free();
1049        if ( d->lookup( "Producer", &obj )->isString() ) {
1050            info->producer = propcnv( obj.getString() );
1051            info->fields_mask |= LU_DOCUMENT_INFO_PRODUCER;
1052        }
1053        obj.free();
1054        if ( d->lookup( "CreationDate", &obj )->isString() ) {
1055            char *d = propcnv( obj.getString() );
1056            info->creation_date = propToDate( d );
1057            if ( (long)info->creation_date != -1 ) {
1058                info->fields_mask |= LU_DOCUMENT_INFO_CREATION_DATE;
1059            }
1060            SOMFree( d );
1061        }
1062        obj.free();
1063        if ( d->lookup( "ModDate", &obj )->isString() ) {
1064            char *d = propcnv( obj.getString() );
1065            info->modified_date = propToDate( d );
1066            if ( (long)info->modified_date != -1 ) {
1067                info->fields_mask |= LU_DOCUMENT_INFO_MOD_DATE;
1068            }
1069            SOMFree( d );
1070        }
1071        obj.free();
1072    }
1073
1074    char *format = (char *)SOMMalloc( 16 );
1075    snprintf( format, 16, "PDF-%.2f", doc->getPDFVersion() );
1076    info->format = format;
1077    info->fields_mask |= LU_DOCUMENT_INFO_FORMAT;
1078
1079    info->linearized = doc->isLinearized();
1080    info->fields_mask |= LU_DOCUMENT_INFO_LINEARIZED;
1081
1082    Catalog *catalog = doc->getCatalog();
1083
1084    if ( ( catalog != NULL ) && catalog->isOk() )
1085    {
1086        info->layout = convLayout( catalog->getPageLayout() );
1087        if ( info->layout != -1 ) {
1088            info->fields_mask |= LU_DOCUMENT_INFO_LAYOUT;
1089        }
1090
1091        info->mode = convPageMode( catalog->getPageMode() );
1092        if ( info->mode != -1 ) {
1093            info->fields_mask |= LU_DOCUMENT_INFO_START_MODE;
1094        }
1095    }
1096
1097    info->fields_mask |= LU_DOCUMENT_INFO_PERMISSIONS;
1098    if ( doc->okToPrint() ) {
1099        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
1100    }
1101    if ( doc->okToChange() ) {
1102        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
1103    }
1104    if ( doc->okToCopy() ) {
1105        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_COPY;
1106    }
1107    if ( doc->okToAddNotes() ) {
1108        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
1109    }
1110
1111    info->n_pages = doc->getNumPages();
1112    info->fields_mask |= LU_DOCUMENT_INFO_N_PAGES;
1113
1114    return info;
1115}
1116
1117
1118SOM_Scope boolean  SOMLINK getThumbnailSize(LuPopplerDocument *somSelf,
1119                                             Environment *ev,
1120                                            long pagenum,
1121                                            short suggested_width,
1122                                            short* width, short* height)
1123{
1124    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1125    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1126
1127    Object thumb;
1128    Dict *dict;
1129    boolean retval = FALSE;
1130
1131    page->getThumb( &thumb );
1132    if ( thumb.isNull() )
1133    {
1134        thumb.free();
1135        return FALSE;
1136    }
1137
1138    dict = thumb.streamGetDict();
1139
1140    // Theoretically, this could succeed and you would still fail when
1141    // loading the thumb
1142    int w = 0, h = 0;
1143    if ( dict->lookupInt( "Width", "W", &w ) && dict->lookupInt( "Height", "H", &h ) )
1144    {
1145        if ( width != NULL ) {
1146            *width = w;
1147        }
1148        if ( height != NULL ) {
1149            *height = h;
1150        }
1151
1152        retval = TRUE;
1153    }
1154
1155    thumb.free();
1156
1157    return retval;
1158}
1159
1160SOM_Scope LuPixbuf*  SOMLINK getThumbnail(LuPopplerDocument *somSelf,
1161                                           Environment *ev, long pagenum,
1162                                          short suggested_width)
1163{
1164    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1165    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1166
1167    unsigned char *data;
1168    int width, height, rowstride;
1169
1170    if ( !page->loadThumb( &data, &width, &height, &rowstride ) ) {
1171        return NULL;
1172    }
1173
1174    short bpp = getBpp( somSelf, ev );
1175    LuPixbuf *pixbuf = new LuPixbuf( ev, width, height, bpp );
1176    char *pixbuf_data = (char *)pixbuf->getDataPtr( ev );
1177    int pixbuf_rowstride = pixbuf->getRowSize( ev );
1178    char *src, *dst;
1179    int i, j;
1180    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
1181    {
1182        src = data + ( j * rowstride );
1183        dst = pixbuf_data + (i * pixbuf_rowstride);
1184        for ( int k = 0; k < pixbuf_rowstride; k += bpp )
1185        {
1186            dst[ k ]     = src[ k + 2 ];
1187            dst[ k + 1 ] = src[ k + 1 ];
1188            dst[ k + 2 ] = src[ k ];
1189        }
1190    }
1191    gfree( data );
1192
1193    return pixbuf;
1194}
1195
1196
1197SOM_Scope LuDocument_LuRectSequence*  SOMLINK searchText(LuPopplerDocument *somSelf,
1198                                                          Environment *ev,
1199                                                         long pagenum,
1200                                                         string text,
1201                                                         boolean caseSensitive)
1202{
1203    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1204    PopplerDocument *document = (PopplerDocument *)somThis->data;
1205    Page *page = document->pages[ pagenum ].page;
1206
1207    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
1208    TextOutputDev *output_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
1209    page->display( output_dev, 72, 72, 0, gFalse,
1210                   gTrue, NULL, document->doc->getCatalog() );
1211    DosReleaseMutexSem( document->mutex );
1212
1213
1214    // Convert string from system encoding to UCS-4
1215    // first, convert to UCS-2
1216    unsigned text_len = strlen( text );
1217    unsigned text_len_sav = text_len;
1218    unsigned ucs2_len = ( text_len + 1 ) * 2;
1219    char *ucs2 = new char[ ucs2_len ];
1220    memset( ucs2, 0, ucs2_len );
1221    char *ucs2sav = ucs2;
1222    cnvSysToUCS2( (const char **)&text, &text_len, &ucs2, &ucs2_len );
1223    // second, convert UCS-2 to UCS-4
1224    short *uucs2 = (short *)ucs2sav;
1225    unsigned ucs4_len = ( text_len_sav + 1 ) * 2;
1226    unsigned *ucs4 = new unsigned[ ucs4_len ];
1227    memset( ucs4, 0, ucs4_len * sizeof( unsigned ) );
1228    int real_ucs4_len = 0;
1229    for ( real_ucs4_len = 0; *uucs2; real_ucs4_len++ ) {
1230        ucs4[ real_ucs4_len ] = *uucs2++;
1231    }
1232    delete ucs2sav;
1233    // conversion end
1234
1235    RectList *rl = new RectList;
1236    double xMin, yMin, xMax, yMax;
1237    xMin = 0;
1238    yMin = 0;
1239    while ( output_dev->findText( ucs4, real_ucs4_len,
1240                   gFalse, gTrue, // startAtTop, stopAtBottom
1241                   gTrue, gFalse, // startAtLast, stopAtLast
1242                   caseSensitive, gFalse, // caseSensitive, backwards
1243                   &xMin, &yMin, &xMax, &yMax ) )
1244    {
1245        LuRectangle r;
1246        r.x1 = xMin;
1247        r.y1 = yMin;
1248        r.x2 = xMax;
1249        r.y2 = yMax;
1250        rl->push_back( r );
1251    }
1252    delete ucs4;
1253    delete output_dev;
1254
1255    LuDocument_LuRectSequence *rectangles = NULL;
1256    int len = rl->size();
1257    if ( len > 0 )
1258    {
1259        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
1260        rectangles->_maximum = len;
1261        rectangles->_length = len;
1262        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
1263
1264        for ( int i = 0; i < len; i++ )
1265        {
1266            rectangles->_buffer[ i ].x1 = (*rl)[i].x1;
1267            rectangles->_buffer[ i ].y1 = (*rl)[i].y1;
1268            rectangles->_buffer[ i ].x2 = (*rl)[i].x2;
1269            rectangles->_buffer[ i ].y2 = (*rl)[i].y2;
1270        }
1271    }
1272    delete rl;
1273
1274    return rectangles;
1275}
1276
1277
1278SOM_Scope void SOMLINK somDefaultInit(LuPopplerDocument *somSelf,
1279                                      som3InitCtrl* ctrl)
1280{
1281    // generated section - do not modify
1282    LuPopplerDocumentData *somThis;
1283    somInitCtrl globalCtrl;
1284    somBooleanVector myMask;
1285    LuPopplerDocument_BeginInitializer_somDefaultInit;
1286    LuPopplerDocument_Init_LuDocument_somDefaultInit(somSelf, ctrl);
1287    // end of generated section
1288
1289    // local LuPopplerDocument initialization code
1290    PopplerDocument *d = new PopplerDocument;
1291    somThis->data = d;
1292}
1293
1294
1295static void set_error( char **error, const char *fmt, ... )
1296{
1297    if ( error == NULL ) {
1298        return;
1299    }
1300
1301    va_list argptr;
1302    va_start( argptr, fmt );
1303    char *msg = new char[ 1000 ];
1304    vsnprintf( msg, 1000, fmt, argptr );
1305    *error = somstrdup( msg );
1306    delete msg;
1307}
1308
1309
1310SOM_Scope boolean  SOMLINK loadFile(LuPopplerDocument *somSelf,
1311                                    Environment *ev, string filename,
1312                                    string password, string* error)
1313{
1314    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData( somSelf );
1315
1316    PDFDoc *newDoc;
1317    GooString *filename_g;
1318    GooString *password_g;
1319    int err;
1320
1321    if ( !globalParams ) {
1322        globalParams = new GlobalParams( NULL );
1323    }
1324
1325    filename_g = new GooString(filename);
1326
1327    password_g = NULL;
1328    if (password != NULL) {
1329        password_g = new GooString(password);
1330    }
1331
1332    newDoc = new PDFDoc(filename_g, password_g, password_g);
1333    if (password_g) {
1334        delete password_g;
1335    }
1336
1337    if (!newDoc->isOk()) {
1338        err = newDoc->getErrorCode();
1339        delete newDoc;
1340
1341        if (err == errEncrypted) {
1342            set_error(error, "Document is encrypted.");
1343        } else {
1344            set_error(error, "Failed to load document (error %d) '%s'\n", err, filename );
1345        }
1346
1347        return FALSE;
1348    }
1349
1350    PopplerDocument *document = (PopplerDocument *)somThis->data;
1351
1352    document->doc = newDoc;
1353    SplashColor white;
1354    white[0] = 255;
1355    white[1] = 255;
1356    white[2] = 255;
1357    document->output_dev = new SplashOutputDev( splashModeRGB8, 4, gFalse, white );
1358    document->output_dev->startDoc( document->doc->getXRef() );
1359
1360    long numpages = document->doc->getNumPages();
1361    document->pages = new PopplerPage[ numpages ];
1362    for ( long pagenum = 0; pagenum < numpages; pagenum++ ) {
1363        document->pages[ pagenum ].page =
1364            document->doc->getCatalog()->getPage( pagenum + 1 );
1365    }
1366
1367    return TRUE;
1368}
1369
1370
1371SOM_Scope void SOMLINK somDestruct(LuPopplerDocument *somSelf,
1372                                   octet doFree, som3DestructCtrl* ctrl)
1373{
1374    LuPopplerDocumentData *somThis;
1375    somDestructCtrl globalCtrl;
1376    somBooleanVector myMask;
1377    LuPopplerDocument_BeginDestructor;
1378
1379    // local LuPopplerDocument deinitialization code
1380    PopplerDocument *document = (PopplerDocument *)somThis->data;
1381    delete document;
1382    // end of local LuPopplerDocument deinitialization code
1383
1384    LuPopplerDocument_EndDestructor;
1385}
1386
1387
Note: See TracBrowser for help on using the repository browser.