Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_jpeg.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// Intel License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Third party copyrights are property of their respective owners.
15
//
16
// Redistribution and use in source and binary forms, with or without modification,
17
// are permitted provided that the following conditions are met:
18
//
19
// * Redistribution's of source code must retain the above copyright notice,
20
// this list of conditions and the following disclaimer.
21
//
22
// * Redistribution's in binary form must reproduce the above copyright notice,
23
// this list of conditions and the following disclaimer in the documentation
24
// and/or other materials provided with the distribution.
25
//
26
// * The name of Intel Corporation may not be used to endorse or promote products
27
// derived from this software without specific prior written permission.
28
//
29
// This software is provided by the copyright holders and contributors "as is" and
30
// any express or implied warranties, including, but not limited to, the implied
31
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the Intel Corporation or contributors be liable for any direct,
33
// indirect, incidental, special, exemplary, or consequential damages
34
// (including, but not limited to, procurement of substitute goods or services;
35
// loss of use, data, or profits; or business interruption) however caused
36
// and on any theory of liability, whether in contract, strict liability,
37
// or tort (including negligence or otherwise) arising in any way out of
38
// the use of this software, even if advised of the possibility of such damage.
39
//
40
//M*/
41
42
#include "precomp.hpp"
43
#include "grfmt_jpeg.hpp"
44
45
#ifdef HAVE_JPEG
46
47
#ifdef _MSC_VER
48
//interaction between '_setjmp' and C++ object destruction is non-portable
49
#pragma warning(disable: 4611)
50
#endif
51
52
#include <stdio.h>
53
#include <setjmp.h>
54
55
// the following defines are a hack to avoid multiple problems with frame ponter handling and setjmp
56
// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
57
#define mingw_getsp(...) 0
58
#define __builtin_frame_address(...) 0
59
60
#ifdef _WIN32
61
62
#define XMD_H // prevent redefinition of INT32
63
#undef FAR // prevent FAR redefinition
64
65
#endif
66
67
#if defined _WIN32 && defined __GNUC__
68
typedef unsigned char boolean;
69
#endif
70
71
#undef FALSE
72
#undef TRUE
73
74
extern "C" {
75
#include "jpeglib.h"
76
}
77
78
namespace cv
79
{
80
81
struct JpegErrorMgr
82
{
83
struct jpeg_error_mgr pub;
84
jmp_buf setjmp_buffer;
85
};
86
87
struct JpegSource
88
{
89
struct jpeg_source_mgr pub;
90
int skip;
91
};
92
93
struct JpegState
94
{
95
jpeg_decompress_struct cinfo; // IJG JPEG codec structure
96
JpegErrorMgr jerr; // error processing manager state
97
JpegSource source; // memory buffer source
98
};
99
100
/////////////////////// Error processing /////////////////////
101
102
METHODDEF(void)
103
stub(j_decompress_ptr)
104
{
105
}
106
107
METHODDEF(boolean)
108
fill_input_buffer(j_decompress_ptr)
109
{
110
return FALSE;
111
}
112
113
// emulating memory input stream
114
115
METHODDEF(void)
116
skip_input_data(j_decompress_ptr cinfo, long num_bytes)
117
{
118
JpegSource* source = (JpegSource*) cinfo->src;
119
120
if( num_bytes > (long)source->pub.bytes_in_buffer )
121
{
122
// We need to skip more data than we have in the buffer.
123
// This will force the JPEG library to suspend decoding.
124
source->skip = (int)(num_bytes - source->pub.bytes_in_buffer);
125
source->pub.next_input_byte += source->pub.bytes_in_buffer;
126
source->pub.bytes_in_buffer = 0;
127
}
128
else
129
{
130
// Skip portion of the buffer
131
source->pub.bytes_in_buffer -= num_bytes;
132
source->pub.next_input_byte += num_bytes;
133
source->skip = 0;
134
}
135
}
136
137
138
static void jpeg_buffer_src(j_decompress_ptr cinfo, JpegSource* source)
139
{
140
cinfo->src = &source->pub;
141
142
// Prepare for suspending reader
143
source->pub.init_source = stub;
144
source->pub.fill_input_buffer = fill_input_buffer;
145
source->pub.skip_input_data = skip_input_data;
146
source->pub.resync_to_restart = jpeg_resync_to_restart;
147
source->pub.term_source = stub;
148
source->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
149
150
source->skip = 0;
151
}
152
153
154
METHODDEF(void)
155
error_exit( j_common_ptr cinfo )
156
{
157
JpegErrorMgr* err_mgr = (JpegErrorMgr*)(cinfo->err);
158
159
/* Return control to the setjmp point */
160
longjmp( err_mgr->setjmp_buffer, 1 );
161
}
162
163
164
/////////////////////// JpegDecoder ///////////////////
165
166
167
JpegDecoder::JpegDecoder()
168
{
169
m_signature = "\xFF\xD8\xFF";
170
m_state = 0;
171
m_f = 0;
172
m_buf_supported = true;
173
}
174
175
176
JpegDecoder::~JpegDecoder()
177
{
178
close();
179
}
180
181
182
void JpegDecoder::close()
183
{
184
if( m_state )
185
{
186
JpegState* state = (JpegState*)m_state;
187
jpeg_destroy_decompress( &state->cinfo );
188
delete state;
189
m_state = 0;
190
}
191
192
if( m_f )
193
{
194
fclose( m_f );
195
m_f = 0;
196
}
197
198
m_width = m_height = 0;
199
m_type = -1;
200
}
201
202
ImageDecoder JpegDecoder::newDecoder() const
203
{
204
return makePtr<JpegDecoder>();
205
}
206
207
bool JpegDecoder::readHeader()
208
{
209
volatile bool result = false;
210
close();
211
212
JpegState* state = new JpegState;
213
m_state = state;
214
state->cinfo.err = jpeg_std_error(&state->jerr.pub);
215
state->jerr.pub.error_exit = error_exit;
216
217
if( setjmp( state->jerr.setjmp_buffer ) == 0 )
218
{
219
jpeg_create_decompress( &state->cinfo );
220
221
if( !m_buf.empty() )
222
{
223
jpeg_buffer_src(&state->cinfo, &state->source);
224
state->source.pub.next_input_byte = m_buf.ptr();
225
state->source.pub.bytes_in_buffer = m_buf.cols*m_buf.rows*m_buf.elemSize();
226
}
227
else
228
{
229
m_f = fopen( m_filename.c_str(), "rb" );
230
if( m_f )
231
jpeg_stdio_src( &state->cinfo, m_f );
232
}
233
234
if (state->cinfo.src != 0)
235
{
236
jpeg_read_header( &state->cinfo, TRUE );
237
238
state->cinfo.scale_num=1;
239
state->cinfo.scale_denom = m_scale_denom;
240
m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_
241
jpeg_calc_output_dimensions(&state->cinfo);
242
m_width = state->cinfo.output_width;
243
m_height = state->cinfo.output_height;
244
m_type = state->cinfo.num_components > 1 ? CV_8UC3 : CV_8UC1;
245
result = true;
246
}
247
}
248
249
if( !result )
250
close();
251
252
return result;
253
}
254
255
/***************************************************************************
256
* following code is for supporting MJPEG image files
257
* based on a message of Laurent Pinchart on the video4linux mailing list
258
***************************************************************************/
259
260
/* JPEG DHT Segment for YCrCb omitted from MJPEG data */
261
static
262
unsigned char my_jpeg_odml_dht[0x1a4] = {
263
0xff, 0xc4, 0x01, 0xa2,
264
265
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
266
0x00, 0x00, 0x00, 0x00, 0x00,
267
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
268
269
0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
270
0x00, 0x00, 0x00, 0x00, 0x00,
271
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
272
273
0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
274
0x04, 0x00, 0x00, 0x01, 0x7d,
275
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
276
0x13, 0x51, 0x61, 0x07,
277
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1,
278
0x15, 0x52, 0xd1, 0xf0,
279
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a,
280
0x25, 0x26, 0x27, 0x28,
281
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
282
0x46, 0x47, 0x48, 0x49,
283
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
284
0x66, 0x67, 0x68, 0x69,
285
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85,
286
0x86, 0x87, 0x88, 0x89,
287
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
288
0xa4, 0xa5, 0xa6, 0xa7,
289
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
290
0xc2, 0xc3, 0xc4, 0xc5,
291
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
292
0xd9, 0xda, 0xe1, 0xe2,
293
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
294
0xf5, 0xf6, 0xf7, 0xf8,
295
0xf9, 0xfa,
296
297
0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
298
0x04, 0x00, 0x01, 0x02, 0x77,
299
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
300
0x51, 0x07, 0x61, 0x71,
301
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09,
302
0x23, 0x33, 0x52, 0xf0,
303
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
304
0x18, 0x19, 0x1a, 0x26,
305
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
306
0x45, 0x46, 0x47, 0x48,
307
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
308
0x65, 0x66, 0x67, 0x68,
309
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
310
0x84, 0x85, 0x86, 0x87,
311
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
312
0xa2, 0xa3, 0xa4, 0xa5,
313
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
314
0xb9, 0xba, 0xc2, 0xc3,
315
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
316
0xd7, 0xd8, 0xd9, 0xda,
317
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
318
0xf5, 0xf6, 0xf7, 0xf8,
319
0xf9, 0xfa
320
};
321
322
/*
323
* Parse the DHT table.
324
* This code comes from jpeg6b (jdmarker.c).
325
*/
326
static
327
int my_jpeg_load_dht (struct jpeg_decompress_struct *info, unsigned char *dht,
328
JHUFF_TBL *ac_tables[], JHUFF_TBL *dc_tables[])
329
{
330
unsigned int length = (dht[2] << 8) + dht[3] - 2;
331
unsigned int pos = 4;
332
unsigned int count, i;
333
int index;
334
335
JHUFF_TBL **hufftbl;
336
unsigned char bits[17];
337
unsigned char huffval[256] = {0};
338
339
while (length > 16)
340
{
341
bits[0] = 0;
342
index = dht[pos++];
343
count = 0;
344
for (i = 1; i <= 16; ++i)
345
{
346
bits[i] = dht[pos++];
347
count += bits[i];
348
}
349
length -= 17;
350
351
if (count > 256 || count > length)
352
return -1;
353
354
for (i = 0; i < count; ++i)
355
huffval[i] = dht[pos++];
356
length -= count;
357
358
if (index & 0x10)
359
{
360
index &= ~0x10;
361
hufftbl = &ac_tables[index];
362
}
363
else
364
hufftbl = &dc_tables[index];
365
366
if (index < 0 || index >= NUM_HUFF_TBLS)
367
return -1;
368
369
if (*hufftbl == NULL)
370
*hufftbl = jpeg_alloc_huff_table ((j_common_ptr)info);
371
if (*hufftbl == NULL)
372
return -1;
373
374
memcpy ((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
375
memcpy ((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
376
}
377
378
if (length != 0)
379
return -1;
380
381
return 0;
382
}
383
384
/***************************************************************************
385
* end of code for supportting MJPEG image files
386
* based on a message of Laurent Pinchart on the video4linux mailing list
387
***************************************************************************/
388
389
bool JpegDecoder::readData( Mat& img )
390
{
391
volatile bool result = false;
392
size_t step = img.step;
393
bool color = img.channels() > 1;
394
395
if( m_state && m_width && m_height )
396
{
397
jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo;
398
JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr;
399
JSAMPARRAY buffer = 0;
400
401
if( setjmp( jerr->setjmp_buffer ) == 0 )
402
{
403
/* check if this is a mjpeg image format */
404
if ( cinfo->ac_huff_tbl_ptrs[0] == NULL &&
405
cinfo->ac_huff_tbl_ptrs[1] == NULL &&
406
cinfo->dc_huff_tbl_ptrs[0] == NULL &&
407
cinfo->dc_huff_tbl_ptrs[1] == NULL )
408
{
409
/* yes, this is a mjpeg image format, so load the correct
410
huffman table */
411
my_jpeg_load_dht( cinfo,
412
my_jpeg_odml_dht,
413
cinfo->ac_huff_tbl_ptrs,
414
cinfo->dc_huff_tbl_ptrs );
415
}
416
417
if( color )
418
{
419
if( cinfo->num_components != 4 )
420
{
421
cinfo->out_color_space = JCS_RGB;
422
cinfo->out_color_components = 3;
423
}
424
else
425
{
426
cinfo->out_color_space = JCS_CMYK;
427
cinfo->out_color_components = 4;
428
}
429
}
430
else
431
{
432
if( cinfo->num_components != 4 )
433
{
434
cinfo->out_color_space = JCS_GRAYSCALE;
435
cinfo->out_color_components = 1;
436
}
437
else
438
{
439
cinfo->out_color_space = JCS_CMYK;
440
cinfo->out_color_components = 4;
441
}
442
}
443
444
jpeg_start_decompress( cinfo );
445
446
buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo,
447
JPOOL_IMAGE, m_width*4, 1 );
448
449
uchar* data = img.ptr();
450
for( ; m_height--; data += step )
451
{
452
jpeg_read_scanlines( cinfo, buffer, 1 );
453
if( color )
454
{
455
if( cinfo->out_color_components == 3 )
456
icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
457
else
458
icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) );
459
}
460
else
461
{
462
if( cinfo->out_color_components == 1 )
463
memcpy( data, buffer[0], m_width );
464
else
465
icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) );
466
}
467
}
468
469
result = true;
470
jpeg_finish_decompress( cinfo );
471
}
472
}
473
474
close();
475
return result;
476
}
477
478
479
/////////////////////// JpegEncoder ///////////////////
480
481
struct JpegDestination
482
{
483
struct jpeg_destination_mgr pub;
484
std::vector<uchar> *buf, *dst;
485
};
486
487
METHODDEF(void)
488
stub(j_compress_ptr)
489
{
490
}
491
492
METHODDEF(void)
493
term_destination (j_compress_ptr cinfo)
494
{
495
JpegDestination* dest = (JpegDestination*)cinfo->dest;
496
size_t sz = dest->dst->size(), bufsz = dest->buf->size() - dest->pub.free_in_buffer;
497
if( bufsz > 0 )
498
{
499
dest->dst->resize(sz + bufsz);
500
memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
501
}
502
}
503
504
METHODDEF(boolean)
505
empty_output_buffer (j_compress_ptr cinfo)
506
{
507
JpegDestination* dest = (JpegDestination*)cinfo->dest;
508
size_t sz = dest->dst->size(), bufsz = dest->buf->size();
509
dest->dst->resize(sz + bufsz);
510
memcpy( &(*dest->dst)[0] + sz, &(*dest->buf)[0], bufsz);
511
512
dest->pub.next_output_byte = &(*dest->buf)[0];
513
dest->pub.free_in_buffer = bufsz;
514
return TRUE;
515
}
516
517
static void jpeg_buffer_dest(j_compress_ptr cinfo, JpegDestination* destination)
518
{
519
cinfo->dest = &destination->pub;
520
521
destination->pub.init_destination = stub;
522
destination->pub.empty_output_buffer = empty_output_buffer;
523
destination->pub.term_destination = term_destination;
524
}
525
526
527
JpegEncoder::JpegEncoder()
528
{
529
m_description = "JPEG files (*.jpeg;*.jpg;*.jpe)";
530
m_buf_supported = true;
531
}
532
533
534
JpegEncoder::~JpegEncoder()
535
{
536
}
537
538
ImageEncoder JpegEncoder::newEncoder() const
539
{
540
return makePtr<JpegEncoder>();
541
}
542
543
bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
544
{
545
m_last_error.clear();
546
547
struct fileWrapper
548
{
549
FILE* f;
550
551
fileWrapper() : f(0) {}
552
~fileWrapper() { if(f) fclose(f); }
553
};
554
volatile bool result = false;
555
fileWrapper fw;
556
int width = img.cols, height = img.rows;
557
558
std::vector<uchar> out_buf(1 << 12);
559
AutoBuffer<uchar> _buffer;
560
uchar* buffer;
561
562
struct jpeg_compress_struct cinfo;
563
JpegErrorMgr jerr;
564
JpegDestination dest;
565
566
jpeg_create_compress(&cinfo);
567
cinfo.err = jpeg_std_error(&jerr.pub);
568
jerr.pub.error_exit = error_exit;
569
570
if( !m_buf )
571
{
572
fw.f = fopen( m_filename.c_str(), "wb" );
573
if( !fw.f )
574
goto _exit_;
575
jpeg_stdio_dest( &cinfo, fw.f );
576
}
577
else
578
{
579
dest.dst = m_buf;
580
dest.buf = &out_buf;
581
582
jpeg_buffer_dest( &cinfo, &dest );
583
584
dest.pub.next_output_byte = &out_buf[0];
585
dest.pub.free_in_buffer = out_buf.size();
586
}
587
588
if( setjmp( jerr.setjmp_buffer ) == 0 )
589
{
590
cinfo.image_width = width;
591
cinfo.image_height = height;
592
593
int _channels = img.channels();
594
int channels = _channels > 1 ? 3 : 1;
595
cinfo.input_components = channels;
596
cinfo.in_color_space = channels > 1 ? JCS_RGB : JCS_GRAYSCALE;
597
598
int quality = 95;
599
int progressive = 0;
600
int optimize = 0;
601
int rst_interval = 0;
602
int luma_quality = -1;
603
int chroma_quality = -1;
604
605
for( size_t i = 0; i < params.size(); i += 2 )
606
{
607
if( params[i] == CV_IMWRITE_JPEG_QUALITY )
608
{
609
quality = params[i+1];
610
quality = MIN(MAX(quality, 0), 100);
611
}
612
613
if( params[i] == CV_IMWRITE_JPEG_PROGRESSIVE )
614
{
615
progressive = params[i+1];
616
}
617
618
if( params[i] == CV_IMWRITE_JPEG_OPTIMIZE )
619
{
620
optimize = params[i+1];
621
}
622
623
if( params[i] == CV_IMWRITE_JPEG_LUMA_QUALITY )
624
{
625
if (params[i+1] >= 0)
626
{
627
luma_quality = MIN(MAX(params[i+1], 0), 100);
628
629
quality = luma_quality;
630
631
if (chroma_quality < 0)
632
{
633
chroma_quality = luma_quality;
634
}
635
}
636
}
637
638
if( params[i] == CV_IMWRITE_JPEG_CHROMA_QUALITY )
639
{
640
if (params[i+1] >= 0)
641
{
642
chroma_quality = MIN(MAX(params[i+1], 0), 100);
643
}
644
}
645
646
if( params[i] == CV_IMWRITE_JPEG_RST_INTERVAL )
647
{
648
rst_interval = params[i+1];
649
rst_interval = MIN(MAX(rst_interval, 0), 65535L);
650
}
651
}
652
653
jpeg_set_defaults( &cinfo );
654
cinfo.restart_interval = rst_interval;
655
656
jpeg_set_quality( &cinfo, quality,
657
TRUE /* limit to baseline-JPEG values */ );
658
if( progressive )
659
jpeg_simple_progression( &cinfo );
660
if( optimize )
661
cinfo.optimize_coding = TRUE;
662
663
#if JPEG_LIB_VERSION >= 70
664
if (luma_quality >= 0 && chroma_quality >= 0)
665
{
666
cinfo.q_scale_factor[0] = jpeg_quality_scaling(luma_quality);
667
cinfo.q_scale_factor[1] = jpeg_quality_scaling(chroma_quality);
668
if ( luma_quality != chroma_quality )
669
{
670
/* disable subsampling - ref. Libjpeg.txt */
671
cinfo.comp_info[0].v_samp_factor = 1;
672
cinfo.comp_info[0].h_samp_factor = 1;
673
cinfo.comp_info[1].v_samp_factor = 1;
674
cinfo.comp_info[1].h_samp_factor = 1;
675
}
676
jpeg_default_qtables( &cinfo, TRUE );
677
}
678
#endif // #if JPEG_LIB_VERSION >= 70
679
680
jpeg_start_compress( &cinfo, TRUE );
681
682
if( channels > 1 )
683
_buffer.allocate(width*channels);
684
buffer = _buffer.data();
685
686
for( int y = 0; y < height; y++ )
687
{
688
uchar *data = img.data + img.step*y, *ptr = data;
689
690
if( _channels == 3 )
691
{
692
icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
693
ptr = buffer;
694
}
695
else if( _channels == 4 )
696
{
697
icvCvt_BGRA2BGR_8u_C4C3R( data, 0, buffer, 0, cvSize(width,1), 2 );
698
ptr = buffer;
699
}
700
701
jpeg_write_scanlines( &cinfo, &ptr, 1 );
702
}
703
704
jpeg_finish_compress( &cinfo );
705
result = true;
706
}
707
708
_exit_:
709
710
if(!result)
711
{
712
char jmsg_buf[JMSG_LENGTH_MAX];
713
jerr.pub.format_message((j_common_ptr)&cinfo, jmsg_buf);
714
m_last_error = jmsg_buf;
715
}
716
717
jpeg_destroy_compress( &cinfo );
718
719
return result;
720
}
721
722
}
723
724
#endif
725
726
/* End of file. */
727
728