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