source: trunk/Lucide/gui/lucidethumbs.cpp

Last change on this file was 680, checked in by Gregg Young, 3 years ago

Fixed some errors reported by CPPCheck.

File size: 16.5 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: CDDL 1.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the COMMON DEVELOPMENT AND
5 * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6 * this file except in compliance with the License. You may obtain a copy of
7 * the License at http://www.sun.com/cddl/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is
15 * Eugene Romanenko, netlabs.org.
16 * Portions created by the Initial Developer are Copyright (C) 2006
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23 * in which case the provisions of the LGPL are applicable instead of those
24 * above. If you wish to allow use of your version of this file only under the
25 * terms of the LGPL, and not to allow others to use your version of this file
26 * under the terms of the CDDL, indicate your decision by deleting the
27 * provisions above and replace them with the notice and other provisions
28 * required by the LGPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under the terms of any one of the CDDL
30 * or the LGPL.
31 *
32 * ***** END LICENSE BLOCK ***** */
33
34
35#include "os2all.h"
36#include <mmioos2.h>
37
38#include <stdlib.h>
39#include <string.h>
40#include <io.h>
41#include <fcntl.h>
42#include <algorithm>
43
44#include <ludoc.xh>
45
46#include "Lucide.h"
47#include "luutils.h"
48
49#define LUTHUMB_SIZE_X  256
50#define LUTHUMB_SIZE_Y  256
51static const char * const LUTHUMB_EA_NAME = "LUCIDE_THUMBNAIL";
52
53
54static bool loadMMIOFuncs();
55
56static HMODULE mmioHndl = NULLHANDLE;
57static bool mmioFuncsLoaded = loadMMIOFuncs();
58
59static void freeMmio()
60{
61    if ( mmioHndl != NULLHANDLE ) {
62        DosFreeModule( mmioHndl );
63    }
64}
65
66HMMIO  APIENTRY (*pMmioOpen)(PSZ,PMMIOINFO,ULONG);
67LONG   APIENTRY (*pMmioWrite)(HMMIO,PCHAR,LONG);
68ULONG  APIENTRY (*pMmioSetHeader)(HMMIO,PVOID,LONG,PLONG,ULONG,ULONG);
69USHORT APIENTRY (*pMmioClose)(HMMIO,USHORT);
70ULONG  APIENTRY (*pMmioIdentifyFile)(PSZ,PMMIOINFO,PMMFORMATINFO,PFOURCC,ULONG,ULONG);
71ULONG  APIENTRY (*pMmioQueryHeaderLength)(HMMIO,PLONG,ULONG,ULONG);
72ULONG  APIENTRY (*pMmioGetHeader)(HMMIO,PVOID,LONG,PLONG,ULONG,ULONG);
73LONG   APIENTRY (*pMmioRead)(HMMIO,PCHAR,LONG);
74
75static bool loadMMIOFuncs()
76{
77    bool res = false;
78    do
79    {
80        if ( DosLoadModule( NULL, 0, "MMIO", &mmioHndl ) != 0 )
81            break;
82        if ( DosQueryProcAddr( mmioHndl, 0, "mmioOpen", (PFN *)&pMmioOpen ) != 0 )
83            break;
84        if ( DosQueryProcAddr( mmioHndl, 0, "mmioWrite", (PFN *)&pMmioWrite ) != 0 )
85            break;
86        if ( DosQueryProcAddr( mmioHndl, 0, "mmioSetHeader", (PFN *)&pMmioSetHeader ) != 0 )
87            break;
88        if ( DosQueryProcAddr( mmioHndl, 0, "mmioClose", (PFN *)&pMmioClose ) != 0 )
89            break;
90        if ( DosQueryProcAddr( mmioHndl, 0, "mmioIdentifyFile", (PFN *)&pMmioIdentifyFile ) != 0 )
91            break;
92        if ( DosQueryProcAddr( mmioHndl, 0, "mmioQueryHeaderLength", (PFN *)&pMmioQueryHeaderLength ) != 0 )
93            break;
94        if ( DosQueryProcAddr( mmioHndl, 0, "mmioGetHeader", (PFN *)&pMmioGetHeader ) != 0 )
95            break;
96        if ( DosQueryProcAddr( mmioHndl, 0, "mmioRead", (PFN *)&pMmioRead ) != 0 )
97            break;
98
99        res = true;
100    } while (0);
101
102    atexit( freeMmio );
103
104    return res;
105}
106
107
108static bool saveToImage( char *pszFileName, char *format,
109                         ULONG width, ULONG height, ULONG row_size,
110                         ULONG bpp, char* src_buf )
111{
112    bool              ret = false;
113    MMIOINFO          mmioinfoTarget;
114    HMMIO             hmmioTarget;
115    PBYTE             pbBuffer = NULL;
116    ULONG             cbBuffer,cbBitmapInfo, rl;
117    ULONG             rc;
118    MMIMAGEHEADER     mmImgHdr;
119    BITMAPINFO2       bmp;
120    FOURCC            saveas;
121
122    rl = ( ( bpp * width + 31 ) / 32 ) * 4;
123    cbBuffer = rl * height;
124
125    if ( !format ) {
126        return ret;
127    }
128
129    saveas = mmioFOURCC( format[0], format[1], format[2], format[3] );
130
131    // fill bmp
132    memset( &bmp, 0, sizeof( bmp ) );
133    bmp.cbFix         = sizeof( bmp );
134    bmp.cx            = width;
135    bmp.cy            = height;
136    bmp.cPlanes       = 1;
137    bmp.cBitCount     = bpp;
138    bmp.ulCompression = 0;
139    bmp.cbImage       = cbBuffer;
140
141    cbBitmapInfo = sizeof( bmp );
142
143    memset( &mmioinfoTarget, 0L, sizeof( MMIOINFO ) );
144    mmioinfoTarget.fccIOProc = saveas;
145    mmioinfoTarget.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
146    hmmioTarget = pMmioOpen( pszFileName, &mmioinfoTarget, MMIO_CREATE | MMIO_WRITE |
147                                                        MMIO_DENYWRITE | MMIO_NOIDENTIFY );
148    if ( hmmioTarget )
149    {
150        ULONG ulBytesWritten;
151
152        memset( &mmImgHdr, 0, sizeof( MMIMAGEHEADER ) );
153        mmImgHdr.ulHeaderLength = sizeof(MMIMAGEHEADER);
154        mmImgHdr.ulContentType = MMIO_IMAGE_UNKNOWN;
155        mmImgHdr.ulMediaType = MMIO_MEDIATYPE_IMAGE;
156        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulMemSize = cbBuffer;
157        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulPelFormat = ( bpp < 24 ) ?
158                        mmioFOURCC('p','a','l','b') : mmioFOURCC('r','g','b','b');
159
160        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.usTransType = 0;
161        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulTransVal = 0;
162        memcpy( &mmImgHdr.mmXDIBHeader.BMPInfoHeader2, &bmp, cbBitmapInfo );
163        rc = pMmioSetHeader( hmmioTarget, &mmImgHdr, sizeof(MMIMAGEHEADER),
164                                    (PLONG)&ulBytesWritten, 0L, 0L);
165        if ( rc == MMIO_SUCCESS )
166        {
167            for ( int k=0; k < height; k++ )
168            {
169                char *line = src_buf + ( k * row_size );
170
171                ulBytesWritten = pMmioWrite( hmmioTarget, (char*)line, rl );
172
173                if ( ( ulBytesWritten == MMIO_ERROR ) || ( ulBytesWritten == 0 ) ) {
174                    break;
175                }
176            }
177
178            if ( ( ulBytesWritten != MMIO_ERROR ) && ( ulBytesWritten != 0 ) ) {
179                ret = true;
180            }
181        }
182
183        pMmioClose( hmmioTarget, 0L );
184    }
185
186    return ret;
187}
188
189static BOOL set_ea( const char *file_name, const char *ea_name,
190                    const char *ea_data, int ea_data_len )
191{
192    APIRET rc = 0;
193    EAOP2  op;
194
195    char *databuf = new char[(64*2*1024)+1024]; // twice 64K for EA data + 1024 for any case
196
197    op.fpGEA2List = (PGEA2LIST)0;
198    op.fpFEA2List = (PFEA2LIST)databuf;
199
200    int  ea_name_len = strlen( ea_name );
201    if ( ea_name_len > 255 ) {
202        delete[] databuf;
203        return FALSE;
204    }
205
206    char *databufp = databuf + sizeof( long );
207    *((long*)databufp) = 0; // Next field offset is zero - just one field here
208    databufp += sizeof(long);
209    *databufp++ = 0; // not critical
210    *databufp++ = (char)ea_name_len;
211    *((short*)databufp) = (short)ea_data_len;
212    databufp += sizeof(short);
213    memcpy( databufp, ea_name, ea_name_len+1 ); // with trailing zero
214    databufp += ea_name_len+1;
215
216    // set the ea type and length
217    *((short*)databufp) = EAT_BINARY;
218    databufp += sizeof(short);
219    *((short*)databufp) = (short)ea_data_len;
220    databufp += sizeof(short);
221
222    memcpy( databufp, ea_data, ea_data_len ); // with trailing zero
223    databufp += ea_data_len;
224
225    *((long*)databuf) = databufp-databuf; // Size of all that stuff
226
227    // HPFS386 workaround
228    // Save timestamp (setting EA drops timestamp on HPFS386)
229    APIRET qpirc = 0;
230    FILESTATUS3 fs = { 0 };
231    qpirc = DosQueryPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ) );
232
233    // Write EA
234    rc = DosSetPathInfo( file_name, FIL_QUERYEASIZE, &op, sizeof(op), 0);
235    delete[] databuf;
236
237    // Restore timestamp
238    if ( qpirc == 0 ) {
239        DosSetPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ), DSPI_WRTTHRU );
240    }
241
242    if ( rc != 0 ) {
243        return FALSE;
244    }
245
246    return TRUE;
247}
248
249bool Lucide::isThumbNeeded( const char *fn )
250{
251    // First, check if mmio is available
252    if ( !mmioFuncsLoaded ) {
253        return false;
254    }
255
256    // Second, check if file is writeable
257    if ( access( fn, W_OK ) != 0 ) {
258        // Isn't writable, do not waste time to render thumbnail
259        return false;
260    }
261
262    // Third, check if thumbnail EA already present
263    UCHAR    EnumBuf[200] = {0};      // Data Buffer
264    ULONG    ulEnumCnt    = 0;        // Count of entries to return
265    FEA2     *ptr         = NULL;     // Pointer to data items returned
266    ULONG    ulTemp       = 0;
267    APIRET   rc           = 0;
268
269    ulEnumCnt = (ULONG)-1; // Request as many attributes as will fit in buffer
270
271    rc = DosEnumAttribute( ENUMEA_REFTYPE_PATH, (PVOID)fn, 1L, &EnumBuf, sizeof( EnumBuf ),
272                           &ulEnumCnt, ENUMEA_LEVEL_NO_VALUE );
273
274    if ( rc != 0 ) {
275        // error look for EA names, return 'false' to prevent EA creation
276        // as if enum failed, creation may also fail
277        return false;
278    }
279
280    ptr = (FEA2 *)EnumBuf; // Mask the buffer pointer to an FEA2 structure
281
282    for ( ULONG i = 0; i < ulEnumCnt; i++ )
283    {
284        if ( strcmp( ptr->szName, LUTHUMB_EA_NAME ) == 0 ) {
285            return false; // Thumbnail already present
286        }
287        /// increment the ptr with the value in oNextEntryOffset
288        ulTemp = ptr->oNextEntryOffset + (ULONG)ptr;
289        ptr = (FEA2 *)ulTemp;
290    }
291    return true;
292}
293
294
295bool Lucide::createThumbnail( LuDocument *doc )
296{
297    //if ( !doc->isScalable( ev ) ) {
298    //    return;
299    //}
300
301    // render first page if there is one
302    if ( doc->getPageCount( ev ) <= 0 )
303        return FALSE;
304    double width = 0, height = 0;
305    doc->getPageSize( ev, 0, &width, &height );
306    if ( width <= 0 || height <= 0 )
307        return FALSE;
308    double zoom = std::min( (double)LUTHUMB_SIZE_X / width, (double)LUTHUMB_SIZE_Y / height );
309    short bpp = doc->getBpp( ev );
310
311    long rx = width * zoom;
312    long ry = height * zoom;
313    LuPixbuf *pixbuf = new LuPixbuf( ev, rx, ry, bpp );
314    if ( !doc->renderPageToPixbuf(ev, 0, 0, 0, rx, ry, zoom, 0, pixbuf,
315                                  NULL, NULL ) ) {
316        delete pixbuf;
317        return TRUE;
318    }
319    char *tmpgif = new char[ CCHMAXPATH ];
320    getTmpDir( tmpgif );
321    strcat( tmpgif, "LUTHUMB.TMP" );
322
323    // Workaround: GIF mmio proc hangs on 32-bit images, convert to 24 bit
324    if ( bpp == 4 )
325    {
326        LuPixbuf *pb = new LuPixbuf( ev, rx, ry, 3 );
327
328        char *src = (char *)pixbuf->getDataPtr( ev );
329        char *dst = (char *)pb->getDataPtr( ev );
330        int src_rowstride = pixbuf->getRowSize( ev );
331        int dst_rowstride = pb->getRowSize( ev );
332
333        int i, j, l, m;
334        for ( i = 0; i < ry; i++ )
335        {
336            char *src_line = src + ( i * src_rowstride );
337            char *dst_line = dst + ( i * dst_rowstride );
338
339            // source 4 Bpp, dest 3 Bpp
340            for ( j = 0, l = 0, m = 0; j < rx; j++ ) {
341                dst_line[ l++ ] = src_line[ m++ ];
342                dst_line[ l++ ] = src_line[ m++ ];
343                dst_line[ l++ ] = src_line[ m++ ];
344                m++;
345            }
346        }
347
348        delete pixbuf;
349        pixbuf = pb;
350        bpp = 3;
351    }
352
353    bool saved = saveToImage( tmpgif, "GIFC", rx, ry, pixbuf->getRowSize( ev ),
354                              bpp * 8, (char *)pixbuf->getDataPtr( ev ) );
355    delete pixbuf;
356    if ( saved )
357    {
358        // If image file saved, read file content into
359        // thumbnailData buffer, to be able write it into EA
360        // when document will be closed
361        int h = open( tmpgif, O_RDONLY | O_BINARY | O_NOINHERIT );
362        if ( h != -1 )
363        {
364            long flen = filelength( h );
365            if ( flen > 0 )
366            {
367                thumbnailData = new char[ flen ];
368                thumbnailDataLen = flen;
369                if ( read( h, thumbnailData, flen ) != flen ) {
370                    delete thumbnailData;
371                    thumbnailData = NULL;
372                    thumbnailDataLen = 0;
373                }
374            }
375            close( h );
376        }
377    }
378    // if tmp file exist - delete it
379    if ( access( tmpgif, F_OK ) == 0 ) {
380        unlink( tmpgif );
381    }
382    delete[] tmpgif;
383    return TRUE;
384}
385
386void Lucide::writeThumbnail( const char *fn )
387{
388    if ( ( thumbnailData == NULL ) || ( thumbnailDataLen == 0 ) ) {
389        return;
390    }
391
392    set_ea( fn, LUTHUMB_EA_NAME, (const char *)thumbnailData, thumbnailDataLen );
393    delete thumbnailData;
394    thumbnailData = NULL;
395    thumbnailDataLen = 0;
396}
397
398
399HBITMAP LoadBitmap( HAB hab, HDC hdc, HPS *hps, PSZ pszFileName )
400{
401    HBITMAP       hbm;
402    MMIOINFO      mmioinfo;
403    MMFORMATINFO  mmFormatInfo;
404    HMMIO         hmmio;
405    ULONG         ulImageHeaderLength;
406    MMIMAGEHEADER mmImgHdr;
407    ULONG         ulBytesRead;
408    ULONG         dwNumRowBytes;
409    PBYTE         pRowBuffer;
410    ULONG         dwRowCount;
411    SIZEL         ImageSize;
412    ULONG         dwHeight, dwWidth;
413    SHORT         wBitCount;
414    FOURCC        fccStorageSystem;
415    ULONG         dwPadBytes;
416    ULONG         dwRowBits;
417    ULONG         ulReturnCode;
418    ULONG         dwReturnCode;
419    HBITMAP       hbReturnCode;
420    LONG          lReturnCode;
421    FOURCC        fccIOProc;
422
423
424    ulReturnCode = pMmioIdentifyFile( pszFileName, 0L, &mmFormatInfo,
425                                      &fccStorageSystem, 0L, 0L );
426    if ( ulReturnCode == MMIO_ERROR ) {
427         return NULLHANDLE;
428    }
429
430    if( mmFormatInfo.fccIOProc == FOURCC_DOS ) {
431         return NULLHANDLE;
432    }
433
434    if ( (mmFormatInfo.ulMediaType != MMIO_MEDIATYPE_IMAGE) ||
435         ((mmFormatInfo.ulFlags & MMIO_CANREADTRANSLATED) == 0) ) {
436         return NULLHANDLE;
437    }
438    else {
439         fccIOProc = mmFormatInfo.fccIOProc;
440    }
441
442    memset( &mmioinfo, 0L, sizeof( MMIOINFO ) );
443    mmioinfo.fccIOProc = fccIOProc;
444    mmioinfo.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
445
446    hmmio = pMmioOpen( (PSZ)pszFileName, &mmioinfo,
447                      MMIO_READ | MMIO_DENYWRITE | MMIO_NOIDENTIFY );
448
449    if ( !hmmio ) {
450         return NULLHANDLE;
451    }
452
453    dwReturnCode = pMmioQueryHeaderLength( hmmio, (PLONG)&ulImageHeaderLength, 0L, 0L );
454
455    if ( ulImageHeaderLength != sizeof ( MMIMAGEHEADER ) ) {
456         pMmioClose( hmmio, 0L );
457         return NULLHANDLE;
458    }
459
460    ulReturnCode = pMmioGetHeader( hmmio, &mmImgHdr, sizeof( MMIMAGEHEADER ),
461                                   (PLONG)&ulBytesRead, 0L, 0L );
462
463    if ( ulReturnCode != MMIO_SUCCESS ) {
464         pMmioClose( hmmio, 0L );
465         return NULLHANDLE;
466    }
467
468    dwHeight = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cy;
469    dwWidth = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cx;
470    wBitCount = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cBitCount;
471    dwRowBits = dwWidth * mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cBitCount;
472    dwNumRowBytes = dwRowBits >> 3;
473
474    if ( dwRowBits % 8 ) {
475         dwNumRowBytes++;
476    }
477
478    dwPadBytes = ( dwNumRowBytes % 4 );
479
480    if ( dwPadBytes ) {
481         dwNumRowBytes += 4 - dwPadBytes;
482    }
483
484    pRowBuffer = (PBYTE)malloc( dwNumRowBytes );
485
486    ImageSize.cx = dwWidth;
487    ImageSize.cy = dwHeight;
488
489    *hps = GpiCreatePS( hab, hdc, &ImageSize,
490                        PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
491
492    if ( !*hps ) {
493        free( pRowBuffer );
494        pMmioClose( hmmio, 0L );
495        return NULLHANDLE;
496    }
497
498    hbm = GpiCreateBitmap( *hps, &mmImgHdr.mmXDIBHeader.BMPInfoHeader2, 0L, NULL, NULL );
499
500    if ( !hbm )
501    {
502        free( pRowBuffer );
503        pMmioClose( hmmio, 0L );
504        return NULLHANDLE;
505    }
506
507    hbReturnCode = GpiSetBitmap( *hps, hbm );
508
509    for ( dwRowCount = 0; dwRowCount < dwHeight; dwRowCount++ )
510    {
511         ulBytesRead = pMmioRead( hmmio, pRowBuffer, dwNumRowBytes );
512
513         if ( !ulBytesRead ) {
514              break;
515         }
516
517         lReturnCode = GpiSetBitmapBits( *hps, dwRowCount, 1, pRowBuffer,
518                                         (PBITMAPINFO2)&mmImgHdr.mmXDIBHeader.BMPInfoHeader2 );
519    }
520
521    pMmioClose( hmmio, 0L );
522    free( pRowBuffer );
523
524    return hbm;
525}
526
Note: See TracBrowser for help on using the repository browser.