Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / vcl / source / filter / jpeg / jpeg.cxx
blob72c6e5746248a45dbbc65f4db6809e26686b7781
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <tools/solar.h>
23 extern "C"
25 #include "stdio.h"
26 #include "jpeg.h"
27 #include <jpeglib.h>
28 #include <jerror.h>
31 #define _JPEGPRIVATE
32 #include <vcl/bmpacc.hxx>
33 #include "jpeg.hxx"
34 #include <vcl/FilterConfigItem.hxx>
35 #include <vcl/graphicfilter.hxx>
37 // -----------
38 // - Defines -
39 // -----------
41 using namespace ::com::sun::star;
43 #define JPEGMINREAD 512
45 // -------------
46 // - (C-Calls) -
47 // -------------
49 // ------------------------------------------------------------------------
51 extern "C" void* CreateBitmap( void* pJPEGReader, void* pJPEGCreateBitmapParam )
53 return ( (JPEGReader*) pJPEGReader )->CreateBitmap( pJPEGCreateBitmapParam );
56 // ------------------------------------------------------------------------
58 extern "C" void* GetScanline( void* pJPEGWriter, long nY )
60 return ( (JPEGWriter*) pJPEGWriter )->GetScanline( nY );
63 // ------------------------------------------------------------------------
65 struct JPEGCallbackStruct
67 uno::Reference< task::XStatusIndicator > xStatusIndicator;
70 extern "C" long JPEGCallback( void* pCallbackData, long nPercent )
72 JPEGCallbackStruct* pS = (JPEGCallbackStruct*)pCallbackData;
73 if ( pS && pS->xStatusIndicator.is() )
75 pS->xStatusIndicator->setValue( nPercent );
77 return 0L;
80 #define BUF_SIZE 4096
82 typedef struct
84 struct jpeg_destination_mgr pub; /* public fields */
86 SvStream* outfile; /* target stream */
87 JOCTET * buffer; /* start of buffer */
88 } my_destination_mgr;
90 typedef my_destination_mgr * my_dest_ptr;
92 extern "C" void init_destination (j_compress_ptr cinfo)
94 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
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 BUF_SIZE * sizeof(JOCTET));
101 dest->pub.next_output_byte = dest->buffer;
102 dest->pub.free_in_buffer = BUF_SIZE;
105 extern "C" boolean empty_output_buffer (j_compress_ptr cinfo)
107 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
109 if (dest->outfile->Write(dest->buffer, BUF_SIZE) !=
110 (size_t) BUF_SIZE)
111 ERREXIT(cinfo, JERR_FILE_WRITE);
113 dest->pub.next_output_byte = dest->buffer;
114 dest->pub.free_in_buffer = BUF_SIZE;
116 return sal_True;
119 extern "C" void term_destination (j_compress_ptr cinfo)
121 my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
122 size_t datacount = BUF_SIZE - dest->pub.free_in_buffer;
124 /* Write any data remaining in the buffer */
125 if (datacount > 0) {
126 if (dest->outfile->Write(dest->buffer, datacount) != datacount)
127 ERREXIT(cinfo, JERR_FILE_WRITE);
131 extern "C" void jpeg_svstream_dest (j_compress_ptr cinfo, void* out)
133 SvStream * outfile = (SvStream*)out;
134 my_dest_ptr dest;
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.
142 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 sizeof(my_destination_mgr));
148 dest = (my_dest_ptr) cinfo->dest;
149 dest->pub.init_destination = init_destination;
150 dest->pub.empty_output_buffer = empty_output_buffer;
151 dest->pub.term_destination = term_destination;
152 dest->outfile = outfile;
155 /* Expanded data source object for stdio input */
157 typedef struct {
158 struct jpeg_source_mgr pub; /* public fields */
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;
165 typedef my_source_mgr * my_src_ptr;
168 * Initialize source --- called by jpeg_read_header
169 * before any data is actually read.
172 extern "C" void init_source (j_decompress_ptr cinfo)
174 my_src_ptr src = (my_src_ptr) cinfo->src;
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.
180 src->start_of_file = sal_True;
183 long StreamRead( SvStream* pSvStm, void* pBuffer, long nBufferSize )
185 long nRead = 0;
187 if( pSvStm->GetError() != ERRCODE_IO_PENDING )
189 long nActPos = pSvStm->Tell();
191 nRead = (long) pSvStm->Read( pBuffer, nBufferSize );
193 if( pSvStm->GetError() == ERRCODE_IO_PENDING )
195 // Damit wir wieder an die alte Position
196 // seeken koennen, setzen wir den Error temp.zurueck
197 pSvStm->ResetError();
198 pSvStm->Seek( nActPos );
199 pSvStm->SetError( ERRCODE_IO_PENDING );
203 return nRead;
206 extern "C" boolean fill_input_buffer (j_decompress_ptr cinfo)
208 my_src_ptr src = (my_src_ptr) cinfo->src;
209 size_t nbytes;
211 nbytes = StreamRead(src->infile, src->buffer, BUF_SIZE);
213 if (!nbytes) {
214 if (src->start_of_file) /* Treat empty input file as fatal error */
215 ERREXIT(cinfo, JERR_INPUT_EMPTY);
216 WARNMS(cinfo, JWRN_JPEG_EOF);
217 /* Insert a fake EOI marker */
218 src->buffer[0] = (JOCTET) 0xFF;
219 src->buffer[1] = (JOCTET) JPEG_EOI;
220 nbytes = 2;
223 src->pub.next_input_byte = src->buffer;
224 src->pub.bytes_in_buffer = nbytes;
225 src->start_of_file = sal_False;
227 return sal_True;
230 extern "C" void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
232 my_src_ptr src = (my_src_ptr) cinfo->src;
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.
238 if (num_bytes > 0) {
239 while (num_bytes > (long) src->pub.bytes_in_buffer) {
240 num_bytes -= (long) src->pub.bytes_in_buffer;
241 (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.
246 src->pub.next_input_byte += (size_t) num_bytes;
247 src->pub.bytes_in_buffer -= (size_t) num_bytes;
251 extern "C" void term_source (j_decompress_ptr)
253 /* no work necessary here */
256 extern "C" void jpeg_svstream_src (j_decompress_ptr cinfo, void * in)
258 my_src_ptr src;
259 SvStream * infile = (SvStream*)in;
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.
268 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 sizeof(my_source_mgr));
272 src = (my_src_ptr) cinfo->src;
273 src->buffer = (JOCTET *)
274 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
275 BUF_SIZE * sizeof(JOCTET));
278 src = (my_src_ptr) cinfo->src;
279 src->pub.init_source = init_source;
280 src->pub.fill_input_buffer = fill_input_buffer;
281 src->pub.skip_input_data = skip_input_data;
282 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
283 src->pub.term_source = term_source;
284 src->infile = infile;
285 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
286 src->pub.next_input_byte = NULL; /* until buffer loaded */
289 // --------------
290 // - JPEGReader -
291 // --------------
293 JPEGReader::JPEGReader( SvStream& rStm, void* /*pCallData*/, sal_Bool bSetLS ) :
294 rIStm ( rStm ),
295 pAcc ( NULL ),
296 pAcc1 ( NULL ),
297 pBuffer ( NULL ),
298 nLastPos ( rStm.Tell() ),
299 nLastLines ( 0 ),
300 bSetLogSize ( bSetLS )
302 maUpperName = rtl::OUString("SVIJPEG");
303 nFormerPos = nLastPos;
306 // ------------------------------------------------------------------------
308 JPEGReader::~JPEGReader()
310 if( pBuffer )
311 rtl_freeMemory( pBuffer );
313 if( pAcc )
314 aBmp.ReleaseAccess( pAcc );
316 if( pAcc1 )
317 aBmp1.ReleaseAccess( pAcc1 );
320 // ------------------------------------------------------------------------
322 void* JPEGReader::CreateBitmap( void* _pParam )
324 JPEGCreateBitmapParam *pParam = (JPEGCreateBitmapParam *) _pParam;
326 if (pParam->nWidth > SAL_MAX_INT32/8 || pParam->nHeight > SAL_MAX_INT32/8)
327 return NULL; // avoid overflows later
329 Size aSize( pParam->nWidth, pParam->nHeight );
330 sal_Bool bGray = pParam->bGray != 0;
332 void* pBmpBuf = NULL;
334 if( pAcc )
335 aBmp.ReleaseAccess( pAcc );
337 sal_uInt64 nSize = aSize.Width();
338 nSize *= aSize.Height();
339 if (nSize > SAL_MAX_INT32 / 24)
340 return NULL;
342 if( bGray )
344 BitmapPalette aGrayPal( 256 );
346 for( sal_uInt16 n = 0; n < 256; n++ )
348 const sal_uInt8 cGray = (sal_uInt8) n;
349 aGrayPal[ n ] = BitmapColor( cGray, cGray, cGray );
352 aBmp = Bitmap( aSize, 8, &aGrayPal );
354 else
355 aBmp = Bitmap( aSize, 24 );
357 if ( bSetLogSize )
359 unsigned long nUnit = ((JPEGCreateBitmapParam*)pParam)->density_unit;
361 if( ( ( 1 == nUnit ) || ( 2 == nUnit ) ) &&
362 pParam->X_density && pParam->Y_density )
364 Point aEmptyPoint;
365 Fraction aFractX( 1, pParam->X_density );
366 Fraction aFractY( 1, pParam->Y_density );
367 MapMode aMapMode( nUnit == 1 ? MAP_INCH : MAP_CM, aEmptyPoint, aFractX, aFractY );
368 Size aPrefSize = OutputDevice::LogicToLogic( aSize, aMapMode, MAP_100TH_MM );
370 aBmp.SetPrefSize( aPrefSize );
371 aBmp.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
375 pAcc = aBmp.AcquireWriteAccess();
377 if( pAcc )
379 const sal_uLong nFormat = pAcc->GetScanlineFormat();
382 ( bGray && ( BMP_FORMAT_8BIT_PAL == nFormat ) ) ||
383 ( !bGray && ( BMP_FORMAT_24BIT_TC_RGB == nFormat ) )
386 pBmpBuf = pAcc->GetBuffer();
387 pParam->nAlignedWidth = pAcc->GetScanlineSize();
388 pParam->bTopDown = pAcc->IsTopDown();
390 else
392 pParam->nAlignedWidth = AlignedWidth4Bytes( aSize.Width() * ( bGray ? 8 : 24 ) );
393 pParam->bTopDown = sal_True;
394 pBmpBuf = pBuffer = rtl_allocateMemory( pParam->nAlignedWidth * aSize.Height() );
398 // clean up, if no Bitmap buffer can be provided.
399 if ( !pBmpBuf )
401 aBmp.ReleaseAccess( pAcc );
402 pAcc = NULL;
405 return pBmpBuf;
408 // ------------------------------------------------------------------------
410 void JPEGReader::FillBitmap()
412 if( pBuffer && pAcc )
414 HPBYTE pTmp;
415 BitmapColor aColor;
416 long nAlignedWidth;
417 long nWidth = pAcc->Width();
418 long nHeight = pAcc->Height();
420 if( pAcc->GetBitCount() == 8 )
422 BitmapColor* pCols = new BitmapColor[ 256 ];
424 for( sal_uInt16 n = 0; n < 256; n++ )
426 const sal_uInt8 cGray = (sal_uInt8) n;
427 pCols[ n ] = pAcc->GetBestMatchingColor( BitmapColor( cGray, cGray, cGray ) );
430 nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 8L );
432 for( long nY = 0L; nY < nHeight; nY++ )
434 pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth;
436 for( long nX = 0L; nX < nWidth; nX++ )
437 pAcc->SetPixel( nY, nX, pCols[ *pTmp++ ] );
440 delete[] pCols;
442 else
444 nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 24L );
446 for( long nY = 0L; nY < nHeight; nY++ )
448 pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth;
450 for( long nX = 0L; nX < nWidth; nX++ )
452 aColor.SetRed( *pTmp++ );
453 aColor.SetGreen( *pTmp++ );
454 aColor.SetBlue( *pTmp++ );
455 pAcc->SetPixel( nY, nX, aColor );
462 // ------------------------------------------------------------------------
464 Graphic JPEGReader::CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines )
466 Graphic aGraphic;
467 const Size aSizePix( rBitmap.GetSizePixel() );
469 if( !nLastLines )
471 if( pAcc1 )
472 aBmp1.ReleaseAccess( pAcc1 );
474 aBmp1 = Bitmap( rBitmap.GetSizePixel(), 1 );
475 aBmp1.Erase( Color( COL_WHITE ) );
476 pAcc1 = aBmp1.AcquireWriteAccess();
479 if( nLines && ( nLines < aSizePix.Height() ) )
481 if( pAcc1 )
483 const long nNewLines = nLines - nLastLines;
485 if( nNewLines )
487 pAcc1->SetFillColor( Color( COL_BLACK ) );
488 pAcc1->FillRect( Rectangle( Point( 0, nLastLines ),
489 Size( pAcc1->Width(), nNewLines ) ) );
492 aBmp1.ReleaseAccess( pAcc1 );
493 aGraphic = BitmapEx( rBitmap, aBmp1 );
494 pAcc1 = aBmp1.AcquireWriteAccess();
496 else
497 aGraphic = rBitmap;
499 else
500 aGraphic = rBitmap;
502 nLastLines = nLines;
504 return aGraphic;
507 // ------------------------------------------------------------------------
509 ReadState JPEGReader::Read( Graphic& rGraphic )
511 long nEndPos;
512 long nLines;
513 ReadState eReadState;
514 sal_Bool bRet = sal_False;
515 sal_uInt8 cDummy;
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 rIStm.Seek( STREAM_SEEK_TO_END );
520 rIStm >> cDummy;
521 nEndPos = rIStm.Tell();
523 // else check if at least JPEGMINREAD bytes can be read
524 if( rIStm.GetError() == ERRCODE_IO_PENDING )
526 rIStm.ResetError();
527 if( ( nEndPos - nFormerPos ) < JPEGMINREAD )
529 rIStm.Seek( nLastPos );
530 return JPEGREAD_NEED_MORE;
534 // seek back to the original position
535 rIStm.Seek( nLastPos );
536 #endif
538 Size aPreviewSize = GetPreviewSize();
539 SetJpegPreviewSizeHint( aPreviewSize.Width(), aPreviewSize.Height() );
541 // read the (partial) image
542 ReadJPEG( this, &rIStm, &nLines );
544 if( pAcc )
546 if( pBuffer )
548 FillBitmap();
549 rtl_freeMemory( pBuffer );
550 pBuffer = NULL;
553 aBmp.ReleaseAccess( pAcc );
554 pAcc = NULL;
556 if( rIStm.GetError() == ERRCODE_IO_PENDING )
557 rGraphic = CreateIntermediateGraphic( aBmp, nLines );
558 else
559 rGraphic = aBmp;
561 bRet = sal_True;
563 else if( rIStm.GetError() == ERRCODE_IO_PENDING )
564 bRet = sal_True;
566 // Status setzen ( Pending hat immer Vorrang )
567 if( rIStm.GetError() == ERRCODE_IO_PENDING )
569 eReadState = JPEGREAD_NEED_MORE;
570 rIStm.ResetError();
571 nFormerPos = rIStm.Tell();
573 else
575 if( bRet )
576 eReadState = JPEGREAD_OK;
577 else
578 eReadState = JPEGREAD_ERROR;
581 return eReadState;
585 // --------------
586 // - JPEGWriter -
587 // --------------
589 JPEGWriter::JPEGWriter( SvStream& rStm, const uno::Sequence< beans::PropertyValue >* pFilterData, bool* pExportWasGrey ) :
590 rOStm ( rStm ),
591 pAcc ( NULL ),
592 pBuffer ( NULL ),
593 pExpWasGrey ( pExportWasGrey )
595 FilterConfigItem aConfigItem( (uno::Sequence< beans::PropertyValue >*)pFilterData );
596 bGreys = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "ColorMode" ) ), 0 ) != 0;
597 nQuality = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ), 75 );
599 if ( pFilterData )
601 int nArgs = pFilterData->getLength();
602 const beans::PropertyValue* pValues = pFilterData->getConstArray();
603 while( nArgs-- )
605 if ( pValues->Name == "StatusIndicator" )
607 pValues->Value >>= xStatusIndicator;
609 pValues++;
614 // ------------------------------------------------------------------------
616 void* JPEGWriter::GetScanline( long nY )
618 void* pScanline = NULL;
620 if( pAcc )
622 if( bNative )
623 pScanline = pAcc->GetScanline( nY );
624 else if( pBuffer )
626 BitmapColor aColor;
627 long nWidth = pAcc->Width();
628 sal_uInt8* pTmp = pBuffer;
630 if( pAcc->HasPalette() )
632 for( long nX = 0L; nX < nWidth; nX++ )
634 aColor = pAcc->GetPaletteColor( (sal_uInt8) pAcc->GetPixel( nY, nX ) );
635 *pTmp++ = aColor.GetRed();
636 if ( bGreys )
637 continue;
638 *pTmp++ = aColor.GetGreen();
639 *pTmp++ = aColor.GetBlue();
642 else
644 for( long nX = 0L; nX < nWidth; nX++ )
646 aColor = pAcc->GetPixel( nY, nX );
647 *pTmp++ = aColor.GetRed();
648 if ( bGreys )
649 continue;
650 *pTmp++ = aColor.GetGreen();
651 *pTmp++ = aColor.GetBlue();
655 pScanline = pBuffer;
659 return pScanline;
662 // ------------------------------------------------------------------------
664 sal_Bool JPEGWriter::Write( const Graphic& rGraphic )
666 sal_Bool bRet = sal_False;
668 if ( xStatusIndicator.is() )
670 rtl::OUString aMsg;
671 xStatusIndicator->start( aMsg, 100 );
674 Bitmap aGraphicBmp( rGraphic.GetBitmap() );
676 if ( bGreys )
678 if ( !aGraphicBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
679 aGraphicBmp = rGraphic.GetBitmap();
682 pAcc = aGraphicBmp.AcquireReadAccess();
684 if ( !bGreys ) // bitmap was not explicitly converted into greyscale,
685 { // check if source is greyscale only
687 sal_Bool bIsGrey = sal_True;
689 long nWidth = pAcc->Width();
690 for ( long nY = 0; bIsGrey && ( nY < pAcc->Height() ); nY++ )
692 BitmapColor aColor;
693 for( long nX = 0L; bIsGrey && ( nX < nWidth ); nX++ )
695 aColor = pAcc->HasPalette() ? pAcc->GetPaletteColor( (sal_uInt8) pAcc->GetPixel( nY, nX ) )
696 : pAcc->GetPixel( nY, nX );
697 bIsGrey = ( aColor.GetRed() == aColor.GetGreen() ) && ( aColor.GetRed() == aColor.GetBlue() );
700 if ( bIsGrey )
701 bGreys = sal_True;
704 if( pExpWasGrey )
705 *pExpWasGrey = bGreys;
707 if( pAcc )
709 bNative = ( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB );
711 if( !bNative )
712 pBuffer = new sal_uInt8[ AlignedWidth4Bytes( bGreys ? pAcc->Width() * 8L : pAcc->Width() * 24L ) ];
714 JPEGCallbackStruct aCallbackData;
715 aCallbackData.xStatusIndicator = xStatusIndicator;
716 bRet = (sal_Bool) WriteJPEG( this, &rOStm, pAcc->Width(), pAcc->Height(), bGreys, nQuality, &aCallbackData );
718 delete[] pBuffer;
719 pBuffer = NULL;
721 aGraphicBmp.ReleaseAccess( pAcc );
722 pAcc = NULL;
724 if ( xStatusIndicator.is() )
725 xStatusIndicator->end();
727 return bRet;
730 // --------------
731 // - ImportJPEG -
732 // --------------
734 sal_Bool ImportJPEG( SvStream& rStm, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags )
736 JPEGReader* pJPEGReader = (JPEGReader*) rGraphic.GetContext();
737 ReadState eReadState;
738 sal_Bool bRet = sal_True;
740 if( !pJPEGReader )
741 pJPEGReader = new JPEGReader( rStm, pCallerData, ( nImportFlags & GRFILTER_I_FLAGS_SET_LOGSIZE_FOR_JPEG ) != 0 );
743 if( nImportFlags & GRFILTER_I_FLAGS_FOR_PREVIEW )
744 pJPEGReader->SetPreviewSize( Size(128,128) );
745 else
746 pJPEGReader->DisablePreviewMode();
748 rGraphic.SetContext( NULL );
749 eReadState = pJPEGReader->Read( rGraphic );
751 if( eReadState == JPEGREAD_ERROR )
753 bRet = sal_False;
754 delete pJPEGReader;
756 else if( eReadState == JPEGREAD_OK )
757 delete pJPEGReader;
758 else
759 rGraphic.SetContext( pJPEGReader );
761 return bRet;
764 // --------------
765 // - ExportJPEG -
766 // --------------
768 sal_Bool ExportJPEG( SvStream& rOStm, const Graphic& rGraphic,
769 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData,
770 bool* pExportWasGrey
773 JPEGWriter aJPEGWriter( rOStm, pFilterData, pExportWasGrey );
774 return aJPEGWriter.Write( rGraphic );
777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */