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