xref: /trunk/main/svtools/source/filter/jpeg/jpegc.c (revision 5f609977)
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