1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "setjmp.h"
25 #include "jpeglib.h"
26 #include "jerror.h"
27 #include "jpeg.h"
28 #include "rtl/alloc.h"
29 #include "osl/diagnose.h"
30
31 struct my_error_mgr
32 {
33 struct jpeg_error_mgr pub;
34 jmp_buf setjmp_buffer;
35 };
36
37 void jpeg_svstream_src (j_decompress_ptr cinfo, void* infile);
38 void jpeg_svstream_dest (j_compress_ptr cinfo, void* outfile);
39
40 METHODDEF( void )
my_error_exit(j_common_ptr cinfo)41 my_error_exit (j_common_ptr cinfo)
42 {
43 my_error_ptr myerr = (my_error_ptr) cinfo->err;
44 (*cinfo->err->output_message) (cinfo);
45 longjmp(myerr->setjmp_buffer, 1);
46 }
47
48
49 METHODDEF( void )
my_output_message(j_common_ptr cinfo)50 my_output_message (j_common_ptr cinfo)
51 {
52 char buffer[JMSG_LENGTH_MAX];
53 (*cinfo->err->format_message) (cinfo, buffer);
54 }
55
56 /* TODO: when incompatible changes are possible again
57 the preview size hint should be redone */
58 static int nPreviewWidth = 0;
59 static int nPreviewHeight = 0;
SetJpegPreviewSizeHint(int nWidth,int nHeight)60 void SetJpegPreviewSizeHint( int nWidth, int nHeight )
61 {
62 nPreviewWidth = nWidth;
63 nPreviewHeight = nHeight;
64 }
65
ReadJPEG(void * pJPEGReader,void * pIStm,long * pLines)66 void ReadJPEG( void* pJPEGReader, void* pIStm, long* pLines )
67 {
68 struct jpeg_decompress_struct cinfo;
69 struct my_error_mgr jerr;
70 struct JPEGCreateBitmapParam aCreateBitmapParam;
71 HPBYTE pDIB;
72 HPBYTE pTmp;
73 long nWidth;
74 long nHeight;
75 long nAlignedWidth;
76 JSAMPLE * range_limit;
77 HPBYTE pScanLineBuffer = NULL;
78 long nScanLineBufferComponents = 0;
79 // declare bDecompCreated volatile because of gcc
80 // warning: variable 'bDecompCreated' might be clobbered by `longjmp' or `vfork'
81 volatile long bDecompCreated = 0;
82
83 /* Falls der Stream nicht ausreicht (IO_PENDING)
84 wird ueber ein longjmp in der Schleife nach Exit
85 gesprungen, wir geben dann die Anzahl
86 der bisher bearbeiteten Scanlines zurueck*/
87 if ( setjmp( jerr.setjmp_buffer ) )
88 goto Exit;
89
90 cinfo.err = jpeg_std_error( &jerr.pub );
91 jerr.pub.error_exit = my_error_exit;
92 jerr.pub.output_message = my_output_message;
93
94 jpeg_create_decompress( &cinfo );
95 bDecompCreated = 1;
96 jpeg_svstream_src( &cinfo, pIStm );
97 jpeg_read_header( &cinfo, sal_True );
98
99 cinfo.scale_num = 1;
100 cinfo.scale_denom = 1;
101 cinfo.output_gamma = 1.0;
102 cinfo.raw_data_out = sal_False;
103 cinfo.quantize_colors = sal_False;
104 if ( cinfo.jpeg_color_space == JCS_YCbCr )
105 cinfo.out_color_space = JCS_RGB;
106 else if ( cinfo.jpeg_color_space == JCS_YCCK )
107 cinfo.out_color_space = JCS_CMYK;
108
109 OSL_ASSERT(cinfo.out_color_space == JCS_CMYK || cinfo.out_color_space == JCS_GRAYSCALE || cinfo.out_color_space == JCS_RGB);
110
111 /* change scale for preview import */
112 if( nPreviewWidth || nPreviewHeight )
113 {
114 if( nPreviewWidth == 0 ) {
115 nPreviewWidth = ( cinfo.image_width*nPreviewHeight )/cinfo.image_height;
116 if( nPreviewWidth <= 0 )
117 nPreviewWidth = 1;
118 } else if( nPreviewHeight == 0 ) {
119 nPreviewHeight = ( cinfo.image_height*nPreviewWidth )/cinfo.image_width;
120 if( nPreviewHeight <= 0 )
121 nPreviewHeight = 1;
122 }
123
124 for( cinfo.scale_denom = 1; cinfo.scale_denom < 8; cinfo.scale_denom *= 2 )
125 {
126 if( cinfo.image_width < nPreviewWidth * cinfo.scale_denom )
127 break;
128 if( cinfo.image_height < nPreviewHeight * cinfo.scale_denom )
129 break;
130 }
131
132 if( cinfo.scale_denom > 1 )
133 {
134 cinfo.dct_method = JDCT_FASTEST;
135 cinfo.do_fancy_upsampling = sal_False;
136 cinfo.do_block_smoothing = sal_False;
137 }
138 }
139
140 jpeg_start_decompress( &cinfo );
141
142 nWidth = cinfo.output_width;
143 nHeight = cinfo.output_height;
144 aCreateBitmapParam.nWidth = nWidth;
145 aCreateBitmapParam.nHeight = nHeight;
146
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 = CreateBitmap( pJPEGReader, &aCreateBitmapParam );
152 nAlignedWidth = aCreateBitmapParam.nAlignedWidth;
153 range_limit=cinfo.sample_range_limit;
154
155 if ( cinfo.out_color_space == JCS_CMYK )
156 {
157 nScanLineBufferComponents = cinfo.output_width * 4;
158 pScanLineBuffer = rtl_allocateMemory( nScanLineBufferComponents );
159 }
160
161 if( pDIB )
162 {
163 if( aCreateBitmapParam.bTopDown )
164 pTmp = pDIB;
165 else
166 {
167 pTmp = pDIB + ( nHeight - 1 ) * nAlignedWidth;
168 nAlignedWidth = -nAlignedWidth;
169 }
170
171 for ( *pLines = 0; *pLines < nHeight; (*pLines)++ )
172 {
173 if (pScanLineBuffer!=NULL) { // in other words cinfo.out_color_space == JCS_CMYK
174 int i;
175 int j;
176 jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pScanLineBuffer, 1 );
177 // convert CMYK to RGB
178 for( i=0, j=0; i < nScanLineBufferComponents; i+=4, j+=3 )
179 {
180 int c_=255-pScanLineBuffer[i+0];
181 int m_=255-pScanLineBuffer[i+1];
182 int y_=255-pScanLineBuffer[i+2];
183 int k_=255-pScanLineBuffer[i+3];
184 pTmp[j+0]=range_limit[ 255L - ( c_ + k_ ) ];
185 pTmp[j+1]=range_limit[ 255L - ( m_ + k_ ) ];
186 pTmp[j+2]=range_limit[ 255L - ( y_ + k_ ) ];
187 }
188 } else {
189 jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pTmp, 1 );
190 }
191 /* PENDING ??? */
192 if ( cinfo.err->msg_code == 113 )
193 break;
194
195 pTmp += nAlignedWidth;
196 }
197 }
198
199 if ( pDIB )
200 {
201 jpeg_finish_decompress( &cinfo );
202 }
203 else
204 {
205 jpeg_abort_decompress( &cinfo );
206 }
207
208 if (pScanLineBuffer!=NULL) {
209 rtl_freeMemory( pScanLineBuffer );
210 pScanLineBuffer=NULL;
211 }
212
213 Exit:
214
215 if( bDecompCreated )
216 jpeg_destroy_decompress( &cinfo );
217 }
218
WriteJPEG(void * pJPEGWriter,void * pOStm,long nWidth,long nHeight,long bGreys,long nQualityPercent,void * pCallbackData)219 long WriteJPEG( void* pJPEGWriter, void* pOStm,
220 long nWidth, long nHeight, long bGreys,
221 long nQualityPercent, void* pCallbackData )
222 {
223 struct jpeg_compress_struct cinfo;
224 struct my_error_mgr jerr;
225 void* pScanline;
226 long nY;
227 // declare bCompCreated, bRet volatile because of gcc
228 // warning: variable 'bCompCreated' might be clobbered by `longjmp' or `vfork'
229 volatile long bCompCreated = 0;
230 volatile long bRet = 0;
231
232 if ( setjmp( jerr.setjmp_buffer ) )
233 goto Exit;
234
235 cinfo.err = jpeg_std_error( &jerr.pub );
236 jerr.pub.error_exit = my_error_exit;
237 jerr.pub.output_message = my_output_message;
238
239 jpeg_create_compress( &cinfo );
240 bCompCreated = 1;
241
242 jpeg_svstream_dest( &cinfo, pOStm );
243
244 cinfo.image_width = (JDIMENSION) nWidth;
245 cinfo.image_height = (JDIMENSION) nHeight;
246 if ( bGreys )
247 {
248 cinfo.input_components = 1;
249 cinfo.in_color_space = JCS_GRAYSCALE;
250 }
251 else
252 {
253 cinfo.input_components = 3;
254 cinfo.in_color_space = JCS_RGB;
255 }
256
257 jpeg_set_defaults( &cinfo );
258 jpeg_set_quality( &cinfo, (int) nQualityPercent, sal_False );
259
260 if ( ( nWidth > 128 ) || ( nHeight > 128 ) )
261 jpeg_simple_progression( &cinfo );
262
263 jpeg_start_compress( &cinfo, sal_True );
264
265 for( nY = 0; nY < nHeight; nY++ )
266 {
267 pScanline = GetScanline( pJPEGWriter, nY );
268
269 if( pScanline )
270 jpeg_write_scanlines( &cinfo, (JSAMPARRAY) &pScanline, 1 );
271
272 if( JPEGCallback( pCallbackData, nY * 100L / nHeight ) )
273 goto Exit;
274 }
275
276 bRet = 1;
277
278 jpeg_finish_compress(&cinfo);
279
280 Exit:
281
282 if ( bCompCreated )
283 jpeg_destroy_compress( &cinfo );
284
285 return bRet;
286 }
287