xref: /aoo4110/main/svtools/source/filter/jpeg/jpeg.cxx (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*b1cdbd2cSJim Jagielski #include "precompiled_svtools.hxx"
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski #include <tools/solar.h>
28*b1cdbd2cSJim Jagielski 
29*b1cdbd2cSJim Jagielski extern "C"
30*b1cdbd2cSJim Jagielski {
31*b1cdbd2cSJim Jagielski 	#include "stdio.h"
32*b1cdbd2cSJim Jagielski 	#include "jpeg.h"
33*b1cdbd2cSJim Jagielski 	#include "jpeglib.h"
34*b1cdbd2cSJim Jagielski 	#include "jerror.h"
35*b1cdbd2cSJim Jagielski }
36*b1cdbd2cSJim Jagielski 
37*b1cdbd2cSJim Jagielski #define _JPEGPRIVATE
38*b1cdbd2cSJim Jagielski #include <vcl/bmpacc.hxx>
39*b1cdbd2cSJim Jagielski #include "jpeg.hxx"
40*b1cdbd2cSJim Jagielski #include <svtools/FilterConfigItem.hxx>
41*b1cdbd2cSJim Jagielski #include <svtools/filter.hxx>
42*b1cdbd2cSJim Jagielski 
43*b1cdbd2cSJim Jagielski // -----------
44*b1cdbd2cSJim Jagielski // - Defines -
45*b1cdbd2cSJim Jagielski // -----------
46*b1cdbd2cSJim Jagielski 
47*b1cdbd2cSJim Jagielski using namespace ::com::sun::star;
48*b1cdbd2cSJim Jagielski 
49*b1cdbd2cSJim Jagielski #define JPEGMINREAD 512
50*b1cdbd2cSJim Jagielski 
51*b1cdbd2cSJim Jagielski namespace {
52*b1cdbd2cSJim Jagielski     // Arbitrary maximal size (256M) of bitmaps after they have been decoded.
53*b1cdbd2cSJim Jagielski     // It is used to prevent excessive swapping due to large buffers in
54*b1cdbd2cSJim Jagielski     // virtual memory.
55*b1cdbd2cSJim Jagielski     // May have to be tuned if it turns out to be too large or too small.
56*b1cdbd2cSJim Jagielski     static const sal_uInt64 MAX_BITMAP_BYTE_SIZE = sal_uInt64(256 * 1024 * 1024);
57*b1cdbd2cSJim Jagielski }
58*b1cdbd2cSJim Jagielski 
59*b1cdbd2cSJim Jagielski // -------------
60*b1cdbd2cSJim Jagielski // - (C-Calls) -
61*b1cdbd2cSJim Jagielski // -------------
62*b1cdbd2cSJim Jagielski 
63*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
64*b1cdbd2cSJim Jagielski 
CreateBitmap(void * pJPEGReader,void * pJPEGCreateBitmapParam)65*b1cdbd2cSJim Jagielski extern "C" void* CreateBitmap( void* pJPEGReader, void* pJPEGCreateBitmapParam )
66*b1cdbd2cSJim Jagielski {
67*b1cdbd2cSJim Jagielski 	return ( (JPEGReader*) pJPEGReader )->CreateBitmap( pJPEGCreateBitmapParam );
68*b1cdbd2cSJim Jagielski }
69*b1cdbd2cSJim Jagielski 
70*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
71*b1cdbd2cSJim Jagielski 
GetScanline(void * pJPEGWriter,long nY)72*b1cdbd2cSJim Jagielski extern "C" void* GetScanline( void* pJPEGWriter, long nY )
73*b1cdbd2cSJim Jagielski {
74*b1cdbd2cSJim Jagielski 	return ( (JPEGWriter*) pJPEGWriter )->GetScanline( nY );
75*b1cdbd2cSJim Jagielski }
76*b1cdbd2cSJim Jagielski 
77*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
78*b1cdbd2cSJim Jagielski 
79*b1cdbd2cSJim Jagielski struct JPEGCallbackStruct
80*b1cdbd2cSJim Jagielski {
81*b1cdbd2cSJim Jagielski 	uno::Reference< task::XStatusIndicator > xStatusIndicator;
82*b1cdbd2cSJim Jagielski };
83*b1cdbd2cSJim Jagielski 
JPEGCallback(void * pCallbackData,long nPercent)84*b1cdbd2cSJim Jagielski extern "C" long JPEGCallback( void* pCallbackData, long nPercent )
85*b1cdbd2cSJim Jagielski {
86*b1cdbd2cSJim Jagielski 	JPEGCallbackStruct* pS = (JPEGCallbackStruct*)pCallbackData;
87*b1cdbd2cSJim Jagielski 	if ( pS && pS->xStatusIndicator.is() )
88*b1cdbd2cSJim Jagielski 	{
89*b1cdbd2cSJim Jagielski 		pS->xStatusIndicator->setValue( nPercent );
90*b1cdbd2cSJim Jagielski 	}
91*b1cdbd2cSJim Jagielski 	return 0L;
92*b1cdbd2cSJim Jagielski }
93*b1cdbd2cSJim Jagielski 
94*b1cdbd2cSJim Jagielski #define BUF_SIZE  4096
95*b1cdbd2cSJim Jagielski 
96*b1cdbd2cSJim Jagielski typedef struct
97*b1cdbd2cSJim Jagielski {
98*b1cdbd2cSJim Jagielski   struct jpeg_destination_mgr pub;  /* public fields */
99*b1cdbd2cSJim Jagielski 
100*b1cdbd2cSJim Jagielski   SvStream* outfile;                /* target stream */
101*b1cdbd2cSJim Jagielski   JOCTET * buffer;                  /* start of buffer */
102*b1cdbd2cSJim Jagielski } my_destination_mgr;
103*b1cdbd2cSJim Jagielski 
104*b1cdbd2cSJim Jagielski typedef my_destination_mgr * my_dest_ptr;
105*b1cdbd2cSJim Jagielski 
init_destination(j_compress_ptr cinfo)106*b1cdbd2cSJim Jagielski extern "C" void init_destination (j_compress_ptr cinfo)
107*b1cdbd2cSJim Jagielski {
108*b1cdbd2cSJim Jagielski   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
109*b1cdbd2cSJim Jagielski 
110*b1cdbd2cSJim Jagielski   /* Allocate the output buffer --- it will be released when done with image */
111*b1cdbd2cSJim Jagielski   dest->buffer = (JOCTET *)
112*b1cdbd2cSJim Jagielski       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
113*b1cdbd2cSJim Jagielski                                   BUF_SIZE * sizeof(JOCTET));
114*b1cdbd2cSJim Jagielski 
115*b1cdbd2cSJim Jagielski   dest->pub.next_output_byte = dest->buffer;
116*b1cdbd2cSJim Jagielski   dest->pub.free_in_buffer = BUF_SIZE;
117*b1cdbd2cSJim Jagielski }
118*b1cdbd2cSJim Jagielski 
empty_output_buffer(j_compress_ptr cinfo)119*b1cdbd2cSJim Jagielski extern "C" boolean empty_output_buffer (j_compress_ptr cinfo)
120*b1cdbd2cSJim Jagielski {
121*b1cdbd2cSJim Jagielski   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
122*b1cdbd2cSJim Jagielski 
123*b1cdbd2cSJim Jagielski   if (dest->outfile->Write(dest->buffer, BUF_SIZE) !=
124*b1cdbd2cSJim Jagielski       (size_t) BUF_SIZE)
125*b1cdbd2cSJim Jagielski     ERREXIT(cinfo, JERR_FILE_WRITE);
126*b1cdbd2cSJim Jagielski 
127*b1cdbd2cSJim Jagielski   dest->pub.next_output_byte = dest->buffer;
128*b1cdbd2cSJim Jagielski   dest->pub.free_in_buffer = BUF_SIZE;
129*b1cdbd2cSJim Jagielski 
130*b1cdbd2cSJim Jagielski   return sal_True;
131*b1cdbd2cSJim Jagielski }
132*b1cdbd2cSJim Jagielski 
term_destination(j_compress_ptr cinfo)133*b1cdbd2cSJim Jagielski extern "C" void term_destination (j_compress_ptr cinfo)
134*b1cdbd2cSJim Jagielski {
135*b1cdbd2cSJim Jagielski   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
136*b1cdbd2cSJim Jagielski   size_t datacount = BUF_SIZE - dest->pub.free_in_buffer;
137*b1cdbd2cSJim Jagielski 
138*b1cdbd2cSJim Jagielski   /* Write any data remaining in the buffer */
139*b1cdbd2cSJim Jagielski   if (datacount > 0) {
140*b1cdbd2cSJim Jagielski     if (dest->outfile->Write(dest->buffer, datacount) != datacount)
141*b1cdbd2cSJim Jagielski       ERREXIT(cinfo, JERR_FILE_WRITE);
142*b1cdbd2cSJim Jagielski   }
143*b1cdbd2cSJim Jagielski }
144*b1cdbd2cSJim Jagielski 
jpeg_svstream_dest(j_compress_ptr cinfo,void * out)145*b1cdbd2cSJim Jagielski extern "C" void jpeg_svstream_dest (j_compress_ptr cinfo, void* out)
146*b1cdbd2cSJim Jagielski {
147*b1cdbd2cSJim Jagielski   SvStream * outfile = (SvStream*)out;
148*b1cdbd2cSJim Jagielski   my_dest_ptr dest;
149*b1cdbd2cSJim Jagielski 
150*b1cdbd2cSJim Jagielski   /* The destination object is made permanent so that multiple JPEG images
151*b1cdbd2cSJim Jagielski    * can be written to the same file without re-executing jpeg_svstream_dest.
152*b1cdbd2cSJim Jagielski    * This makes it dangerous to use this manager and a different destination
153*b1cdbd2cSJim Jagielski    * manager serially with the same JPEG object, because their private object
154*b1cdbd2cSJim Jagielski    * sizes may be different.  Caveat programmer.
155*b1cdbd2cSJim Jagielski    */
156*b1cdbd2cSJim Jagielski   if (cinfo->dest == NULL) {    /* first time for this JPEG object? */
157*b1cdbd2cSJim Jagielski     cinfo->dest = (struct jpeg_destination_mgr *)
158*b1cdbd2cSJim Jagielski       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
159*b1cdbd2cSJim Jagielski                                   sizeof(my_destination_mgr));
160*b1cdbd2cSJim Jagielski   }
161*b1cdbd2cSJim Jagielski 
162*b1cdbd2cSJim Jagielski   dest = (my_dest_ptr) cinfo->dest;
163*b1cdbd2cSJim Jagielski   dest->pub.init_destination = init_destination;
164*b1cdbd2cSJim Jagielski   dest->pub.empty_output_buffer = empty_output_buffer;
165*b1cdbd2cSJim Jagielski   dest->pub.term_destination = term_destination;
166*b1cdbd2cSJim Jagielski   dest->outfile = outfile;
167*b1cdbd2cSJim Jagielski }
168*b1cdbd2cSJim Jagielski 
169*b1cdbd2cSJim Jagielski /* Expanded data source object for stdio input */
170*b1cdbd2cSJim Jagielski 
171*b1cdbd2cSJim Jagielski typedef struct {
172*b1cdbd2cSJim Jagielski   struct jpeg_source_mgr pub;   /* public fields */
173*b1cdbd2cSJim Jagielski 
174*b1cdbd2cSJim Jagielski   SvStream * infile;            /* source stream */
175*b1cdbd2cSJim Jagielski   JOCTET * buffer;              /* start of buffer */
176*b1cdbd2cSJim Jagielski   boolean start_of_file;        /* have we gotten any data yet? */
177*b1cdbd2cSJim Jagielski } my_source_mgr;
178*b1cdbd2cSJim Jagielski 
179*b1cdbd2cSJim Jagielski typedef my_source_mgr * my_src_ptr;
180*b1cdbd2cSJim Jagielski 
181*b1cdbd2cSJim Jagielski /*
182*b1cdbd2cSJim Jagielski  * Initialize source --- called by jpeg_read_header
183*b1cdbd2cSJim Jagielski  * before any data is actually read.
184*b1cdbd2cSJim Jagielski  */
185*b1cdbd2cSJim Jagielski 
init_source(j_decompress_ptr cinfo)186*b1cdbd2cSJim Jagielski extern "C" void init_source (j_decompress_ptr cinfo)
187*b1cdbd2cSJim Jagielski {
188*b1cdbd2cSJim Jagielski   my_src_ptr src = (my_src_ptr) cinfo->src;
189*b1cdbd2cSJim Jagielski 
190*b1cdbd2cSJim Jagielski   /* We reset the empty-input-file flag for each image,
191*b1cdbd2cSJim Jagielski    * but we don't clear the input buffer.
192*b1cdbd2cSJim Jagielski    * This is correct behavior for reading a series of images from one source.
193*b1cdbd2cSJim Jagielski    */
194*b1cdbd2cSJim Jagielski   src->start_of_file = sal_True;
195*b1cdbd2cSJim Jagielski }
196*b1cdbd2cSJim Jagielski 
StreamRead(SvStream * pSvStm,void * pBuffer,long nBufferSize)197*b1cdbd2cSJim Jagielski long StreamRead( SvStream* pSvStm, void* pBuffer, long nBufferSize )
198*b1cdbd2cSJim Jagielski {
199*b1cdbd2cSJim Jagielski         long            nRead;
200*b1cdbd2cSJim Jagielski 
201*b1cdbd2cSJim Jagielski         if( pSvStm->GetError() != ERRCODE_IO_PENDING )
202*b1cdbd2cSJim Jagielski         {
203*b1cdbd2cSJim Jagielski                 long nActPos = pSvStm->Tell();
204*b1cdbd2cSJim Jagielski 
205*b1cdbd2cSJim Jagielski                 nRead = (long) pSvStm->Read( pBuffer, nBufferSize );
206*b1cdbd2cSJim Jagielski 
207*b1cdbd2cSJim Jagielski                 if( pSvStm->GetError() == ERRCODE_IO_PENDING )
208*b1cdbd2cSJim Jagielski                 {
209*b1cdbd2cSJim Jagielski                         nRead = 0;
210*b1cdbd2cSJim Jagielski 
211*b1cdbd2cSJim Jagielski                         // Damit wir wieder an die alte Position
212*b1cdbd2cSJim Jagielski                         // seeken koennen, setzen wir den Error temp.zurueck
213*b1cdbd2cSJim Jagielski                         pSvStm->ResetError();
214*b1cdbd2cSJim Jagielski                         pSvStm->Seek( nActPos );
215*b1cdbd2cSJim Jagielski                         pSvStm->SetError( ERRCODE_IO_PENDING );
216*b1cdbd2cSJim Jagielski                 }
217*b1cdbd2cSJim Jagielski         }
218*b1cdbd2cSJim Jagielski         else
219*b1cdbd2cSJim Jagielski                 nRead = 0;
220*b1cdbd2cSJim Jagielski 
221*b1cdbd2cSJim Jagielski         return nRead;
222*b1cdbd2cSJim Jagielski }
223*b1cdbd2cSJim Jagielski 
fill_input_buffer(j_decompress_ptr cinfo)224*b1cdbd2cSJim Jagielski extern "C" boolean fill_input_buffer (j_decompress_ptr cinfo)
225*b1cdbd2cSJim Jagielski {
226*b1cdbd2cSJim Jagielski   my_src_ptr src = (my_src_ptr) cinfo->src;
227*b1cdbd2cSJim Jagielski   size_t nbytes;
228*b1cdbd2cSJim Jagielski 
229*b1cdbd2cSJim Jagielski   nbytes = StreamRead(src->infile, src->buffer, BUF_SIZE);
230*b1cdbd2cSJim Jagielski 
231*b1cdbd2cSJim Jagielski   if (nbytes <= 0) {
232*b1cdbd2cSJim Jagielski     if (src->start_of_file)     /* Treat empty input file as fatal error */
233*b1cdbd2cSJim Jagielski       ERREXIT(cinfo, JERR_INPUT_EMPTY);
234*b1cdbd2cSJim Jagielski     WARNMS(cinfo, JWRN_JPEG_EOF);
235*b1cdbd2cSJim Jagielski     /* Insert a fake EOI marker */
236*b1cdbd2cSJim Jagielski     src->buffer[0] = (JOCTET) 0xFF;
237*b1cdbd2cSJim Jagielski     src->buffer[1] = (JOCTET) JPEG_EOI;
238*b1cdbd2cSJim Jagielski     nbytes = 2;
239*b1cdbd2cSJim Jagielski   }
240*b1cdbd2cSJim Jagielski 
241*b1cdbd2cSJim Jagielski   src->pub.next_input_byte = src->buffer;
242*b1cdbd2cSJim Jagielski   src->pub.bytes_in_buffer = nbytes;
243*b1cdbd2cSJim Jagielski   src->start_of_file = sal_False;
244*b1cdbd2cSJim Jagielski 
245*b1cdbd2cSJim Jagielski   return sal_True;
246*b1cdbd2cSJim Jagielski }
247*b1cdbd2cSJim Jagielski 
skip_input_data(j_decompress_ptr cinfo,long num_bytes)248*b1cdbd2cSJim Jagielski extern "C" void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
249*b1cdbd2cSJim Jagielski {
250*b1cdbd2cSJim Jagielski   my_src_ptr src = (my_src_ptr) cinfo->src;
251*b1cdbd2cSJim Jagielski 
252*b1cdbd2cSJim Jagielski   /* Just a dumb implementation for now.  Could use fseek() except
253*b1cdbd2cSJim Jagielski    * it doesn't work on pipes.  Not clear that being smart is worth
254*b1cdbd2cSJim Jagielski    * any trouble anyway --- large skips are infrequent.
255*b1cdbd2cSJim Jagielski    */
256*b1cdbd2cSJim Jagielski   if (num_bytes > 0) {
257*b1cdbd2cSJim Jagielski     while (num_bytes > (long) src->pub.bytes_in_buffer) {
258*b1cdbd2cSJim Jagielski       num_bytes -= (long) src->pub.bytes_in_buffer;
259*b1cdbd2cSJim Jagielski       (void) fill_input_buffer(cinfo);
260*b1cdbd2cSJim Jagielski       /* note we assume that fill_input_buffer will never return sal_False,
261*b1cdbd2cSJim Jagielski        * so suspension need not be handled.
262*b1cdbd2cSJim Jagielski        */
263*b1cdbd2cSJim Jagielski     }
264*b1cdbd2cSJim Jagielski     src->pub.next_input_byte += (size_t) num_bytes;
265*b1cdbd2cSJim Jagielski     src->pub.bytes_in_buffer -= (size_t) num_bytes;
266*b1cdbd2cSJim Jagielski   }
267*b1cdbd2cSJim Jagielski }
268*b1cdbd2cSJim Jagielski 
term_source(j_decompress_ptr)269*b1cdbd2cSJim Jagielski extern "C" void term_source (j_decompress_ptr)
270*b1cdbd2cSJim Jagielski {
271*b1cdbd2cSJim Jagielski   /* no work necessary here */
272*b1cdbd2cSJim Jagielski }
273*b1cdbd2cSJim Jagielski 
jpeg_svstream_src(j_decompress_ptr cinfo,void * in)274*b1cdbd2cSJim Jagielski extern "C" void jpeg_svstream_src (j_decompress_ptr cinfo, void * in)
275*b1cdbd2cSJim Jagielski {
276*b1cdbd2cSJim Jagielski   my_src_ptr src;
277*b1cdbd2cSJim Jagielski   SvStream * infile = (SvStream*)in;
278*b1cdbd2cSJim Jagielski 
279*b1cdbd2cSJim Jagielski   /* The source object and input buffer are made permanent so that a series
280*b1cdbd2cSJim Jagielski    * of JPEG images can be read from the same file by calling jpeg_stdio_src
281*b1cdbd2cSJim Jagielski    * only before the first one.  (If we discarded the buffer at the end of
282*b1cdbd2cSJim Jagielski    * one image, we'd likely lose the start of the next one.)
283*b1cdbd2cSJim Jagielski    * This makes it unsafe to use this manager and a different source
284*b1cdbd2cSJim Jagielski    * manager serially with the same JPEG object.  Caveat programmer.
285*b1cdbd2cSJim Jagielski    */
286*b1cdbd2cSJim Jagielski   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
287*b1cdbd2cSJim Jagielski     cinfo->src = (struct jpeg_source_mgr *)
288*b1cdbd2cSJim Jagielski       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
289*b1cdbd2cSJim Jagielski                                   sizeof(my_source_mgr));
290*b1cdbd2cSJim Jagielski     src = (my_src_ptr) cinfo->src;
291*b1cdbd2cSJim Jagielski     src->buffer = (JOCTET *)
292*b1cdbd2cSJim Jagielski       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
293*b1cdbd2cSJim Jagielski                                   BUF_SIZE * sizeof(JOCTET));
294*b1cdbd2cSJim Jagielski   }
295*b1cdbd2cSJim Jagielski 
296*b1cdbd2cSJim Jagielski   src = (my_src_ptr) cinfo->src;
297*b1cdbd2cSJim Jagielski   src->pub.init_source = init_source;
298*b1cdbd2cSJim Jagielski   src->pub.fill_input_buffer = fill_input_buffer;
299*b1cdbd2cSJim Jagielski   src->pub.skip_input_data = skip_input_data;
300*b1cdbd2cSJim Jagielski   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
301*b1cdbd2cSJim Jagielski   src->pub.term_source = term_source;
302*b1cdbd2cSJim Jagielski   src->infile = infile;
303*b1cdbd2cSJim Jagielski   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
304*b1cdbd2cSJim Jagielski   src->pub.next_input_byte = NULL; /* until buffer loaded */
305*b1cdbd2cSJim Jagielski }
306*b1cdbd2cSJim Jagielski 
307*b1cdbd2cSJim Jagielski // --------------
308*b1cdbd2cSJim Jagielski // - JPEGReader -
309*b1cdbd2cSJim Jagielski // --------------
310*b1cdbd2cSJim Jagielski 
JPEGReader(SvStream & rStm,void *,sal_Bool bSetLS)311*b1cdbd2cSJim Jagielski JPEGReader::JPEGReader( SvStream& rStm, void* /*pCallData*/, sal_Bool bSetLS ) :
312*b1cdbd2cSJim Jagielski 		rIStm			( rStm ),
313*b1cdbd2cSJim Jagielski 		pAcc			( NULL ),
314*b1cdbd2cSJim Jagielski 		pAcc1			( NULL ),
315*b1cdbd2cSJim Jagielski 		pBuffer			( NULL ),
316*b1cdbd2cSJim Jagielski 		nLastPos		( rStm.Tell() ),
317*b1cdbd2cSJim Jagielski 		nLastLines		( 0 ),
318*b1cdbd2cSJim Jagielski         bSetLogSize     ( bSetLS )
319*b1cdbd2cSJim Jagielski {
320*b1cdbd2cSJim Jagielski 	maUpperName = String::CreateFromAscii( "SVIJPEG", 7 );
321*b1cdbd2cSJim Jagielski 	nFormerPos = nLastPos;
322*b1cdbd2cSJim Jagielski }
323*b1cdbd2cSJim Jagielski 
324*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
325*b1cdbd2cSJim Jagielski 
~JPEGReader()326*b1cdbd2cSJim Jagielski JPEGReader::~JPEGReader()
327*b1cdbd2cSJim Jagielski {
328*b1cdbd2cSJim Jagielski 	if( pBuffer )
329*b1cdbd2cSJim Jagielski 		rtl_freeMemory( pBuffer );
330*b1cdbd2cSJim Jagielski 
331*b1cdbd2cSJim Jagielski 	if( pAcc )
332*b1cdbd2cSJim Jagielski 		aBmp.ReleaseAccess( pAcc );
333*b1cdbd2cSJim Jagielski 
334*b1cdbd2cSJim Jagielski 	if( pAcc1 )
335*b1cdbd2cSJim Jagielski 		aBmp1.ReleaseAccess( pAcc1 );
336*b1cdbd2cSJim Jagielski }
337*b1cdbd2cSJim Jagielski 
338*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
339*b1cdbd2cSJim Jagielski 
CreateBitmap(void * pParam)340*b1cdbd2cSJim Jagielski void* JPEGReader::CreateBitmap( void* pParam )
341*b1cdbd2cSJim Jagielski {
342*b1cdbd2cSJim Jagielski     Size        aSize( ((JPEGCreateBitmapParam*)pParam)->nWidth,
343*b1cdbd2cSJim Jagielski                         ((JPEGCreateBitmapParam*)pParam)->nHeight );
344*b1cdbd2cSJim Jagielski     sal_Bool    bGray = ((JPEGCreateBitmapParam*)pParam)->bGray != 0;
345*b1cdbd2cSJim Jagielski 
346*b1cdbd2cSJim Jagielski     void* pBmpBuf = NULL;
347*b1cdbd2cSJim Jagielski 
348*b1cdbd2cSJim Jagielski     if( pAcc )
349*b1cdbd2cSJim Jagielski     {
350*b1cdbd2cSJim Jagielski         aBmp.ReleaseAccess( pAcc );
351*b1cdbd2cSJim Jagielski         aBmp = Bitmap();
352*b1cdbd2cSJim Jagielski         pAcc = NULL;
353*b1cdbd2cSJim Jagielski     }
354*b1cdbd2cSJim Jagielski 
355*b1cdbd2cSJim Jagielski     // Check if the bitmap is untypically large.
356*b1cdbd2cSJim Jagielski     if (aSize.Width()<=0
357*b1cdbd2cSJim Jagielski         || aSize.Height()<=0
358*b1cdbd2cSJim Jagielski         || sal_uInt64(aSize.Width())*sal_uInt64(aSize.Height())*(bGray?1:3) > MAX_BITMAP_BYTE_SIZE)
359*b1cdbd2cSJim Jagielski     {
360*b1cdbd2cSJim Jagielski         // Do not try to acquire resources for the large bitmap or to
361*b1cdbd2cSJim Jagielski         // read the bitmap into memory.
362*b1cdbd2cSJim Jagielski         return NULL;
363*b1cdbd2cSJim Jagielski     }
364*b1cdbd2cSJim Jagielski 
365*b1cdbd2cSJim Jagielski 	if( bGray )
366*b1cdbd2cSJim Jagielski 	{
367*b1cdbd2cSJim Jagielski 		BitmapPalette aGrayPal( 256 );
368*b1cdbd2cSJim Jagielski 
369*b1cdbd2cSJim Jagielski 		for( sal_uInt16 n = 0; n < 256; n++ )
370*b1cdbd2cSJim Jagielski 		{
371*b1cdbd2cSJim Jagielski 			const sal_uInt8 cGray = (sal_uInt8) n;
372*b1cdbd2cSJim Jagielski 			aGrayPal[ n ] = BitmapColor( cGray, cGray, cGray );
373*b1cdbd2cSJim Jagielski 		}
374*b1cdbd2cSJim Jagielski 
375*b1cdbd2cSJim Jagielski 		aBmp = Bitmap( aSize, 8, &aGrayPal );
376*b1cdbd2cSJim Jagielski 	}
377*b1cdbd2cSJim Jagielski 	else
378*b1cdbd2cSJim Jagielski 		aBmp = Bitmap( aSize, 24 );
379*b1cdbd2cSJim Jagielski 
380*b1cdbd2cSJim Jagielski     if ( bSetLogSize )
381*b1cdbd2cSJim Jagielski     {
382*b1cdbd2cSJim Jagielski         unsigned long nUnit = ((JPEGCreateBitmapParam*)pParam)->density_unit;
383*b1cdbd2cSJim Jagielski 
384*b1cdbd2cSJim Jagielski         if( ( ( 1 == nUnit ) || ( 2 == nUnit ) ) &&
385*b1cdbd2cSJim Jagielski             ( (JPEGCreateBitmapParam*) pParam )->X_density &&
386*b1cdbd2cSJim Jagielski             ( (JPEGCreateBitmapParam*) pParam )->Y_density )
387*b1cdbd2cSJim Jagielski         {
388*b1cdbd2cSJim Jagielski             Point       aEmptyPoint;
389*b1cdbd2cSJim Jagielski 	        Fraction	aFractX( 1, ((JPEGCreateBitmapParam*)pParam)->X_density );
390*b1cdbd2cSJim Jagielski 	        Fraction	aFractY( 1, ((JPEGCreateBitmapParam*)pParam)->Y_density );
391*b1cdbd2cSJim Jagielski 	        MapMode		aMapMode( nUnit == 1 ? MAP_INCH : MAP_CM, aEmptyPoint, aFractX, aFractY );
392*b1cdbd2cSJim Jagielski 	        Size		aPrefSize = OutputDevice::LogicToLogic( aSize, aMapMode, MAP_100TH_MM );
393*b1cdbd2cSJim Jagielski 
394*b1cdbd2cSJim Jagielski             aBmp.SetPrefSize( aPrefSize );
395*b1cdbd2cSJim Jagielski             aBmp.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
396*b1cdbd2cSJim Jagielski         }
397*b1cdbd2cSJim Jagielski     }
398*b1cdbd2cSJim Jagielski 
399*b1cdbd2cSJim Jagielski     pAcc = aBmp.AcquireWriteAccess();
400*b1cdbd2cSJim Jagielski 
401*b1cdbd2cSJim Jagielski     if( pAcc )
402*b1cdbd2cSJim Jagielski     {
403*b1cdbd2cSJim Jagielski         long nAlignedWidth;
404*b1cdbd2cSJim Jagielski 
405*b1cdbd2cSJim Jagielski 		const sal_uLong nFormat = pAcc->GetScanlineFormat();
406*b1cdbd2cSJim Jagielski 
407*b1cdbd2cSJim Jagielski 		if(
408*b1cdbd2cSJim Jagielski 			( bGray && ( BMP_FORMAT_8BIT_PAL == nFormat ) ) ||
409*b1cdbd2cSJim Jagielski 			( !bGray && ( BMP_FORMAT_24BIT_TC_RGB == nFormat ) )
410*b1cdbd2cSJim Jagielski 		  )
411*b1cdbd2cSJim Jagielski 		{
412*b1cdbd2cSJim Jagielski 			pBmpBuf = pAcc->GetBuffer();
413*b1cdbd2cSJim Jagielski 			nAlignedWidth = pAcc->GetScanlineSize();
414*b1cdbd2cSJim Jagielski 			((JPEGCreateBitmapParam*)pParam)->bTopDown = pAcc->IsTopDown();
415*b1cdbd2cSJim Jagielski 		}
416*b1cdbd2cSJim Jagielski 		else
417*b1cdbd2cSJim Jagielski 		{
418*b1cdbd2cSJim Jagielski 			nAlignedWidth = AlignedWidth4Bytes( aSize.Width() * ( bGray ? 8 : 24 ) );
419*b1cdbd2cSJim Jagielski 			((JPEGCreateBitmapParam*)pParam)->bTopDown = sal_True;
420*b1cdbd2cSJim Jagielski 			pBmpBuf = pBuffer = rtl_allocateMemory( nAlignedWidth * aSize.Height() );
421*b1cdbd2cSJim Jagielski 		}
422*b1cdbd2cSJim Jagielski 
423*b1cdbd2cSJim Jagielski         // clean up, if no Bitmap buffer can be provided.
424*b1cdbd2cSJim Jagielski         if ( pBmpBuf == 0 )
425*b1cdbd2cSJim Jagielski         {
426*b1cdbd2cSJim Jagielski             aBmp.ReleaseAccess( pAcc );
427*b1cdbd2cSJim Jagielski             aBmp = Bitmap();
428*b1cdbd2cSJim Jagielski             pAcc = NULL;
429*b1cdbd2cSJim Jagielski         }
430*b1cdbd2cSJim Jagielski 
431*b1cdbd2cSJim Jagielski         ((JPEGCreateBitmapParam*)pParam)->nAlignedWidth = nAlignedWidth;
432*b1cdbd2cSJim Jagielski     }
433*b1cdbd2cSJim Jagielski 
434*b1cdbd2cSJim Jagielski     return pBmpBuf;
435*b1cdbd2cSJim Jagielski }
436*b1cdbd2cSJim Jagielski 
437*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
438*b1cdbd2cSJim Jagielski 
FillBitmap()439*b1cdbd2cSJim Jagielski void JPEGReader::FillBitmap()
440*b1cdbd2cSJim Jagielski {
441*b1cdbd2cSJim Jagielski 	if( pBuffer && pAcc )
442*b1cdbd2cSJim Jagielski 	{
443*b1cdbd2cSJim Jagielski 		HPBYTE		pTmp;
444*b1cdbd2cSJim Jagielski 		BitmapColor	aColor;
445*b1cdbd2cSJim Jagielski 		long		nAlignedWidth;
446*b1cdbd2cSJim Jagielski 		long		nWidth = pAcc->Width();
447*b1cdbd2cSJim Jagielski 		long		nHeight = pAcc->Height();
448*b1cdbd2cSJim Jagielski 
449*b1cdbd2cSJim Jagielski 		if( pAcc->GetBitCount() == 8 )
450*b1cdbd2cSJim Jagielski 		{
451*b1cdbd2cSJim Jagielski 			BitmapColor* pCols = new BitmapColor[ 256 ];
452*b1cdbd2cSJim Jagielski 
453*b1cdbd2cSJim Jagielski 			for( sal_uInt16 n = 0; n < 256; n++ )
454*b1cdbd2cSJim Jagielski 			{
455*b1cdbd2cSJim Jagielski 				const sal_uInt8 cGray = (sal_uInt8) n;
456*b1cdbd2cSJim Jagielski 				pCols[ n ] = pAcc->GetBestMatchingColor( BitmapColor( cGray, cGray, cGray ) );
457*b1cdbd2cSJim Jagielski 			}
458*b1cdbd2cSJim Jagielski 
459*b1cdbd2cSJim Jagielski 			nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 8L );
460*b1cdbd2cSJim Jagielski 
461*b1cdbd2cSJim Jagielski 			for( long nY = 0L; nY < nHeight; nY++ )
462*b1cdbd2cSJim Jagielski 			{
463*b1cdbd2cSJim Jagielski 				pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth;
464*b1cdbd2cSJim Jagielski 
465*b1cdbd2cSJim Jagielski 				for( long nX = 0L; nX < nWidth; nX++ )
466*b1cdbd2cSJim Jagielski 					pAcc->SetPixel( nY, nX, pCols[ *pTmp++ ] );
467*b1cdbd2cSJim Jagielski 			}
468*b1cdbd2cSJim Jagielski 
469*b1cdbd2cSJim Jagielski 			delete[] pCols;
470*b1cdbd2cSJim Jagielski 		}
471*b1cdbd2cSJim Jagielski 		else
472*b1cdbd2cSJim Jagielski 		{
473*b1cdbd2cSJim Jagielski 			nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 24L );
474*b1cdbd2cSJim Jagielski 
475*b1cdbd2cSJim Jagielski 			for( long nY = 0L; nY < nHeight; nY++ )
476*b1cdbd2cSJim Jagielski 			{
477*b1cdbd2cSJim Jagielski                 // #122985# Added fast-lane implementations using CopyScanline with direct supported mem formats
478*b1cdbd2cSJim Jagielski                 static bool bCheckOwnReader(true);
479*b1cdbd2cSJim Jagielski 
480*b1cdbd2cSJim Jagielski                 if(bCheckOwnReader)
481*b1cdbd2cSJim Jagielski                 {
482*b1cdbd2cSJim Jagielski                     // #122985# Trying to copy the RGB data from jpeg import to make things faster. Unfortunately
483*b1cdbd2cSJim Jagielski                     // it has no GBR format, so RGB three-byte groups need to be 'flipped' to GBR first,
484*b1cdbd2cSJim Jagielski                     // then CopyScanline can use a memcpy to do the data transport. CopyScanline can also
485*b1cdbd2cSJim Jagielski                     // do the needed conversion from BMP_FORMAT_24BIT_TC_RGB (and it works well), but this
486*b1cdbd2cSJim Jagielski                     // is not faster that the old loop below using SetPixel.
487*b1cdbd2cSJim Jagielski                     sal_uInt8* aSource((sal_uInt8*)pBuffer + nY * nAlignedWidth);
488*b1cdbd2cSJim Jagielski                     sal_uInt8* aEnd(aSource + (nWidth * 3));
489*b1cdbd2cSJim Jagielski 
490*b1cdbd2cSJim Jagielski                     for(sal_uInt8* aTmp(aSource); aTmp < aEnd; aTmp += 3)
491*b1cdbd2cSJim Jagielski                     {
492*b1cdbd2cSJim Jagielski                         ::std::swap(*aTmp, *(aTmp + 2));
493*b1cdbd2cSJim Jagielski                     }
494*b1cdbd2cSJim Jagielski 
495*b1cdbd2cSJim Jagielski                     pAcc->CopyScanline(nY, aSource, BMP_FORMAT_24BIT_TC_BGR, nWidth * 3);
496*b1cdbd2cSJim Jagielski                 }
497*b1cdbd2cSJim Jagielski                 else
498*b1cdbd2cSJim Jagielski                 {
499*b1cdbd2cSJim Jagielski                     // old version: WritePixel
500*b1cdbd2cSJim Jagielski                     pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth;
501*b1cdbd2cSJim Jagielski 
502*b1cdbd2cSJim Jagielski                     for( long nX = 0L; nX < nWidth; nX++ )
503*b1cdbd2cSJim Jagielski                     {
504*b1cdbd2cSJim Jagielski                         aColor.SetRed( *pTmp++ );
505*b1cdbd2cSJim Jagielski                         aColor.SetGreen( *pTmp++ );
506*b1cdbd2cSJim Jagielski                         aColor.SetBlue( *pTmp++ );
507*b1cdbd2cSJim Jagielski                         pAcc->SetPixel( nY, nX, aColor );
508*b1cdbd2cSJim Jagielski                     }
509*b1cdbd2cSJim Jagielski                 }
510*b1cdbd2cSJim Jagielski 			}
511*b1cdbd2cSJim Jagielski 		}
512*b1cdbd2cSJim Jagielski 	}
513*b1cdbd2cSJim Jagielski }
514*b1cdbd2cSJim Jagielski 
515*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
516*b1cdbd2cSJim Jagielski 
CreateIntermediateGraphic(const Bitmap & rBitmap,long nLines)517*b1cdbd2cSJim Jagielski Graphic JPEGReader::CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines )
518*b1cdbd2cSJim Jagielski {
519*b1cdbd2cSJim Jagielski 	Graphic		aGraphic;
520*b1cdbd2cSJim Jagielski 	const Size	aSizePix( rBitmap.GetSizePixel() );
521*b1cdbd2cSJim Jagielski 
522*b1cdbd2cSJim Jagielski 	if( !nLastLines )
523*b1cdbd2cSJim Jagielski 	{
524*b1cdbd2cSJim Jagielski 		if( pAcc1 )
525*b1cdbd2cSJim Jagielski 			aBmp1.ReleaseAccess( pAcc1 );
526*b1cdbd2cSJim Jagielski 
527*b1cdbd2cSJim Jagielski 		aBmp1 = Bitmap( rBitmap.GetSizePixel(), 1 );
528*b1cdbd2cSJim Jagielski 		aBmp1.Erase( Color( COL_WHITE ) );
529*b1cdbd2cSJim Jagielski 		pAcc1 = aBmp1.AcquireWriteAccess();
530*b1cdbd2cSJim Jagielski 	}
531*b1cdbd2cSJim Jagielski 
532*b1cdbd2cSJim Jagielski 	if( nLines && ( nLines < aSizePix.Height() ) )
533*b1cdbd2cSJim Jagielski 	{
534*b1cdbd2cSJim Jagielski 		if( pAcc1 )
535*b1cdbd2cSJim Jagielski 		{
536*b1cdbd2cSJim Jagielski 			const long nNewLines = nLines - nLastLines;
537*b1cdbd2cSJim Jagielski 
538*b1cdbd2cSJim Jagielski 			if( nNewLines )
539*b1cdbd2cSJim Jagielski 			{
540*b1cdbd2cSJim Jagielski 				pAcc1->SetFillColor( Color( COL_BLACK ) );
541*b1cdbd2cSJim Jagielski 				pAcc1->FillRect( Rectangle( Point( 0, nLastLines ),
542*b1cdbd2cSJim Jagielski 											Size( pAcc1->Width(), nNewLines ) ) );
543*b1cdbd2cSJim Jagielski 			}
544*b1cdbd2cSJim Jagielski 
545*b1cdbd2cSJim Jagielski 			aBmp1.ReleaseAccess( pAcc1 );
546*b1cdbd2cSJim Jagielski 			aGraphic = BitmapEx( rBitmap, aBmp1 );
547*b1cdbd2cSJim Jagielski 			pAcc1 = aBmp1.AcquireWriteAccess();
548*b1cdbd2cSJim Jagielski 		}
549*b1cdbd2cSJim Jagielski 		else
550*b1cdbd2cSJim Jagielski 			aGraphic = rBitmap;
551*b1cdbd2cSJim Jagielski 	}
552*b1cdbd2cSJim Jagielski 	else
553*b1cdbd2cSJim Jagielski 		aGraphic = rBitmap;
554*b1cdbd2cSJim Jagielski 
555*b1cdbd2cSJim Jagielski 	nLastLines = nLines;
556*b1cdbd2cSJim Jagielski 
557*b1cdbd2cSJim Jagielski 	return aGraphic;
558*b1cdbd2cSJim Jagielski }
559*b1cdbd2cSJim Jagielski 
560*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
561*b1cdbd2cSJim Jagielski 
Read(Graphic & rGraphic)562*b1cdbd2cSJim Jagielski ReadState JPEGReader::Read( Graphic& rGraphic )
563*b1cdbd2cSJim Jagielski {
564*b1cdbd2cSJim Jagielski 	long		nEndPos;
565*b1cdbd2cSJim Jagielski 	long		nLines;
566*b1cdbd2cSJim Jagielski 	ReadState	eReadState;
567*b1cdbd2cSJim Jagielski 	sal_Bool		bRet = sal_False;
568*b1cdbd2cSJim Jagielski 	sal_uInt8		cDummy;
569*b1cdbd2cSJim Jagielski 
570*b1cdbd2cSJim Jagielski #if 1 // TODO: is it possible to get rid of this seek to the end?
571*b1cdbd2cSJim Jagielski 	// check if the stream's end is already available
572*b1cdbd2cSJim Jagielski 	rIStm.Seek( STREAM_SEEK_TO_END );
573*b1cdbd2cSJim Jagielski 	rIStm >> cDummy;
574*b1cdbd2cSJim Jagielski 	nEndPos = rIStm.Tell();
575*b1cdbd2cSJim Jagielski 
576*b1cdbd2cSJim Jagielski 	// else check if at least JPEGMINREAD bytes can be read
577*b1cdbd2cSJim Jagielski 	if( rIStm.GetError() == ERRCODE_IO_PENDING )
578*b1cdbd2cSJim Jagielski 	{
579*b1cdbd2cSJim Jagielski 		rIStm.ResetError();
580*b1cdbd2cSJim Jagielski 		if( ( nEndPos  - nFormerPos ) < JPEGMINREAD )
581*b1cdbd2cSJim Jagielski 		{
582*b1cdbd2cSJim Jagielski 			rIStm.Seek( nLastPos );
583*b1cdbd2cSJim Jagielski 			return JPEGREAD_NEED_MORE;
584*b1cdbd2cSJim Jagielski 		}
585*b1cdbd2cSJim Jagielski 	}
586*b1cdbd2cSJim Jagielski 
587*b1cdbd2cSJim Jagielski 	// seek back to the original position
588*b1cdbd2cSJim Jagielski 	rIStm.Seek( nLastPos );
589*b1cdbd2cSJim Jagielski #endif
590*b1cdbd2cSJim Jagielski 
591*b1cdbd2cSJim Jagielski     Size aPreviewSize = GetPreviewSize();
592*b1cdbd2cSJim Jagielski     SetJpegPreviewSizeHint( aPreviewSize.Width(), aPreviewSize.Height() );
593*b1cdbd2cSJim Jagielski 
594*b1cdbd2cSJim Jagielski 	// read the (partial) image
595*b1cdbd2cSJim Jagielski 	ReadJPEG( this, &rIStm, &nLines );
596*b1cdbd2cSJim Jagielski 
597*b1cdbd2cSJim Jagielski 	if( pAcc )
598*b1cdbd2cSJim Jagielski 	{
599*b1cdbd2cSJim Jagielski 		if( pBuffer )
600*b1cdbd2cSJim Jagielski 		{
601*b1cdbd2cSJim Jagielski 			FillBitmap();
602*b1cdbd2cSJim Jagielski 			rtl_freeMemory( pBuffer );
603*b1cdbd2cSJim Jagielski 			pBuffer = NULL;
604*b1cdbd2cSJim Jagielski 		}
605*b1cdbd2cSJim Jagielski 
606*b1cdbd2cSJim Jagielski 		aBmp.ReleaseAccess( pAcc );
607*b1cdbd2cSJim Jagielski 		pAcc = NULL;
608*b1cdbd2cSJim Jagielski 
609*b1cdbd2cSJim Jagielski 		if( rIStm.GetError() == ERRCODE_IO_PENDING )
610*b1cdbd2cSJim Jagielski 			rGraphic = CreateIntermediateGraphic( aBmp, nLines );
611*b1cdbd2cSJim Jagielski 		else
612*b1cdbd2cSJim Jagielski 			rGraphic = aBmp;
613*b1cdbd2cSJim Jagielski 
614*b1cdbd2cSJim Jagielski 		bRet = sal_True;
615*b1cdbd2cSJim Jagielski 	}
616*b1cdbd2cSJim Jagielski 	else if( rIStm.GetError() == ERRCODE_IO_PENDING )
617*b1cdbd2cSJim Jagielski 		bRet = sal_True;
618*b1cdbd2cSJim Jagielski 
619*b1cdbd2cSJim Jagielski 	// Status setzen ( Pending hat immer Vorrang )
620*b1cdbd2cSJim Jagielski 	if( rIStm.GetError() == ERRCODE_IO_PENDING )
621*b1cdbd2cSJim Jagielski 	{
622*b1cdbd2cSJim Jagielski 		eReadState = JPEGREAD_NEED_MORE;
623*b1cdbd2cSJim Jagielski 		rIStm.ResetError();
624*b1cdbd2cSJim Jagielski 		nFormerPos = rIStm.Tell();
625*b1cdbd2cSJim Jagielski 	}
626*b1cdbd2cSJim Jagielski 	else
627*b1cdbd2cSJim Jagielski 	{
628*b1cdbd2cSJim Jagielski 		if( bRet )
629*b1cdbd2cSJim Jagielski 			eReadState = JPEGREAD_OK;
630*b1cdbd2cSJim Jagielski 		else
631*b1cdbd2cSJim Jagielski 			eReadState = JPEGREAD_ERROR;
632*b1cdbd2cSJim Jagielski 	}
633*b1cdbd2cSJim Jagielski 
634*b1cdbd2cSJim Jagielski 	return eReadState;
635*b1cdbd2cSJim Jagielski }
636*b1cdbd2cSJim Jagielski 
637*b1cdbd2cSJim Jagielski 
638*b1cdbd2cSJim Jagielski // --------------
639*b1cdbd2cSJim Jagielski // - JPEGWriter -
640*b1cdbd2cSJim Jagielski // --------------
641*b1cdbd2cSJim Jagielski 
JPEGWriter(SvStream & rStm,const uno::Sequence<beans::PropertyValue> * pFilterData,bool * pExportWasGrey)642*b1cdbd2cSJim Jagielski JPEGWriter::JPEGWriter( SvStream& rStm, const uno::Sequence< beans::PropertyValue >* pFilterData, bool* pExportWasGrey ) :
643*b1cdbd2cSJim Jagielski 		rOStm		( rStm ),
644*b1cdbd2cSJim Jagielski 		pAcc		( NULL ),
645*b1cdbd2cSJim Jagielski 		pBuffer		( NULL ),
646*b1cdbd2cSJim Jagielski 		pExpWasGrey ( pExportWasGrey )
647*b1cdbd2cSJim Jagielski {
648*b1cdbd2cSJim Jagielski 	FilterConfigItem aConfigItem( (uno::Sequence< beans::PropertyValue >*)pFilterData );
649*b1cdbd2cSJim Jagielski 	bGreys = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "ColorMode" ) ), 0 ) != 0;
650*b1cdbd2cSJim Jagielski 	nQuality = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ), 75 );
651*b1cdbd2cSJim Jagielski 
652*b1cdbd2cSJim Jagielski 	if ( pFilterData )
653*b1cdbd2cSJim Jagielski 	{
654*b1cdbd2cSJim Jagielski 		int nArgs = pFilterData->getLength();
655*b1cdbd2cSJim Jagielski 		const beans::PropertyValue* pValues = pFilterData->getConstArray();
656*b1cdbd2cSJim Jagielski 		while( nArgs-- )
657*b1cdbd2cSJim Jagielski 		{
658*b1cdbd2cSJim Jagielski 			if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StatusIndicator" ) ) )
659*b1cdbd2cSJim Jagielski 			{
660*b1cdbd2cSJim Jagielski 				pValues->Value >>= xStatusIndicator;
661*b1cdbd2cSJim Jagielski 			}
662*b1cdbd2cSJim Jagielski 			pValues++;
663*b1cdbd2cSJim Jagielski 		}
664*b1cdbd2cSJim Jagielski 	}
665*b1cdbd2cSJim Jagielski }
666*b1cdbd2cSJim Jagielski 
667*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
668*b1cdbd2cSJim Jagielski 
GetScanline(long nY)669*b1cdbd2cSJim Jagielski void* JPEGWriter::GetScanline( long nY )
670*b1cdbd2cSJim Jagielski {
671*b1cdbd2cSJim Jagielski 	void* pScanline = NULL;
672*b1cdbd2cSJim Jagielski 
673*b1cdbd2cSJim Jagielski 	if( pAcc )
674*b1cdbd2cSJim Jagielski 	{
675*b1cdbd2cSJim Jagielski 		if( bNative )
676*b1cdbd2cSJim Jagielski 			pScanline = pAcc->GetScanline( nY );
677*b1cdbd2cSJim Jagielski 		else if( pBuffer )
678*b1cdbd2cSJim Jagielski 		{
679*b1cdbd2cSJim Jagielski 			BitmapColor aColor;
680*b1cdbd2cSJim Jagielski 			long		nWidth = pAcc->Width();
681*b1cdbd2cSJim Jagielski 			sal_uInt8*		pTmp = pBuffer;
682*b1cdbd2cSJim Jagielski 
683*b1cdbd2cSJim Jagielski 			if( pAcc->HasPalette() )
684*b1cdbd2cSJim Jagielski 			{
685*b1cdbd2cSJim Jagielski 				for( long nX = 0L; nX < nWidth; nX++ )
686*b1cdbd2cSJim Jagielski 				{
687*b1cdbd2cSJim Jagielski 					aColor = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nY, nX ) );
688*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetRed();
689*b1cdbd2cSJim Jagielski 					if ( bGreys )
690*b1cdbd2cSJim Jagielski 						continue;
691*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetGreen();
692*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetBlue();
693*b1cdbd2cSJim Jagielski 				}
694*b1cdbd2cSJim Jagielski 			}
695*b1cdbd2cSJim Jagielski 			else
696*b1cdbd2cSJim Jagielski 			{
697*b1cdbd2cSJim Jagielski 				for( long nX = 0L; nX < nWidth; nX++ )
698*b1cdbd2cSJim Jagielski 				{
699*b1cdbd2cSJim Jagielski 					aColor = pAcc->GetPixel( nY, nX );
700*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetRed();
701*b1cdbd2cSJim Jagielski 					if ( bGreys )
702*b1cdbd2cSJim Jagielski 						continue;
703*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetGreen();
704*b1cdbd2cSJim Jagielski 					*pTmp++ = aColor.GetBlue();
705*b1cdbd2cSJim Jagielski 				}
706*b1cdbd2cSJim Jagielski 			}
707*b1cdbd2cSJim Jagielski 
708*b1cdbd2cSJim Jagielski 			pScanline = pBuffer;
709*b1cdbd2cSJim Jagielski 		}
710*b1cdbd2cSJim Jagielski 	}
711*b1cdbd2cSJim Jagielski 
712*b1cdbd2cSJim Jagielski 	return pScanline;
713*b1cdbd2cSJim Jagielski }
714*b1cdbd2cSJim Jagielski 
715*b1cdbd2cSJim Jagielski // ------------------------------------------------------------------------
716*b1cdbd2cSJim Jagielski 
Write(const Graphic & rGraphic)717*b1cdbd2cSJim Jagielski sal_Bool JPEGWriter::Write( const Graphic& rGraphic )
718*b1cdbd2cSJim Jagielski {
719*b1cdbd2cSJim Jagielski 	sal_Bool bRet = sal_False;
720*b1cdbd2cSJim Jagielski 
721*b1cdbd2cSJim Jagielski 	if ( xStatusIndicator.is() )
722*b1cdbd2cSJim Jagielski 	{
723*b1cdbd2cSJim Jagielski 		rtl::OUString aMsg;
724*b1cdbd2cSJim Jagielski 		xStatusIndicator->start( aMsg, 100 );
725*b1cdbd2cSJim Jagielski 	}
726*b1cdbd2cSJim Jagielski 
727*b1cdbd2cSJim Jagielski 	Bitmap aGraphicBmp( rGraphic.GetBitmap() );
728*b1cdbd2cSJim Jagielski 
729*b1cdbd2cSJim Jagielski 	if ( bGreys )
730*b1cdbd2cSJim Jagielski 	{
731*b1cdbd2cSJim Jagielski 		if ( !aGraphicBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
732*b1cdbd2cSJim Jagielski 			aGraphicBmp = rGraphic.GetBitmap();
733*b1cdbd2cSJim Jagielski 	}
734*b1cdbd2cSJim Jagielski 
735*b1cdbd2cSJim Jagielski 	pAcc = aGraphicBmp.AcquireReadAccess();
736*b1cdbd2cSJim Jagielski 
737*b1cdbd2cSJim Jagielski 	if ( !bGreys )	// bitmap was not explicitely converted into greyscale,
738*b1cdbd2cSJim Jagielski 	{				// check if source is greyscale only
739*b1cdbd2cSJim Jagielski 
740*b1cdbd2cSJim Jagielski 		sal_Bool bIsGrey = sal_True;
741*b1cdbd2cSJim Jagielski 
742*b1cdbd2cSJim Jagielski 		long nWidth = pAcc->Width();
743*b1cdbd2cSJim Jagielski 		for ( long nY = 0; bIsGrey && ( nY < pAcc->Height() ); nY++ )
744*b1cdbd2cSJim Jagielski 		{
745*b1cdbd2cSJim Jagielski 			BitmapColor aColor;
746*b1cdbd2cSJim Jagielski 			for( long nX = 0L; bIsGrey && ( nX < nWidth ); nX++ )
747*b1cdbd2cSJim Jagielski 			{
748*b1cdbd2cSJim Jagielski 				aColor = pAcc->HasPalette() ? pAcc->GetPaletteColor( pAcc->GetPixelIndex( nY, nX ) )
749*b1cdbd2cSJim Jagielski 											: pAcc->GetPixel( nY, nX );
750*b1cdbd2cSJim Jagielski 				bIsGrey = ( aColor.GetRed() == aColor.GetGreen() ) && ( aColor.GetRed() == aColor.GetBlue() );
751*b1cdbd2cSJim Jagielski 			}
752*b1cdbd2cSJim Jagielski 		}
753*b1cdbd2cSJim Jagielski 		if ( bIsGrey )
754*b1cdbd2cSJim Jagielski 			bGreys = sal_True;
755*b1cdbd2cSJim Jagielski 	}
756*b1cdbd2cSJim Jagielski 
757*b1cdbd2cSJim Jagielski 	if( pExpWasGrey )
758*b1cdbd2cSJim Jagielski 	    *pExpWasGrey = bGreys;
759*b1cdbd2cSJim Jagielski 
760*b1cdbd2cSJim Jagielski 	if( pAcc )
761*b1cdbd2cSJim Jagielski 	{
762*b1cdbd2cSJim Jagielski 		bNative = ( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB );
763*b1cdbd2cSJim Jagielski 
764*b1cdbd2cSJim Jagielski 		if( !bNative )
765*b1cdbd2cSJim Jagielski 			pBuffer = new sal_uInt8[ AlignedWidth4Bytes( bGreys ? pAcc->Width() * 8L : pAcc->Width() * 24L ) ];
766*b1cdbd2cSJim Jagielski 
767*b1cdbd2cSJim Jagielski 		JPEGCallbackStruct aCallbackData;
768*b1cdbd2cSJim Jagielski 		aCallbackData.xStatusIndicator = xStatusIndicator;
769*b1cdbd2cSJim Jagielski 		bRet = (sal_Bool) WriteJPEG( this, &rOStm, pAcc->Width(), pAcc->Height(), bGreys, nQuality, &aCallbackData );
770*b1cdbd2cSJim Jagielski 
771*b1cdbd2cSJim Jagielski 		delete[] pBuffer;
772*b1cdbd2cSJim Jagielski 		pBuffer = NULL;
773*b1cdbd2cSJim Jagielski 
774*b1cdbd2cSJim Jagielski 		aGraphicBmp.ReleaseAccess( pAcc );
775*b1cdbd2cSJim Jagielski 		pAcc = NULL;
776*b1cdbd2cSJim Jagielski 	}
777*b1cdbd2cSJim Jagielski 	if ( xStatusIndicator.is() )
778*b1cdbd2cSJim Jagielski 		xStatusIndicator->end();
779*b1cdbd2cSJim Jagielski 
780*b1cdbd2cSJim Jagielski 	return bRet;
781*b1cdbd2cSJim Jagielski }
782*b1cdbd2cSJim Jagielski 
783*b1cdbd2cSJim Jagielski // --------------
784*b1cdbd2cSJim Jagielski // - ImportJPEG -
785*b1cdbd2cSJim Jagielski // --------------
786*b1cdbd2cSJim Jagielski 
ImportJPEG(SvStream & rStm,Graphic & rGraphic,void * pCallerData,sal_Int32 nImportFlags)787*b1cdbd2cSJim Jagielski sal_Bool ImportJPEG( SvStream& rStm, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags )
788*b1cdbd2cSJim Jagielski {
789*b1cdbd2cSJim Jagielski 	JPEGReader*	pJPEGReader = (JPEGReader*) rGraphic.GetContext();
790*b1cdbd2cSJim Jagielski 	ReadState	eReadState;
791*b1cdbd2cSJim Jagielski 	sal_Bool		bRet = sal_True;
792*b1cdbd2cSJim Jagielski 
793*b1cdbd2cSJim Jagielski 	if( !pJPEGReader )
794*b1cdbd2cSJim Jagielski         pJPEGReader = new JPEGReader( rStm, pCallerData, ( nImportFlags & GRFILTER_I_FLAGS_SET_LOGSIZE_FOR_JPEG ) != 0 );
795*b1cdbd2cSJim Jagielski 
796*b1cdbd2cSJim Jagielski     if( nImportFlags & GRFILTER_I_FLAGS_FOR_PREVIEW )
797*b1cdbd2cSJim Jagielski         pJPEGReader->SetPreviewSize( Size(128,128) );
798*b1cdbd2cSJim Jagielski     else
799*b1cdbd2cSJim Jagielski         pJPEGReader->DisablePreviewMode();
800*b1cdbd2cSJim Jagielski 
801*b1cdbd2cSJim Jagielski 	rGraphic.SetContext( NULL );
802*b1cdbd2cSJim Jagielski 	eReadState = pJPEGReader->Read( rGraphic );
803*b1cdbd2cSJim Jagielski 
804*b1cdbd2cSJim Jagielski 	if( eReadState == JPEGREAD_ERROR )
805*b1cdbd2cSJim Jagielski 	{
806*b1cdbd2cSJim Jagielski 		bRet = sal_False;
807*b1cdbd2cSJim Jagielski 		delete pJPEGReader;
808*b1cdbd2cSJim Jagielski 	}
809*b1cdbd2cSJim Jagielski 	else if( eReadState == JPEGREAD_OK )
810*b1cdbd2cSJim Jagielski 		delete pJPEGReader;
811*b1cdbd2cSJim Jagielski 	else
812*b1cdbd2cSJim Jagielski 		rGraphic.SetContext( pJPEGReader );
813*b1cdbd2cSJim Jagielski 
814*b1cdbd2cSJim Jagielski 	return bRet;
815*b1cdbd2cSJim Jagielski }
816*b1cdbd2cSJim Jagielski 
817*b1cdbd2cSJim Jagielski //  --------------
818*b1cdbd2cSJim Jagielski //  - ExportJPEG -
819*b1cdbd2cSJim Jagielski //  --------------
820*b1cdbd2cSJim Jagielski 
ExportJPEG(SvStream & rOStm,const Graphic & rGraphic,const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> * pFilterData,bool * pExportWasGrey)821*b1cdbd2cSJim Jagielski sal_Bool ExportJPEG( SvStream& rOStm, const Graphic& rGraphic,
822*b1cdbd2cSJim Jagielski                  const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData,
823*b1cdbd2cSJim Jagielski                  bool* pExportWasGrey
824*b1cdbd2cSJim Jagielski                 )
825*b1cdbd2cSJim Jagielski {
826*b1cdbd2cSJim Jagielski 	JPEGWriter aJPEGWriter( rOStm, pFilterData, pExportWasGrey );
827*b1cdbd2cSJim Jagielski 	return aJPEGWriter.Write( rGraphic );
828*b1cdbd2cSJim Jagielski }
829