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

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

Writes into EA thumbnail of first page of document

File size: 10.6 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);
75
76static bool loadMMIOFuncs()
77{
78    bool res = false;
79    do
80    {
81        if ( DosLoadModule( NULL, 0, "MMIO", &mmioHndl ) != 0 )
82            break;
83        if ( DosQueryProcAddr( mmioHndl, 0, "mmioOpen", (PFN *)&pMmioOpen ) != 0 )
84            break;
85        if ( DosQueryProcAddr( mmioHndl, 0, "mmioWrite", (PFN *)&pMmioWrite ) != 0 )
86            break;
87        if ( DosQueryProcAddr( mmioHndl, 0, "mmioSetHeader", (PFN *)&pMmioSetHeader ) != 0 )
88            break;
89        if ( DosQueryProcAddr( mmioHndl, 0, "mmioClose", (PFN *)&pMmioClose ) != 0 )
90            break;
91
92        res = true;
93    } while (0);
94
95    atexit( freeMmio );
96
97    return res;
98}
99
100
101static bool saveToImage( char *pszFileName, char *format,
102                         ULONG width, ULONG height, ULONG row_size,
103                         ULONG bpp, char* src_buf )
104{
105    bool              ret = false;
106    MMIOINFO          mmioinfoTarget;
107    HMMIO             hmmioTarget;
108    PBYTE             pbBuffer = NULL;
109    ULONG             cbBuffer,cbBitmapInfo, rl;
110    ULONG             rc;
111    MMIMAGEHEADER     mmImgHdr;
112    BITMAPINFO2       bmp;
113    FOURCC            saveas;
114
115    rl = ( ( bpp * width + 31 ) / 32 ) * 4;
116    cbBuffer = rl * height;
117
118    if ( !format ) {
119        return ret;
120    }
121
122    saveas = mmioFOURCC( format[0], format[1], format[2], format[3] );
123
124    // fill bmp
125    memset( &bmp, 0, sizeof( bmp ) );
126    bmp.cbFix         = sizeof( bmp );
127    bmp.cx            = width;
128    bmp.cy            = height;
129    bmp.cPlanes       = 1;
130    bmp.cBitCount     = bpp;
131    bmp.ulCompression = 0;
132    bmp.cbImage       = cbBuffer;
133
134    cbBitmapInfo = sizeof( bmp );
135
136    memset( &mmioinfoTarget, 0L, sizeof( MMIOINFO ) );
137    mmioinfoTarget.fccIOProc = saveas;
138    mmioinfoTarget.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
139    hmmioTarget = pMmioOpen( pszFileName, &mmioinfoTarget, MMIO_CREATE | MMIO_WRITE |
140                                                        MMIO_DENYWRITE | MMIO_NOIDENTIFY );
141    if ( hmmioTarget )
142    {
143        ULONG ulBytesWritten;
144
145        memset( &mmImgHdr, 0, sizeof( MMIMAGEHEADER ) );
146        mmImgHdr.ulHeaderLength = sizeof(MMIMAGEHEADER);
147        mmImgHdr.ulContentType = MMIO_IMAGE_UNKNOWN;
148        mmImgHdr.ulMediaType = MMIO_MEDIATYPE_IMAGE;
149        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulMemSize = cbBuffer;
150        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulPelFormat = ( bpp < 24 ) ?
151                        mmioFOURCC('p','a','l','b') : mmioFOURCC('r','g','b','b');
152
153        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.usTransType = 0;
154        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulTransVal = 0;
155        memcpy( &mmImgHdr.mmXDIBHeader.BMPInfoHeader2, &bmp, cbBitmapInfo );
156        rc = pMmioSetHeader( hmmioTarget, &mmImgHdr, sizeof(MMIMAGEHEADER),
157                                    (PLONG)&ulBytesWritten, 0L, 0L);
158        if ( rc == MMIO_SUCCESS )
159        {
160            for ( int k=0; k < height; k++ )
161            {
162                char *line = src_buf + ( k * row_size );
163
164                ulBytesWritten = pMmioWrite( hmmioTarget, (char*)line, rl );
165
166                if ( ( ulBytesWritten == MMIO_ERROR ) || ( ulBytesWritten == 0 ) ) {
167                    break;
168                }
169            }
170
171            if ( ( ulBytesWritten != MMIO_ERROR ) && ( ulBytesWritten != 0 ) ) {
172                ret = true;
173            }
174        }
175
176        pMmioClose( hmmioTarget, 0L );
177    }
178
179    return ret;
180}
181
182static BOOL set_ea( const char *file_name, const char *ea_name,
183                    const char *ea_data, int ea_data_len )
184{
185    APIRET rc = 0;
186    EAOP2  op;
187
188    char *databuf = new char[(64*2*1024)+1024]; // twice 64K for EA data + 1024 for any case
189
190    op.fpGEA2List = (PGEA2LIST)0;
191    op.fpFEA2List = (PFEA2LIST)databuf;
192
193    int  ea_name_len = strlen( ea_name );
194    if ( ea_name_len > 255 ) {
195        delete databuf;
196        return FALSE;
197    }
198
199    char *databufp = databuf + sizeof( long );
200    *((long*)databufp) = 0; // Next field offset is zero - just one field here
201    databufp += sizeof(long);
202    *databufp++ = 0; // not critical
203    *databufp++ = (char)ea_name_len;
204    *((short*)databufp) = (short)ea_data_len;
205    databufp += sizeof(short);
206    memcpy( databufp, ea_name, ea_name_len+1 ); // with trailing zero
207    databufp += ea_name_len+1;
208    memcpy( databufp, ea_data, ea_data_len ); // with trailing zero
209    databufp += ea_data_len;
210
211    *((long*)databuf) = databufp-databuf; // Size of all that stuff
212
213    rc = DosSetPathInfo( file_name, FIL_QUERYEASIZE, &op, sizeof(op), 0);
214    delete databuf;
215    if ( rc != 0 ) {
216        return FALSE;
217    }
218
219    return TRUE;
220}
221
222bool Lucide::isThumbNeeded( const char *fn )
223{
224    // First, check if mmio is available
225    if ( !mmioFuncsLoaded ) {
226        return false;
227    }
228
229    // Second, check if file is writeable
230    if ( access( fn, W_OK ) != 0 ) {
231        // Isn't writable, do not waste time to render thumbnail
232        return false;
233    }
234
235    // Third, check if thumbnail EA already present
236    UCHAR    EnumBuf[200] = {0};      // Data Buffer
237    ULONG    ulEnumCnt    = 0;        // Count of entries to return
238    FEA2     *ptr         = NULL;     // Pointer to data items returned
239    ULONG    ulTemp       = 0;
240    APIRET   rc           = 0;
241
242    ulEnumCnt = (ULONG)-1; // Request as many attributes as will fit in buffer
243
244    rc = DosEnumAttribute( ENUMEA_REFTYPE_PATH, (PVOID)fn, 1L, &EnumBuf, sizeof( EnumBuf ),
245                           &ulEnumCnt, ENUMEA_LEVEL_NO_VALUE );
246
247    if ( rc != 0 ) {
248        // error look for EA names, return 'false' to prevent EA creation
249        // as if enum failed, creation may also fail
250        return false;
251    }
252
253    ptr = (FEA2 *)EnumBuf; // Mask the buffer pointer to an FEA2 structure
254
255    for ( ULONG i = 0; i < ulEnumCnt; i++ )
256    {
257        if ( strcmp( ptr->szName, LUTHUMB_EA_NAME ) == 0 ) {
258            return false; // Thumbnail already present
259        }
260        /// increment the ptr with the value in oNextEntryOffset
261        ulTemp = ptr->oNextEntryOffset + (ULONG)ptr;
262        ptr = (FEA2 *)ulTemp;
263    }
264    return true;
265}
266
267
268void Lucide::createThumbnail( LuDocument *doc )
269{
270    if ( !doc->isScalable( ev ) ) {
271        return;
272    }
273
274    // render first page
275    double width = 0, height = 0;
276    doc->getPageSize( ev, 0, &width, &height );
277    double zoom = __min( (double)LUTHUMB_SIZE_X / width, (double)LUTHUMB_SIZE_Y / height );
278    short bpp = doc->getBpp( ev );
279
280    long rx = width * zoom;
281    long ry = height * zoom;
282    LuPixbuf *pixbuf = new LuPixbuf( ev, rx, ry, bpp );
283    // TODO: analyze return value
284    doc->renderPageToPixbuf( ev, 0, 0, 0, rx, ry, zoom, 0, pixbuf );
285
286    char *tmpgif = new char[ CCHMAXPATH ];
287    getTmpDir( tmpgif );
288    strcat( tmpgif, "LUTHUMB.TMP" );
289
290    bool saved = saveToImage( tmpgif, "GIFC", rx, ry, pixbuf->getRowSize( ev ),
291                              bpp * 8, (char *)pixbuf->getDataPtr( ev ) );
292    delete pixbuf;
293    if ( saved )
294    {
295        // If image file saved, read file content into
296        // thumbnailData buffer, to be able write it into EA
297        // when document will be closed
298        int h = open( tmpgif, O_RDONLY | O_BINARY | O_NOINHERIT );
299        if ( h != -1 )
300        {
301            long flen = filelength( h );
302            if ( flen > 0 )
303            {
304                thumbnailData = new char[ flen ];
305                thumbnailDataLen = flen;
306                if ( read( h, thumbnailData, flen ) != flen ) {
307                    delete thumbnailData;
308                    thumbnailData = NULL;
309                    thumbnailDataLen = 0;
310                }
311            }
312            close( h );
313        }
314    }
315    // if tmp file exist - delete it
316    if ( access( tmpgif, F_OK ) == 0 ) {
317        unlink( tmpgif );
318    }
319    delete tmpgif;
320}
321
322void Lucide::writeThumbnail( const char *fn )
323{
324    if ( ( thumbnailData == NULL ) || ( thumbnailDataLen == 0 ) ) {
325        return;
326    }
327
328    set_ea( fn, LUTHUMB_EA_NAME, (const char *)thumbnailData, thumbnailDataLen );
329    delete thumbnailData;
330    thumbnailData = NULL;
331    thumbnailDataLen = 0;
332}
333
Note: See TracBrowser for help on using the repository browser.