1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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 */
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
),
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 );
121 int nArgs
= pFilterData
->getLength();
122 const css::beans::PropertyValue
* pValues
= pFilterData
->getConstArray();
125 if ( pValues
->Name
== "StatusIndicator" )
127 pValues
->Value
>>= mxStatusIndicator
;
134 void* JPEGWriter::GetScanline( long nY
)
136 void* pScanline
= NULL
;
142 pScanline
= mpReadAccess
->GetScanline( nY
);
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();
158 *pTmp
++ = aColor
.GetGreen();
159 *pTmp
++ = aColor
.GetBlue();
165 for( long nX
= 0L; nX
< nWidth
; nX
++ )
167 aColor
= mpReadAccess
->GetPixel( nY
, nX
);
168 *pTmp
++ = aColor
.GetRed();
171 *pTmp
++ = aColor
.GetGreen();
172 *pTmp
++ = aColor
.GetBlue();
177 pScanline
= mpBuffer
;
184 bool JPEGWriter::Write( const Graphic
& rGraphic
)
188 if ( mxStatusIndicator
.is() )
191 mxStatusIndicator
->start( aMsg
, 100 );
194 Bitmap
aGraphicBmp( rGraphic
.GetBitmap() );
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
209 long nWidth
= mpReadAccess
->Width();
210 for ( long nY
= 0; bIsGrey
&& ( nY
< mpReadAccess
->Height() ); nY
++ )
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() );
225 *mpExpWasGrey
= mbGreys
;
229 mbNative
= ( mpReadAccess
->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB
);
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
);
239 Bitmap::ReleaseAccess( mpReadAccess
);
242 if ( mxStatusIndicator
.is() )
243 mxStatusIndicator
->end();
248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */