source: trunk/Lucide/SOURCE/gui/lucidethumbs.cpp @ 242

Last change on this file since 242 was 230, checked in by Eugene Romanenko, 14 years ago

custom file dialog with preview

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