Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / source / filter / jpeg / JpegWriter.cxx
blobfe03540519a554b7119b9f32c4f1d9557f6701db
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 .
20 #include <sal/config.h>
22 #include "stdio.h"
23 #include "jpeg.h"
24 #include <jpeglib.h>
25 #include <jerror.h>
27 #include "JpegWriter.hxx"
28 #include <vcl/bmpacc.hxx>
29 #include <vcl/FilterConfigItem.hxx>
30 #include <vcl/graphicfilter.hxx>
32 #define BUFFER_SIZE 4096
34 struct DestinationManagerStruct
36 jpeg_destination_mgr pub; /* public fields */
37 SvStream* stream; /* target stream */
38 JOCTET * buffer; /* start of buffer */
41 extern "C" void init_destination (j_compress_ptr cinfo)
43 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
45 /* Allocate the output buffer -- it will be released when done with image */
46 destination->buffer = static_cast<JOCTET *>(
47 (*cinfo->mem->alloc_small) (reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, BUFFER_SIZE * sizeof(JOCTET)));
49 destination->pub.next_output_byte = destination->buffer;
50 destination->pub.free_in_buffer = BUFFER_SIZE;
53 extern "C" boolean empty_output_buffer (j_compress_ptr cinfo)
55 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
57 if (destination->stream->Write(destination->buffer, BUFFER_SIZE) != (size_t) BUFFER_SIZE)
59 ERREXIT(cinfo, JERR_FILE_WRITE);
62 destination->pub.next_output_byte = destination->buffer;
63 destination->pub.free_in_buffer = BUFFER_SIZE;
65 return TRUE;
68 extern "C" void term_destination (j_compress_ptr cinfo)
70 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
71 size_t datacount = BUFFER_SIZE - destination->pub.free_in_buffer;
73 /* Write any data remaining in the buffer */
74 if (datacount > 0)
76 if (destination->stream->Write(destination->buffer, datacount) != datacount)
78 ERREXIT(cinfo, JERR_FILE_WRITE);
83 void jpeg_svstream_dest (j_compress_ptr cinfo, void* output)
85 SvStream* stream = static_cast<SvStream*>(output);
86 DestinationManagerStruct * destination;
88 /* The destination object is made permanent so that multiple JPEG images
89 * can be written to the same file without re-executing jpeg_svstream_dest.
90 * This makes it dangerous to use this manager and a different destination
91 * manager serially with the same JPEG object, because their private object
92 * sizes may be different. Caveat programmer.
94 if (cinfo->dest == NULL)
95 { /* first time for this JPEG object? */
96 cinfo->dest = static_cast<jpeg_destination_mgr*>(
97 (*cinfo->mem->alloc_small) (reinterpret_cast<j_common_ptr>(cinfo), JPOOL_PERMANENT, sizeof(DestinationManagerStruct)));
100 destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
101 destination->pub.init_destination = init_destination;
102 destination->pub.empty_output_buffer = empty_output_buffer;
103 destination->pub.term_destination = term_destination;
104 destination->stream = stream;
107 JPEGWriter::JPEGWriter( SvStream& rStream, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData, bool* pExportWasGrey ) :
108 mrStream ( rStream ),
109 mpReadAccess ( NULL ),
110 mpBuffer ( NULL ),
111 mbNative ( false ),
112 mpExpWasGrey ( pExportWasGrey )
114 FilterConfigItem aConfigItem( const_cast<css::uno::Sequence< css::beans::PropertyValue >*>(pFilterData) );
115 mbGreys = aConfigItem.ReadInt32( "ColorMode", 0 ) != 0;
116 mnQuality = aConfigItem.ReadInt32( "Quality", 75 );
117 maChromaSubsampling = aConfigItem.ReadInt32( "ChromaSubsamplingMode", 0 );
119 if ( pFilterData )
121 int nArgs = pFilterData->getLength();
122 const css::beans::PropertyValue* pValues = pFilterData->getConstArray();
123 while( nArgs-- )
125 if ( pValues->Name == "StatusIndicator" )
127 pValues->Value >>= mxStatusIndicator;
129 pValues++;
134 void* JPEGWriter::GetScanline( long nY )
136 void* pScanline = NULL;
138 if( mpReadAccess )
140 if( mbNative )
142 pScanline = mpReadAccess->GetScanline( nY );
144 else if( mpBuffer )
146 BitmapColor aColor;
147 long nWidth = mpReadAccess->Width();
148 sal_uInt8* pTmp = mpBuffer;
150 if( mpReadAccess->HasPalette() )
152 for( long nX = 0L; nX < nWidth; nX++ )
154 aColor = mpReadAccess->GetPaletteColor( mpReadAccess->GetPixelIndex( nY, nX ) );
155 *pTmp++ = aColor.GetRed();
156 if ( !mbGreys )
158 *pTmp++ = aColor.GetGreen();
159 *pTmp++ = aColor.GetBlue();
163 else
165 for( long nX = 0L; nX < nWidth; nX++ )
167 aColor = mpReadAccess->GetPixel( nY, nX );
168 *pTmp++ = aColor.GetRed();
169 if ( !mbGreys )
171 *pTmp++ = aColor.GetGreen();
172 *pTmp++ = aColor.GetBlue();
177 pScanline = mpBuffer;
181 return pScanline;
184 bool JPEGWriter::Write( const Graphic& rGraphic )
186 bool bRet = false;
188 if ( mxStatusIndicator.is() )
190 OUString aMsg;
191 mxStatusIndicator->start( aMsg, 100 );
194 Bitmap aGraphicBmp( rGraphic.GetBitmap() );
196 if ( mbGreys )
198 if ( !aGraphicBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) )
199 aGraphicBmp = rGraphic.GetBitmap();
202 mpReadAccess = aGraphicBmp.AcquireReadAccess();
204 if ( !mbGreys ) // bitmap was not explicitly converted into greyscale,
205 { // check if source is greyscale only
207 bool bIsGrey = true;
209 long nWidth = mpReadAccess->Width();
210 for ( long nY = 0; bIsGrey && ( nY < mpReadAccess->Height() ); nY++ )
212 BitmapColor aColor;
213 for( long nX = 0L; bIsGrey && ( nX < nWidth ); nX++ )
215 aColor = mpReadAccess->HasPalette() ? mpReadAccess->GetPaletteColor( mpReadAccess->GetPixelIndex( nY, nX ) )
216 : mpReadAccess->GetPixel( nY, nX );
217 bIsGrey = ( aColor.GetRed() == aColor.GetGreen() ) && ( aColor.GetRed() == aColor.GetBlue() );
220 if ( bIsGrey )
221 mbGreys = true;
224 if( mpExpWasGrey )
225 *mpExpWasGrey = mbGreys;
227 if( mpReadAccess )
229 mbNative = ( mpReadAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB );
231 if( !mbNative )
232 mpBuffer = new sal_uInt8[ AlignedWidth4Bytes( mbGreys ? mpReadAccess->Width() * 8L : mpReadAccess->Width() * 24L ) ];
234 bRet = WriteJPEG( this, &mrStream, mpReadAccess->Width(), mpReadAccess->Height(), mbGreys, mnQuality, maChromaSubsampling, mxStatusIndicator );
236 delete[] mpBuffer;
237 mpBuffer = NULL;
239 Bitmap::ReleaseAccess( mpReadAccess );
240 mpReadAccess = NULL;
242 if ( mxStatusIndicator.is() )
243 mxStatusIndicator->end();
245 return bRet;
248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */