Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <stdio.h>
21 : #include <stdlib.h>
22 : #include "setjmp.h"
23 : #include "jpeglib.h"
24 : #include "jerror.h"
25 : #include "jpeg.h"
26 : #include "rtl/alloc.h"
27 : #include "osl/diagnose.h"
28 :
29 : struct my_error_mgr
30 : {
31 : struct jpeg_error_mgr pub;
32 : jmp_buf setjmp_buffer;
33 : };
34 :
35 : void jpeg_svstream_src (j_decompress_ptr cinfo, void* infile);
36 : void jpeg_svstream_dest (j_compress_ptr cinfo, void* outfile);
37 :
38 : METHODDEF( void )
39 4 : my_error_exit (j_common_ptr cinfo)
40 : {
41 4 : my_error_ptr myerr = (my_error_ptr) cinfo->err;
42 4 : (*cinfo->err->output_message) (cinfo);
43 4 : longjmp(myerr->setjmp_buffer, 1);
44 : }
45 :
46 :
47 : METHODDEF( void )
48 9 : my_output_message (j_common_ptr cinfo)
49 : {
50 : char buffer[JMSG_LENGTH_MAX];
51 9 : (*cinfo->err->format_message) (cinfo, buffer);
52 9 : }
53 :
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 8 : void SetJpegPreviewSizeHint( int nWidth, int nHeight )
59 : {
60 8 : nPreviewWidth = nWidth;
61 8 : nPreviewHeight = nHeight;
62 8 : }
63 :
64 8 : void ReadJPEG( void* pJPEGReader, void* pIStm, long* pLines )
65 : {
66 : struct jpeg_decompress_struct cinfo;
67 : struct my_error_mgr jerr;
68 : struct JPEGCreateBitmapParam aCreateBitmapParam;
69 : HPBYTE pDIB;
70 : HPBYTE pTmp;
71 : long nWidth;
72 : long nHeight;
73 : long nAlignedWidth;
74 : JSAMPLE * range_limit;
75 8 : HPBYTE pScanLineBuffer = NULL;
76 8 : long nScanLineBufferComponents = 0;
77 : // declare bDecompCreated volatile because of gcc
78 : // warning: variable 'bDecompCreated' might be clobbered by `longjmp' or `vfork'
79 8 : volatile long bDecompCreated = 0;
80 :
81 : /* Falls der Stream nicht ausreicht (IO_PENDING)
82 : wird ueber ein longjmp in der Schleife nach Exit
83 : gesprungen, wir geben dann die Anzahl
84 : der bisher bearbeiteten Scanlines zurueck*/
85 8 : if ( setjmp( jerr.setjmp_buffer ) )
86 4 : goto Exit;
87 :
88 8 : cinfo.err = jpeg_std_error( &jerr.pub );
89 8 : jerr.pub.error_exit = my_error_exit;
90 8 : jerr.pub.output_message = my_output_message;
91 :
92 8 : jpeg_create_decompress( &cinfo );
93 8 : bDecompCreated = 1;
94 8 : jpeg_svstream_src( &cinfo, pIStm );
95 8 : jpeg_read_header( &cinfo, sal_True );
96 :
97 7 : cinfo.scale_num = 1;
98 7 : cinfo.scale_denom = 1;
99 7 : cinfo.output_gamma = 1.0;
100 7 : cinfo.raw_data_out = sal_False;
101 7 : cinfo.quantize_colors = sal_False;
102 7 : if ( cinfo.jpeg_color_space == JCS_YCbCr )
103 7 : cinfo.out_color_space = JCS_RGB;
104 0 : else if ( cinfo.jpeg_color_space == JCS_YCCK )
105 0 : cinfo.out_color_space = JCS_CMYK;
106 :
107 : OSL_ASSERT(cinfo.out_color_space == JCS_CMYK || cinfo.out_color_space == JCS_GRAYSCALE || cinfo.out_color_space == JCS_RGB);
108 :
109 : /* change scale for preview import */
110 7 : if( nPreviewWidth || nPreviewHeight )
111 : {
112 0 : if( nPreviewWidth == 0 ) {
113 0 : nPreviewWidth = ( cinfo.image_width*nPreviewHeight )/cinfo.image_height;
114 0 : if( nPreviewWidth <= 0 )
115 0 : nPreviewWidth = 1;
116 0 : } else if( nPreviewHeight == 0 ) {
117 0 : nPreviewHeight = ( cinfo.image_height*nPreviewWidth )/cinfo.image_width;
118 0 : if( nPreviewHeight <= 0 )
119 0 : nPreviewHeight = 1;
120 : }
121 :
122 0 : for( cinfo.scale_denom = 1; cinfo.scale_denom < 8; cinfo.scale_denom *= 2 )
123 : {
124 0 : if( cinfo.image_width < nPreviewWidth * cinfo.scale_denom )
125 0 : break;
126 0 : if( cinfo.image_height < nPreviewHeight * cinfo.scale_denom )
127 0 : break;
128 : }
129 :
130 0 : if( cinfo.scale_denom > 1 )
131 : {
132 0 : cinfo.dct_method = JDCT_FASTEST;
133 0 : cinfo.do_fancy_upsampling = sal_False;
134 0 : cinfo.do_block_smoothing = sal_False;
135 : }
136 : }
137 :
138 7 : jpeg_start_decompress( &cinfo );
139 :
140 5 : nWidth = cinfo.output_width;
141 5 : nHeight = cinfo.output_height;
142 5 : aCreateBitmapParam.nWidth = nWidth;
143 5 : aCreateBitmapParam.nHeight = nHeight;
144 :
145 5 : aCreateBitmapParam.density_unit = cinfo.density_unit;
146 5 : aCreateBitmapParam.X_density = cinfo.X_density;
147 5 : aCreateBitmapParam.Y_density = cinfo.Y_density;
148 5 : aCreateBitmapParam.bGray = cinfo.output_components == 1;
149 5 : pDIB = CreateBitmap( pJPEGReader, &aCreateBitmapParam );
150 5 : nAlignedWidth = aCreateBitmapParam.nAlignedWidth;
151 5 : range_limit=cinfo.sample_range_limit;
152 :
153 5 : if ( cinfo.out_color_space == JCS_CMYK )
154 : {
155 0 : nScanLineBufferComponents = cinfo.output_width * 4;
156 0 : pScanLineBuffer = rtl_allocateMemory( nScanLineBufferComponents );
157 : }
158 :
159 5 : if( pDIB )
160 : {
161 5 : if( aCreateBitmapParam.bTopDown )
162 5 : pTmp = pDIB;
163 : else
164 : {
165 0 : pTmp = pDIB + ( nHeight - 1 ) * nAlignedWidth;
166 0 : nAlignedWidth = -nAlignedWidth;
167 : }
168 :
169 233 : for ( *pLines = 0; *pLines < nHeight; (*pLines)++ )
170 : {
171 228 : if (pScanLineBuffer!=NULL) { // in other words cinfo.out_color_space == JCS_CMYK
172 : int i;
173 : int j;
174 0 : jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pScanLineBuffer, 1 );
175 : // convert CMYK to RGB
176 0 : for( i=0, j=0; i < nScanLineBufferComponents; i+=4, j+=3 )
177 : {
178 0 : int c_=255-pScanLineBuffer[i+0];
179 0 : int m_=255-pScanLineBuffer[i+1];
180 0 : int y_=255-pScanLineBuffer[i+2];
181 0 : int k_=255-pScanLineBuffer[i+3];
182 0 : pTmp[j+0]=range_limit[ 255L - ( c_ + k_ ) ];
183 0 : pTmp[j+1]=range_limit[ 255L - ( m_ + k_ ) ];
184 0 : pTmp[j+2]=range_limit[ 255L - ( y_ + k_ ) ];
185 : }
186 : } else {
187 228 : jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pTmp, 1 );
188 : }
189 : /* PENDING ??? */
190 228 : if ( cinfo.err->msg_code == 113 )
191 0 : break;
192 :
193 228 : pTmp += nAlignedWidth;
194 : }
195 : }
196 :
197 5 : jpeg_finish_decompress( &cinfo );
198 4 : if (pScanLineBuffer!=NULL) {
199 0 : rtl_freeMemory( pScanLineBuffer );
200 0 : pScanLineBuffer=NULL;
201 : }
202 :
203 : Exit:
204 :
205 8 : if( bDecompCreated )
206 8 : jpeg_destroy_decompress( &cinfo );
207 8 : }
208 :
209 0 : long WriteJPEG( void* pJPEGWriter, void* pOStm,
210 : long nWidth, long nHeight, long bGreys,
211 : long nQualityPercent, void* pCallbackData )
212 : {
213 : struct jpeg_compress_struct cinfo;
214 : struct my_error_mgr jerr;
215 : void* pScanline;
216 : long nY;
217 : // declare bCompCreated, bRet volatile because of gcc
218 : // warning: variable 'bCompCreated' might be clobbered by `longjmp' or `vfork'
219 0 : volatile long bCompCreated = 0;
220 0 : volatile long bRet = 0;
221 :
222 0 : if ( setjmp( jerr.setjmp_buffer ) )
223 0 : goto Exit;
224 :
225 0 : cinfo.err = jpeg_std_error( &jerr.pub );
226 0 : jerr.pub.error_exit = my_error_exit;
227 0 : jerr.pub.output_message = my_output_message;
228 :
229 0 : jpeg_create_compress( &cinfo );
230 0 : bCompCreated = 1;
231 :
232 0 : jpeg_svstream_dest( &cinfo, pOStm );
233 :
234 0 : cinfo.image_width = (JDIMENSION) nWidth;
235 0 : cinfo.image_height = (JDIMENSION) nHeight;
236 0 : if ( bGreys )
237 : {
238 0 : cinfo.input_components = 1;
239 0 : cinfo.in_color_space = JCS_GRAYSCALE;
240 : }
241 : else
242 : {
243 0 : cinfo.input_components = 3;
244 0 : cinfo.in_color_space = JCS_RGB;
245 : }
246 :
247 0 : jpeg_set_defaults( &cinfo );
248 0 : jpeg_set_quality( &cinfo, (int) nQualityPercent, sal_False );
249 :
250 0 : if ( ( nWidth > 128 ) || ( nHeight > 128 ) )
251 0 : jpeg_simple_progression( &cinfo );
252 :
253 0 : jpeg_start_compress( &cinfo, sal_True );
254 :
255 0 : for( nY = 0; nY < nHeight; nY++ )
256 : {
257 0 : pScanline = GetScanline( pJPEGWriter, nY );
258 :
259 0 : if( pScanline )
260 0 : jpeg_write_scanlines( &cinfo, (JSAMPARRAY) &pScanline, 1 );
261 :
262 0 : if( JPEGCallback( pCallbackData, nY * 100L / nHeight ) )
263 0 : goto Exit;
264 : }
265 :
266 0 : bRet = 1;
267 :
268 0 : jpeg_finish_compress(&cinfo);
269 :
270 : Exit:
271 :
272 0 : if ( bCompCreated )
273 0 : jpeg_destroy_compress( &cinfo );
274 :
275 0 : return bRet;
276 : }
277 :
278 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|