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 .
26 #include <rtl/alloc.h>
27 #include <osl/diagnose.h>
32 struct ErrorManagerStruct
34 struct jpeg_error_mgr pub
;
35 jmp_buf setjmp_buffer
;
38 void jpeg_svstream_src (j_decompress_ptr cinfo
, void* infile
);
39 void jpeg_svstream_dest (j_compress_ptr cinfo
, void* outfile
);
41 METHODDEF( void ) errorExit (j_common_ptr cinfo
)
43 ErrorManagerPointer error
= (ErrorManagerPointer
) cinfo
->err
;
44 (*cinfo
->err
->output_message
) (cinfo
);
45 longjmp(error
->setjmp_buffer
, 1);
48 METHODDEF( void ) outputMessage (j_common_ptr cinfo
)
50 char buffer
[JMSG_LENGTH_MAX
];
51 (*cinfo
->err
->format_message
) (cinfo
, buffer
);
54 /* TODO: when incompatible changes are possible again
55 the preview size hint should be redone */
56 static int nPreviewWidth
= 0;
57 static int nPreviewHeight
= 0;
58 void SetJpegPreviewSizeHint( int nWidth
, int nHeight
)
60 nPreviewWidth
= nWidth
;
61 nPreviewHeight
= nHeight
;
64 void ReadJPEG( void* pJPEGReader
, void* pInputStream
, long* pLines
)
66 struct jpeg_decompress_struct cinfo
;
67 struct ErrorManagerStruct jerr
;
68 struct JPEGCreateBitmapParam aCreateBitmapParam
;
75 HPBYTE pScanLineBuffer
= NULL
;
76 long nScanLineBufferComponents
= 0;
78 if ( setjmp( jerr
.setjmp_buffer
) )
80 jpeg_destroy_decompress( &cinfo
);
84 cinfo
.err
= jpeg_std_error( &jerr
.pub
);
85 jerr
.pub
.error_exit
= errorExit
;
86 jerr
.pub
.output_message
= outputMessage
;
88 jpeg_create_decompress( &cinfo
);
89 jpeg_svstream_src( &cinfo
, pInputStream
);
90 jpeg_read_header( &cinfo
, TRUE
);
93 cinfo
.scale_denom
= 1;
94 cinfo
.output_gamma
= 1.0;
95 cinfo
.raw_data_out
= FALSE
;
96 cinfo
.quantize_colors
= FALSE
;
97 if ( cinfo
.jpeg_color_space
== JCS_YCbCr
)
98 cinfo
.out_color_space
= JCS_RGB
;
99 else if ( cinfo
.jpeg_color_space
== JCS_YCCK
)
100 cinfo
.out_color_space
= JCS_CMYK
;
102 OSL_ASSERT(cinfo
.out_color_space
== JCS_CMYK
|| cinfo
.out_color_space
== JCS_GRAYSCALE
|| cinfo
.out_color_space
== JCS_RGB
);
104 /* change scale for preview import */
105 if( nPreviewWidth
|| nPreviewHeight
)
107 if( nPreviewWidth
== 0 )
109 nPreviewWidth
= ( cinfo
.image_width
* nPreviewHeight
) / cinfo
.image_height
;
110 if( nPreviewWidth
<= 0 )
115 else if( nPreviewHeight
== 0 )
117 nPreviewHeight
= ( cinfo
.image_height
* nPreviewWidth
) / cinfo
.image_width
;
118 if( nPreviewHeight
<= 0 )
124 for( cinfo
.scale_denom
= 1; cinfo
.scale_denom
< 8; cinfo
.scale_denom
*= 2 )
126 if( cinfo
.image_width
< nPreviewWidth
* cinfo
.scale_denom
)
128 if( cinfo
.image_height
< nPreviewHeight
* cinfo
.scale_denom
)
132 if( cinfo
.scale_denom
> 1 )
134 cinfo
.dct_method
= JDCT_FASTEST
;
135 cinfo
.do_fancy_upsampling
= FALSE
;
136 cinfo
.do_block_smoothing
= FALSE
;
140 jpeg_start_decompress( &cinfo
);
142 nWidth
= cinfo
.output_width
;
143 nHeight
= cinfo
.output_height
;
144 aCreateBitmapParam
.nWidth
= nWidth
;
145 aCreateBitmapParam
.nHeight
= nHeight
;
147 aCreateBitmapParam
.density_unit
= cinfo
.density_unit
;
148 aCreateBitmapParam
.X_density
= cinfo
.X_density
;
149 aCreateBitmapParam
.Y_density
= cinfo
.Y_density
;
150 aCreateBitmapParam
.bGray
= cinfo
.output_components
== 1;
151 pDIB
= CreateBitmapFromJPEGReader( pJPEGReader
, &aCreateBitmapParam
);
152 nAlignedWidth
= aCreateBitmapParam
.nAlignedWidth
;
153 aRangeLimit
= cinfo
.sample_range_limit
;
155 if ( cinfo
.out_color_space
== JCS_CMYK
)
157 nScanLineBufferComponents
= cinfo
.output_width
* 4;
158 pScanLineBuffer
= rtl_allocateMemory( nScanLineBufferComponents
);
163 if( aCreateBitmapParam
.bTopDown
)
169 pTmp
= pDIB
+ ( nHeight
- 1 ) * nAlignedWidth
;
170 nAlignedWidth
= -nAlignedWidth
;
173 for ( *pLines
= 0; *pLines
< nHeight
; (*pLines
)++ )
175 if (pScanLineBuffer
!= NULL
)
176 { // in other words cinfo.out_color_space == JCS_CMYK
179 jpeg_read_scanlines( &cinfo
, (JSAMPARRAY
) &pScanLineBuffer
, 1 );
180 // convert CMYK to RGB
181 for( i
=0, j
=0; i
< nScanLineBufferComponents
; i
+=4, j
+=3 )
183 int color_C
= 255 - pScanLineBuffer
[i
+0];
184 int color_M
= 255 - pScanLineBuffer
[i
+1];
185 int color_Y
= 255 - pScanLineBuffer
[i
+2];
186 int color_K
= 255 - pScanLineBuffer
[i
+3];
187 pTmp
[j
+0] = aRangeLimit
[ 255L - ( color_C
+ color_K
) ];
188 pTmp
[j
+1] = aRangeLimit
[ 255L - ( color_M
+ color_K
) ];
189 pTmp
[j
+2] = aRangeLimit
[ 255L - ( color_Y
+ color_K
) ];
194 jpeg_read_scanlines( &cinfo
, (JSAMPARRAY
) &pTmp
, 1 );
198 if ( cinfo
.err
->msg_code
== 113 )
201 pTmp
+= nAlignedWidth
;
207 jpeg_finish_decompress( &cinfo
);
211 jpeg_abort_decompress( &cinfo
);
214 if (pScanLineBuffer
!= NULL
)
216 rtl_freeMemory( pScanLineBuffer
);
217 pScanLineBuffer
= NULL
;
220 jpeg_destroy_decompress( &cinfo
);
223 long WriteJPEG( void* pJPEGWriter
, void* pOutputStream
,
224 long nWidth
, long nHeight
, long bGreys
,
225 long nQualityPercent
, long aChromaSubsampling
,
226 void* pCallbackData
)
228 struct jpeg_compress_struct cinfo
;
229 struct ErrorManagerStruct jerr
;
233 if ( setjmp( jerr
.setjmp_buffer
) )
235 jpeg_destroy_compress( &cinfo
);
239 cinfo
.err
= jpeg_std_error( &jerr
.pub
);
240 jerr
.pub
.error_exit
= errorExit
;
241 jerr
.pub
.output_message
= outputMessage
;
243 jpeg_create_compress( &cinfo
);
244 jpeg_svstream_dest( &cinfo
, pOutputStream
);
246 cinfo
.image_width
= (JDIMENSION
) nWidth
;
247 cinfo
.image_height
= (JDIMENSION
) nHeight
;
250 cinfo
.input_components
= 1;
251 cinfo
.in_color_space
= JCS_GRAYSCALE
;
255 cinfo
.input_components
= 3;
256 cinfo
.in_color_space
= JCS_RGB
;
259 jpeg_set_defaults( &cinfo
);
260 jpeg_set_quality( &cinfo
, (int) nQualityPercent
, FALSE
);
262 if ( ( nWidth
> 128 ) || ( nHeight
> 128 ) )
263 jpeg_simple_progression( &cinfo
);
265 if (aChromaSubsampling
== 1) // YUV 4:4:4
267 cinfo
.comp_info
[0].h_samp_factor
= 1;
268 cinfo
.comp_info
[0].v_samp_factor
= 1;
270 else if (aChromaSubsampling
== 2) // YUV 4:2:2
272 cinfo
.comp_info
[0].h_samp_factor
= 2;
273 cinfo
.comp_info
[0].v_samp_factor
= 1;
275 else if (aChromaSubsampling
== 3) // YUV 4:2:0
277 cinfo
.comp_info
[0].h_samp_factor
= 2;
278 cinfo
.comp_info
[0].v_samp_factor
= 2;
281 jpeg_start_compress( &cinfo
, TRUE
);
283 for( nY
= 0; nY
< nHeight
; nY
++ )
285 pScanline
= GetScanline( pJPEGWriter
, nY
);
289 jpeg_write_scanlines( &cinfo
, (JSAMPARRAY
) &pScanline
, 1 );
292 if( JPEGCallback( pCallbackData
, nY
* 100L / nHeight
) )
294 jpeg_destroy_compress( &cinfo
);
299 jpeg_finish_compress(&cinfo
);
300 jpeg_destroy_compress( &cinfo
);
305 long Transform(void* pInputStream
, void* pOutputStream
, long nAngle
)
307 jpeg_transform_info aTransformOption
;
308 JCOPY_OPTION aCopyOption
= JCOPYOPT_ALL
;
310 struct jpeg_decompress_struct aSourceInfo
;
311 struct jpeg_compress_struct aDestinationInfo
;
312 struct ErrorManagerStruct aSourceError
;
313 struct ErrorManagerStruct aDestinationError
;
315 jvirt_barray_ptr
* aSourceCoefArrays
= 0;
316 jvirt_barray_ptr
* aDestinationCoefArrays
= 0;
318 aTransformOption
.force_grayscale
= FALSE
;
319 aTransformOption
.trim
= FALSE
;
320 aTransformOption
.perfect
= FALSE
;
321 aTransformOption
.crop
= FALSE
;
323 // Angle to transform option
324 // 90 Clockwise = 270 Counterclockwise
328 aTransformOption
.transform
= JXFORM_ROT_90
;
331 aTransformOption
.transform
= JXFORM_ROT_180
;
334 aTransformOption
.transform
= JXFORM_ROT_270
;
337 aTransformOption
.transform
= JXFORM_NONE
;
341 aSourceInfo
.err
= jpeg_std_error(&aSourceError
.pub
);
342 aSourceInfo
.err
->error_exit
= errorExit
;
343 aSourceInfo
.err
->output_message
= outputMessage
;
346 aDestinationInfo
.err
= jpeg_std_error(&aDestinationError
.pub
);
347 aDestinationInfo
.err
->error_exit
= errorExit
;
348 aDestinationInfo
.err
->output_message
= outputMessage
;
350 aDestinationInfo
.optimize_coding
= TRUE
;
352 if (setjmp(aSourceError
.setjmp_buffer
) || setjmp(aDestinationError
.setjmp_buffer
))
354 jpeg_destroy_decompress(&aSourceInfo
);
355 jpeg_destroy_compress(&aDestinationInfo
);
359 jpeg_create_decompress(&aSourceInfo
);
360 jpeg_create_compress(&aDestinationInfo
);
362 jpeg_svstream_src (&aSourceInfo
, pInputStream
);
364 jcopy_markers_setup(&aSourceInfo
, aCopyOption
);
365 jpeg_read_header(&aSourceInfo
, 1);
366 jtransform_request_workspace(&aSourceInfo
, &aTransformOption
);
368 aSourceCoefArrays
= jpeg_read_coefficients(&aSourceInfo
);
369 jpeg_copy_critical_parameters(&aSourceInfo
, &aDestinationInfo
);
371 aDestinationCoefArrays
= jtransform_adjust_parameters(&aSourceInfo
, &aDestinationInfo
, aSourceCoefArrays
, &aTransformOption
);
372 jpeg_svstream_dest (&aDestinationInfo
, pOutputStream
);
374 // Compute optimal Huffman coding tables instead of precomuted tables
375 aDestinationInfo
.optimize_coding
= 1;
376 jpeg_write_coefficients(&aDestinationInfo
, aDestinationCoefArrays
);
377 jcopy_markers_execute(&aSourceInfo
, &aDestinationInfo
, aCopyOption
);
378 jtransform_execute_transformation(&aSourceInfo
, &aDestinationInfo
, aSourceCoefArrays
, &aTransformOption
);
380 jpeg_finish_compress(&aDestinationInfo
);
381 jpeg_destroy_compress(&aDestinationInfo
);
383 jpeg_finish_decompress(&aSourceInfo
);
384 jpeg_destroy_decompress(&aSourceInfo
);
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */