build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / jpeg / JpegWriter.cxx
blob604308f05a65f540ccbc80b69afb9d63941aa518
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 "jpeg.h"
23 #include <jpeglib.h>
24 #include <jerror.h>
26 #include "JpegWriter.hxx"
27 #include <vcl/bitmapaccess.hxx>
28 #include <vcl/FilterConfigItem.hxx>
29 #include <vcl/graphicfilter.hxx>
31 #define BUFFER_SIZE 4096
33 struct DestinationManagerStruct
35 jpeg_destination_mgr pub; /* public fields */
36 SvStream* stream; /* target stream */
37 JOCTET * buffer; /* start of buffer */
40 extern "C" void init_destination (j_compress_ptr cinfo)
42 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
44 /* Allocate the output buffer -- it will be released when done with image */
45 destination->buffer = static_cast<JOCTET *>(
46 (*cinfo->mem->alloc_small) (reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, BUFFER_SIZE * sizeof(JOCTET)));
48 destination->pub.next_output_byte = destination->buffer;
49 destination->pub.free_in_buffer = BUFFER_SIZE;
52 extern "C" boolean empty_output_buffer (j_compress_ptr cinfo)
54 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
56 if (destination->stream->WriteBytes(destination->buffer, BUFFER_SIZE) != BUFFER_SIZE)
58 ERREXIT(cinfo, JERR_FILE_WRITE);
61 destination->pub.next_output_byte = destination->buffer;
62 destination->pub.free_in_buffer = BUFFER_SIZE;
64 return TRUE;
67 extern "C" void term_destination (j_compress_ptr cinfo)
69 DestinationManagerStruct * destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
70 size_t datacount = BUFFER_SIZE - destination->pub.free_in_buffer;
72 /* Write any data remaining in the buffer */
73 if (datacount > 0)
75 if (destination->stream->WriteBytes(destination->buffer, datacount) != datacount)
77 ERREXIT(cinfo, JERR_FILE_WRITE);
82 void jpeg_svstream_dest (j_compress_ptr cinfo, void* output)
84 SvStream* stream = static_cast<SvStream*>(output);
85 DestinationManagerStruct * destination;
87 /* The destination object is made permanent so that multiple JPEG images
88 * can be written to the same file without re-executing jpeg_svstream_dest.
89 * This makes it dangerous to use this manager and a different destination
90 * manager serially with the same JPEG object, because their private object
91 * sizes may be different. Caveat programmer.
93 if (cinfo->dest == nullptr)
94 { /* first time for this JPEG object? */
95 cinfo->dest = static_cast<jpeg_destination_mgr*>(
96 (*cinfo->mem->alloc_small) (reinterpret_cast<j_common_ptr>(cinfo), JPOOL_PERMANENT, sizeof(DestinationManagerStruct)));
99 destination = reinterpret_cast<DestinationManagerStruct *>(cinfo->dest);
100 destination->pub.init_destination = init_destination;
101 destination->pub.empty_output_buffer = empty_output_buffer;
102 destination->pub.term_destination = term_destination;
103 destination->stream = stream;
106 JPEGWriter::JPEGWriter( SvStream& rStream, const css::uno::Sequence< css::beans::PropertyValue >* pFilterData, bool* pExportWasGrey ) :
107 mrStream ( rStream ),
108 mpBuffer ( nullptr ),
109 mbNative ( false ),
110 mpExpWasGrey ( pExportWasGrey )
112 FilterConfigItem aConfigItem( const_cast<css::uno::Sequence< css::beans::PropertyValue >*>(pFilterData) );
113 mbGreys = aConfigItem.ReadInt32( "ColorMode", 0 ) != 0;
114 mnQuality = aConfigItem.ReadInt32( "Quality", 75 );
115 maChromaSubsampling = aConfigItem.ReadInt32( "ChromaSubsamplingMode", 0 );
117 if ( pFilterData )
119 int nArgs = pFilterData->getLength();
120 const css::beans::PropertyValue* pValues = pFilterData->getConstArray();
121 while( nArgs-- )
123 if ( pValues->Name == "StatusIndicator" )
125 pValues->Value >>= mxStatusIndicator;
127 pValues++;
132 void* JPEGWriter::GetScanline( long nY )
134 void* pScanline = nullptr;
136 if( mpReadAccess )
138 if( mbNative )
140 pScanline = mpReadAccess->GetScanline( nY );
142 else if( mpBuffer )
144 BitmapColor aColor;
145 long nWidth = mpReadAccess->Width();
146 sal_uInt8* pTmp = mpBuffer;
148 if( mpReadAccess->HasPalette() )
150 for( long nX = 0; nX < nWidth; nX++ )
152 aColor = mpReadAccess->GetPaletteColor( mpReadAccess->GetPixelIndex( nY, nX ) );
153 *pTmp++ = aColor.GetRed();
154 if ( !mbGreys )
156 *pTmp++ = aColor.GetGreen();
157 *pTmp++ = aColor.GetBlue();
161 else
163 for( long nX = 0; nX < nWidth; nX++ )
165 aColor = mpReadAccess->GetPixel( nY, nX );
166 *pTmp++ = aColor.GetRed();
167 if ( !mbGreys )
169 *pTmp++ = aColor.GetGreen();
170 *pTmp++ = aColor.GetBlue();
175 pScanline = mpBuffer;
179 return pScanline;
182 bool JPEGWriter::Write( const Graphic& rGraphic )
184 bool bRet = false;
186 if ( mxStatusIndicator.is() )
188 OUString aMsg;
189 mxStatusIndicator->start( aMsg, 100 );
192 Bitmap aGraphicBmp( rGraphic.GetBitmap() );
194 if ( mbGreys )
196 if ( !aGraphicBmp.Convert( BmpConversion::N8BitGreys ) )
197 aGraphicBmp = rGraphic.GetBitmap();
200 mpReadAccess = Bitmap::ScopedReadAccess(aGraphicBmp);
201 if( mpReadAccess )
203 if ( !mbGreys ) // bitmap was not explicitly converted into greyscale,
204 { // check if source is greyscale only
205 bool bIsGrey = true;
207 long nWidth = mpReadAccess->Width();
208 for ( long nY = 0; bIsGrey && ( nY < mpReadAccess->Height() ); nY++ )
210 BitmapColor aColor;
211 for( long nX = 0; bIsGrey && ( nX < nWidth ); nX++ )
213 aColor = mpReadAccess->HasPalette() ? mpReadAccess->GetPaletteColor( mpReadAccess->GetPixelIndex( nY, nX ) )
214 : mpReadAccess->GetPixel( nY, nX );
215 bIsGrey = ( aColor.GetRed() == aColor.GetGreen() ) && ( aColor.GetRed() == aColor.GetBlue() );
218 if ( bIsGrey )
219 mbGreys = true;
221 if( mpExpWasGrey )
222 *mpExpWasGrey = mbGreys;
224 mbNative = ( mpReadAccess->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb );
226 if( !mbNative )
227 mpBuffer = new sal_uInt8[ AlignedWidth4Bytes( mbGreys ? mpReadAccess->Width() * 8L : mpReadAccess->Width() * 24L ) ];
229 SAL_INFO("vcl", "\nJPEG Export - DPI X: " << rGraphic.GetPPI().getX() << "\nJPEG Export - DPI Y: " << rGraphic.GetPPI().getY());
231 bRet = WriteJPEG( this, &mrStream, mpReadAccess->Width(),
232 mpReadAccess->Height(), rGraphic.GetPPI(), mbGreys,
233 mnQuality, maChromaSubsampling, mxStatusIndicator );
235 delete[] mpBuffer;
236 mpBuffer = nullptr;
238 mpReadAccess.reset();
240 if ( mxStatusIndicator.is() )
241 mxStatusIndicator->end();
243 return bRet;
246 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */