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