source: trunk/Lucide/gui/lucidethumbs.cpp @ 367

Last change on this file since 367 was 367, checked in by dmik, 11 years ago

Merged bramches/kmk (r294:365) to trunk.

File size: 16.1 KB
RevLine 
[153]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
[334]35#include "os2all.h"
[309]36#include <mmioos2.h>
[153]37
38#include <stdlib.h>
39#include <string.h>
40#include <io.h>
41#include <fcntl.h>
[309]42#include <algorithm>
[153]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);
[230]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);
[153]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;
[230]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;
[153]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    memcpy( databufp, ea_data, ea_data_len ); // with trailing zero
216    databufp += ea_data_len;
217
218    *((long*)databuf) = databufp-databuf; // Size of all that stuff
219
[198]220    // HPFS386 workaround
221    // Save timestamp (setting EA drops timestamp on HPFS386)
222    APIRET qpirc = 0;
223    FILESTATUS3 fs = { 0 };
224    qpirc = DosQueryPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ) );
225
226    // Write EA
[153]227    rc = DosSetPathInfo( file_name, FIL_QUERYEASIZE, &op, sizeof(op), 0);
228    delete databuf;
[198]229
230    // Restore timestamp
231    if ( qpirc == 0 ) {
232        DosSetPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ), DSPI_WRTTHRU );
233    }
234
[153]235    if ( rc != 0 ) {
236        return FALSE;
237    }
238
239    return TRUE;
240}
241
242bool Lucide::isThumbNeeded( const char *fn )
243{
244    // First, check if mmio is available
245    if ( !mmioFuncsLoaded ) {
246        return false;
247    }
248
249    // Second, check if file is writeable
250    if ( access( fn, W_OK ) != 0 ) {
251        // Isn't writable, do not waste time to render thumbnail
252        return false;
253    }
254
255    // Third, check if thumbnail EA already present
256    UCHAR    EnumBuf[200] = {0};      // Data Buffer
257    ULONG    ulEnumCnt    = 0;        // Count of entries to return
258    FEA2     *ptr         = NULL;     // Pointer to data items returned
259    ULONG    ulTemp       = 0;
260    APIRET   rc           = 0;
261
262    ulEnumCnt = (ULONG)-1; // Request as many attributes as will fit in buffer
263
264    rc = DosEnumAttribute( ENUMEA_REFTYPE_PATH, (PVOID)fn, 1L, &EnumBuf, sizeof( EnumBuf ),
265                           &ulEnumCnt, ENUMEA_LEVEL_NO_VALUE );
266
267    if ( rc != 0 ) {
268        // error look for EA names, return 'false' to prevent EA creation
269        // as if enum failed, creation may also fail
270        return false;
271    }
272
273    ptr = (FEA2 *)EnumBuf; // Mask the buffer pointer to an FEA2 structure
274
275    for ( ULONG i = 0; i < ulEnumCnt; i++ )
276    {
277        if ( strcmp( ptr->szName, LUTHUMB_EA_NAME ) == 0 ) {
278            return false; // Thumbnail already present
279        }
280        /// increment the ptr with the value in oNextEntryOffset
281        ulTemp = ptr->oNextEntryOffset + (ULONG)ptr;
282        ptr = (FEA2 *)ulTemp;
283    }
284    return true;
285}
286
287
288void Lucide::createThumbnail( LuDocument *doc )
289{
290    if ( !doc->isScalable( ev ) ) {
291        return;
292    }
293
294    // render first page
295    double width = 0, height = 0;
296    doc->getPageSize( ev, 0, &width, &height );
[309]297    double zoom = std::min( (double)LUTHUMB_SIZE_X / width, (double)LUTHUMB_SIZE_Y / height );
[153]298    short bpp = doc->getBpp( ev );
299
300    long rx = width * zoom;
301    long ry = height * zoom;
302    LuPixbuf *pixbuf = new LuPixbuf( ev, rx, ry, bpp );
[155]303    if ( !doc->renderPageToPixbuf( ev, 0, 0, 0, rx, ry, zoom, 0, pixbuf, NULL, NULL ) ) {
304        delete pixbuf;
305        return;
306    }
[153]307
308    char *tmpgif = new char[ CCHMAXPATH ];
309    getTmpDir( tmpgif );
310    strcat( tmpgif, "LUTHUMB.TMP" );
311
[260]312    // Workaround: GIF mmio proc hangs on 32-bit images, convert to 24 bit
313    if ( bpp == 4 )
314    {
315        LuPixbuf *pb = new LuPixbuf( ev, rx, ry, 3 );
316
317        char *src = (char *)pixbuf->getDataPtr( ev );
318        char *dst = (char *)pb->getDataPtr( ev );
319        int src_rowstride = pixbuf->getRowSize( ev );
320        int dst_rowstride = pb->getRowSize( ev );
321
322        int i, j, l, m;
323        for ( i = 0; i < ry; i++ )
324        {
325            char *src_line = src + ( i * src_rowstride );
326            char *dst_line = dst + ( i * dst_rowstride );
327
328            // source 4 Bpp, dest 3 Bpp
329            for ( j = 0, l = 0, m = 0; j < rx; j++ ) {
330                dst_line[ l++ ] = src_line[ m++ ];
331                dst_line[ l++ ] = src_line[ m++ ];
332                dst_line[ l++ ] = src_line[ m++ ];
333                m++;
334            }
335        }
336
337        delete pixbuf;
338        pixbuf = pb;
339        bpp = 3;
340    }
341
[153]342    bool saved = saveToImage( tmpgif, "GIFC", rx, ry, pixbuf->getRowSize( ev ),
343                              bpp * 8, (char *)pixbuf->getDataPtr( ev ) );
344    delete pixbuf;
345    if ( saved )
346    {
347        // If image file saved, read file content into
348        // thumbnailData buffer, to be able write it into EA
349        // when document will be closed
350        int h = open( tmpgif, O_RDONLY | O_BINARY | O_NOINHERIT );
351        if ( h != -1 )
352        {
353            long flen = filelength( h );
354            if ( flen > 0 )
355            {
356                thumbnailData = new char[ flen ];
357                thumbnailDataLen = flen;
358                if ( read( h, thumbnailData, flen ) != flen ) {
359                    delete thumbnailData;
360                    thumbnailData = NULL;
361                    thumbnailDataLen = 0;
362                }
363            }
364            close( h );
365        }
366    }
367    // if tmp file exist - delete it
368    if ( access( tmpgif, F_OK ) == 0 ) {
369        unlink( tmpgif );
370    }
371    delete tmpgif;
372}
373
374void Lucide::writeThumbnail( const char *fn )
375{
376    if ( ( thumbnailData == NULL ) || ( thumbnailDataLen == 0 ) ) {
377        return;
378    }
379
380    set_ea( fn, LUTHUMB_EA_NAME, (const char *)thumbnailData, thumbnailDataLen );
381    delete thumbnailData;
382    thumbnailData = NULL;
383    thumbnailDataLen = 0;
384}
385
[230]386
387HBITMAP LoadBitmap( HAB hab, HDC hdc, HPS *hps, PSZ pszFileName )
388{
389    HBITMAP       hbm;
390    MMIOINFO      mmioinfo;
391    MMFORMATINFO  mmFormatInfo;
392    HMMIO         hmmio;
393    ULONG         ulImageHeaderLength;
394    MMIMAGEHEADER mmImgHdr;
395    ULONG         ulBytesRead;
396    ULONG         dwNumRowBytes;
397    PBYTE         pRowBuffer;
398    ULONG         dwRowCount;
399    SIZEL         ImageSize;
400    ULONG         dwHeight, dwWidth;
401    SHORT         wBitCount;
402    FOURCC        fccStorageSystem;
403    ULONG         dwPadBytes;
404    ULONG         dwRowBits;
405    ULONG         ulReturnCode;
406    ULONG         dwReturnCode;
407    HBITMAP       hbReturnCode;
408    LONG          lReturnCode;
409    FOURCC        fccIOProc;
410
411
412    ulReturnCode = pMmioIdentifyFile( pszFileName, 0L, &mmFormatInfo,
413                                      &fccStorageSystem, 0L, 0L );
414    if ( ulReturnCode == MMIO_ERROR ) {
415         return NULLHANDLE;
416    }
417
418    if( mmFormatInfo.fccIOProc == FOURCC_DOS ) {
419         return NULLHANDLE;
420    }
421
422    if ( (mmFormatInfo.ulMediaType != MMIO_MEDIATYPE_IMAGE) ||
423         ((mmFormatInfo.ulFlags & MMIO_CANREADTRANSLATED) == 0) ) {
424         return NULLHANDLE;
425    }
426    else {
427         fccIOProc = mmFormatInfo.fccIOProc;
428    }
429
430    memset( &mmioinfo, 0L, sizeof( MMIOINFO ) );
431    mmioinfo.fccIOProc = fccIOProc;
432    mmioinfo.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
433
434    hmmio = pMmioOpen( (PSZ)pszFileName, &mmioinfo,
435                      MMIO_READ | MMIO_DENYWRITE | MMIO_NOIDENTIFY );
436
437    if ( !hmmio ) {
438         return NULLHANDLE;
439    }
440
441    dwReturnCode = pMmioQueryHeaderLength( hmmio, (PLONG)&ulImageHeaderLength, 0L, 0L );
442
443    if ( ulImageHeaderLength != sizeof ( MMIMAGEHEADER ) ) {
444         pMmioClose( hmmio, 0L );
445         return NULLHANDLE;
446    }
447
448    ulReturnCode = pMmioGetHeader( hmmio, &mmImgHdr, sizeof( MMIMAGEHEADER ),
449                                   (PLONG)&ulBytesRead, 0L, 0L );
450
451    if ( ulReturnCode != MMIO_SUCCESS ) {
452         pMmioClose( hmmio, 0L );
453         return NULLHANDLE;
454    }
455
456    dwHeight = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cy;
457    dwWidth = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cx;
458    wBitCount = mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cBitCount;
459    dwRowBits = dwWidth * mmImgHdr.mmXDIBHeader.BMPInfoHeader2.cBitCount;
460    dwNumRowBytes = dwRowBits >> 3;
461
462    if ( dwRowBits % 8 ) {
463         dwNumRowBytes++;
464    }
465
466    dwPadBytes = ( dwNumRowBytes % 4 );
467
468    if ( dwPadBytes ) {
469         dwNumRowBytes += 4 - dwPadBytes;
470    }
471
472    pRowBuffer = (PBYTE)malloc( dwNumRowBytes );
473
474    ImageSize.cx = dwWidth;
475    ImageSize.cy = dwHeight;
476
477    *hps = GpiCreatePS( hab, hdc, &ImageSize,
478                        PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
479
480    if ( !*hps ) {
481        free( pRowBuffer );
482        pMmioClose( hmmio, 0L );
483        return NULLHANDLE;
484    }
485
486    hbm = GpiCreateBitmap( *hps, &mmImgHdr.mmXDIBHeader.BMPInfoHeader2, 0L, NULL, NULL );
487
488    if ( !hbm )
489    {
490        free( pRowBuffer );
491        pMmioClose( hmmio, 0L );
492        return NULLHANDLE;
493    }
494
495    hbReturnCode = GpiSetBitmap( *hps, hbm );
496
497    for ( dwRowCount = 0; dwRowCount < dwHeight; dwRowCount++ )
498    {
499         ulBytesRead = pMmioRead( hmmio, pRowBuffer, dwNumRowBytes );
500
501         if ( !ulBytesRead ) {
502              break;
503         }
504
505         lReturnCode = GpiSetBitmapBits( *hps, dwRowCount, 1, pRowBuffer,
506                                         (PBITMAPINFO2)&mmImgHdr.mmXDIBHeader.BMPInfoHeader2 );
507    }
508
509    pMmioClose( hmmio, 0L );
510    free( pRowBuffer );
511
512    return hbm;
513}
514
Note: See TracBrowser for help on using the repository browser.