1 /*****************************************************************************\
2 ModeJpeg.cpp : Jpeg compressor implementation
4 Copyright (c) 1996 - 2009, Hewlett-Packard Co.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of Hewlett-Packard nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
31 #include "CommonDefinitions.h"
37 #define MAX_JPEG_FILE_SIZE 2097152 // 2 Mgabytes
41 int (*HPLJJRCompress) (BYTE *pCompressedData,
42 uint32_t *pCompressedDataLen,
44 const uint32_t uiLogicalImageWidth,
45 const uint32_t uiLogicalImageHeight);
48 ModeJpeg::ModeJpeg(unsigned int raster_width) : Compressor (raster_width, false)
50 m_eCompressor = COMPRESSOR_JPEG_QUICKCONNECT;
52 m_max_file_size = MAX_JPEG_FILE_SIZE;;
54 m_iRowWidth = (int) raster_width * 3;
57 m_uiGrayscaleOffset = 0;
58 m_pbyInputBuffer = NULL;
59 m_hHPLibHandle = NULL;
62 // Don't need originalKData buffer allocate by Compressor, delete it
65 delete [] originalKData;
70 DRIVER_ERROR ModeJpeg::Init(int max_file_size, int page_height)
72 int buffer_size = m_iRowWidth * (page_height + 2);
73 m_pbyInputBuffer = new BYTE[buffer_size];
74 if (m_pbyInputBuffer == NULL)
76 return ALLOCMEM_ERROR;
78 if (max_file_size > 0)
80 m_max_file_size = (unsigned int) max_file_size;
82 compressBuf = new BYTE[m_max_file_size];
83 if (compressBuf == NULL)
85 return ALLOCMEM_ERROR;
87 m_iBandHeight = page_height;
91 DRIVER_ERROR ModeJpeg::Init(int color_mode, int band_height, COMPRESS_MODE *eCompressMode, QTableInfo *qtable_info)
94 m_iColorMode = color_mode;
95 m_pQTableInfo = qtable_info;
96 int buf_size = band_height * m_iRowWidth;
97 err = Init(buf_size, band_height);
103 // If plugin is not available or the plugin does not contain Taos compressor, stay with JPEG compression
104 m_eCompressor = COMPRESSOR_JPEG_JETREADY;
105 if (*eCompressMode == COMPRESS_MODE_LJ)
107 m_hHPLibHandle = LoadPlugin ("lj.so");
111 *(void **) (&HPLJJRCompress) = dlsym (m_hHPLibHandle, "HPJetReadyCompress");
112 if (HPLJJRCompress == NULL)
114 dlclose(m_hHPLibHandle);
115 m_hHPLibHandle = NULL;
116 *eCompressMode = COMPRESS_MODE_JPEG;
120 m_eCompressor = COMPRESSOR_TAOS;
127 ModeJpeg::~ModeJpeg()
131 dlclose(m_hHPLibHandle);
133 if (m_pbyInputBuffer)
135 delete [] m_pbyInputBuffer;
139 void ModeJpeg::Flush()
141 if (m_iRowNumber > 0)
147 #define RGBTOGRAY(rgb) (BYTE) ((rgb[0] * 30 + rgb[1] * 59 + rgb[2] * 11) / 100)
148 void ModeJpeg::rgbToGray(BYTE *rgbData, int iNumBytes)
150 if (m_eCompressor == COMPRESSOR_TAOS)
152 BYTE *p = m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth);
153 for (int i = 0; i < iNumBytes; i += 3, rgbData += 3)
155 *p++ = RGBTOGRAY(rgbData);
161 BYTE *p = m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth / 3);
162 for (int i = 0; i < iNumBytes; i += 3, rgbData += 3)
164 *p++ = 255 - RGBTOGRAY(rgbData);
168 bool ModeJpeg::Process(RASTERDATA *input)
174 if (input->rasterdata[COLORTYPE_COLOR])
176 if (m_iColorMode == 0)
178 memcpy(m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth), input->rasterdata[COLORTYPE_COLOR],
179 input->rastersize[COLORTYPE_COLOR]);
183 rgbToGray(input->rasterdata[COLORTYPE_COLOR], input->rastersize[COLORTYPE_COLOR]);
187 if (m_iRowNumber == m_iBandHeight)
195 bool ModeJpeg::NextOutputRaster (RASTERDATA &next_raster)
197 if (iRastersReady == 0)
201 if (myplane == COLORTYPE_COLOR && compressedsize != 0)
203 next_raster.rastersize[COLORTYPE_COLOR] = compressedsize - m_uiGrayscaleOffset;
204 next_raster.rasterdata[COLORTYPE_COLOR] = compressBuf + m_uiGrayscaleOffset;
208 next_raster.rastersize[COLORTYPE_COLOR] = 0;
209 next_raster.rasterdata[COLORTYPE_COLOR] = NULL;
211 next_raster.rastersize[COLORTYPE_BLACK] = 0;
212 next_raster.rasterdata[COLORTYPE_BLACK] = NULL;
215 m_uiGrayscaleOffset = 0;
219 static void output_buffer_callback (JOCTET *outbuf, BYTE *buffer, int size)
221 ModeJpeg *pModeJpeg = (ModeJpeg *) outbuf;
222 pModeJpeg->StoreJpegData (buffer, size);
225 void ModeJpeg::StoreJpegData (BYTE *buffer, int iSize)
227 compressedsize += iSize;
228 if (compressedsize < m_max_file_size)
230 memcpy (compressBuf + compressedsize - iSize, buffer, iSize);
234 compressedsize = m_max_file_size + 1;
238 //----------------------------------------------------------------
239 // These are "overrides" to the JPEG library error routines
240 //----------------------------------------------------------------
242 static void HPJpeg_error (j_common_ptr cinfo)
249 void jpeg_buffer_dest (j_compress_ptr cinfo, JOCTET* outbuff, void* flush_output_buffer_callback);
250 void hp_rgb_ycc_setup (int iFlag);
253 void ModeJpeg::compress ()
255 switch(m_eCompressor)
257 case COMPRESSOR_JPEG_QUICKCONNECT:
259 jpegCompressForQuickConnect();
262 case COMPRESSOR_JPEG_JETREADY:
264 jpegCompressForJetReady();
267 case COMPRESSOR_TAOS:
269 taosCompressForJetReady();
275 memset(m_pbyInputBuffer, 0xFF, m_iRowWidth * m_iBandHeight);
278 void ModeJpeg::jpegCompressForQuickConnect()
284 * Convert the byte buffer to jpg, if converted size is greater than 2MB, delete it and
285 * convert with a higher compression factor.
288 struct jpeg_compress_struct cinfo;
289 struct jpeg_error_mgr jerr;
290 jmp_buf setjmp_buffer;
294 // Use the standard RGB to YCC table rather than the modified one for JetReady
296 hp_rgb_ycc_setup (0);
301 memset (compressBuf, 0xFF, m_max_file_size);
302 p = m_pbyInputBuffer;
304 cinfo.err = jpeg_std_error (&jerr);
305 jerr.error_exit = HPJpeg_error;
306 if (setjmp (setjmp_buffer))
308 jpeg_destroy_compress (&cinfo);
312 jpeg_create_compress (&cinfo);
313 cinfo.in_color_space = JCS_RGB;
314 jpeg_set_defaults (&cinfo);
315 cinfo.image_width = m_iRowWidth / 3;
316 cinfo.image_height = m_iRowNumber;
317 cinfo.input_components = 3;
318 cinfo.data_precision = 8;
319 jpeg_set_quality (&cinfo, iQuality, TRUE);
320 jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback));
321 jpeg_start_compress (&cinfo, TRUE);
322 JSAMPROW pRowArray[1];
323 for (int i = 0; i < m_iRowNumber; i++)
325 pRowArray[0] = (JSAMPROW) p;
326 jpeg_write_scanlines (&cinfo, pRowArray, 1);
328 if (compressedsize > m_max_file_size)
334 jpeg_finish_compress (&cinfo);
335 jpeg_destroy_compress (&cinfo);
346 void ModeJpeg::jpegCompressForJetReady()
348 struct jpeg_compress_struct cinfo;
349 struct jpeg_error_mgr jerr;
350 jmp_buf setjmp_buffer;
353 // Use the modified Mojave CSC table
354 hp_rgb_ycc_setup (1);
357 memset (compressBuf, 0xFF, m_max_file_size);
359 cinfo.err = jpeg_std_error (&jerr);
360 jerr.error_exit = HPJpeg_error;
361 if (setjmp (setjmp_buffer))
363 jpeg_destroy_compress (&cinfo);
367 jpeg_create_compress (&cinfo);
368 cinfo.in_color_space = (m_iColorMode == 0) ? JCS_RGB : JCS_GRAYSCALE;
369 jpeg_set_defaults (&cinfo);
370 cinfo.image_width = m_iRowWidth / 3;
371 cinfo.image_height = m_iBandHeight;
372 cinfo.input_components = (m_iColorMode == 0) ? 3 : 1;
373 cinfo.data_precision = 8;
375 // Create a static quant table here.
377 static unsigned int mojave_quant_table1[64] = {
389 // JetReady specific Q-Tables will be added here. We do the following:
390 // 1. Add three Q-Tables.
391 // 2. Scale the Q-Table elemets with the given scale factor.
392 // 3. Check to see if any of the element in the table is greater than 255
393 // reset that elemet to 255.
394 // 5. There is a specific scaling needed to be done to the first 6
395 // elements in the matrix. This is required to achieve better
396 // compression ratio.
397 // 4. Check to see if any the of the recently modified element is
398 // greater than 255, reset that to 255.
400 // Please refer to sRGBLaserHostBasedSoftwareERS.doc v9.0 section 5.2.5.3.1.1
403 // [NOTE] These loop needs to be further optimized.
405 for (int i = 0; i < 3; i++)
409 jpeg_add_quant_table(&cinfo, i, mojave_quant_table1, 0, FALSE );
411 // Scaling the Q-Table elements.
412 // Reset the element to 255, if it is greater than 255.
415 for(int j = 1; j < 64; j++)
417 cinfo.quant_tbl_ptrs[i]->quantval[j] = (UINT16)((mojave_quant_table1[j] * m_pQTableInfo->qFactor) & 0xFF);
418 } // for (int j = 1; j < 64; j++)
421 // Special scaling for first 6 elements in the table.
422 // Reset the specially scaled elements 255, if it is greater than 255.
426 // 1st component in the table. Unchanged, I need not change anything here.
428 cinfo.quant_tbl_ptrs[i]->quantval[0] = (UINT16)mojave_quant_table1[0];
431 // 2nd and 3rd components in the zig zag order
433 // The following dTemp is being used to ceil the vales: e.g 28.5 to 29
435 double dTemp = mojave_quant_table1[1] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5;
436 cinfo.quant_tbl_ptrs[i]->quantval[1] = (UINT16)dTemp & 0xFF;
438 dTemp = mojave_quant_table1[8] * (1 + 0.25 * (m_pQTableInfo->qFactor - 1)) + 0.5;
439 cinfo.quant_tbl_ptrs[i]->quantval[8] = (UINT16)dTemp & 0xFF;
442 // 4th, 5th and 6th components in the zig zag order
444 dTemp = mojave_quant_table1[16] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
445 cinfo.quant_tbl_ptrs[i]->quantval[16] = (UINT16)dTemp & 0xFF;
447 dTemp = mojave_quant_table1[9] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
448 cinfo.quant_tbl_ptrs[i]->quantval[9] = (UINT16)dTemp & 0xFF;
450 dTemp = mojave_quant_table1[2] * (1 + 0.50 * (m_pQTableInfo->qFactor - 1)) + 0.5;
451 cinfo.quant_tbl_ptrs[i]->quantval[2] = (UINT16)dTemp & 0xFF;
452 } // for (i = 0; i < 3; i++)
454 // Hard code to use sampling mode 4:4:4
456 cinfo.comp_info[0].h_samp_factor = 1;
457 cinfo.comp_info[0].v_samp_factor = 1;
459 jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback));
461 int row_width = m_iRowWidth;
462 if (m_iColorMode != 0)
464 row_width = m_iRowWidth / 3;
465 cinfo.write_JFIF_header = FALSE;
466 cinfo.write_Adobe_marker = FALSE;
467 jpeg_suppress_tables(&cinfo, TRUE);
470 jpeg_start_compress (&cinfo, TRUE);
471 JSAMPROW pRowArray[1];
472 BYTE *pScanLine = m_pbyInputBuffer;
474 for (i = 0; i < m_iBandHeight; i++)
476 pRowArray[0] = (JSAMPROW) pScanLine;
477 jpeg_write_scanlines (&cinfo, pRowArray, 1);
478 pScanLine += (row_width);
480 jpeg_finish_compress (&cinfo);
482 // Read the quantization table used for this compression
484 if (cinfo.quant_tbl_ptrs[0] != NULL)
486 // memcpy(m_pQTableInfo->qtable0, cinfo.quant_tbl_ptrs[0]->quantval, QTABLE_SIZE);
487 for (i = 0; i < QTABLE_SIZE; i++)
489 m_pQTableInfo->qtable0[i] = cinfo.quant_tbl_ptrs[0]->quantval[i];
492 if (cinfo.quant_tbl_ptrs[1] != NULL)
494 // memcpy(m_pQTableInfo->qtable1, cinfo.quant_tbl_ptrs[1]->quantval, QTABLE_SIZE);
495 for (i = 0; i < QTABLE_SIZE; i++)
497 m_pQTableInfo->qtable1[i] = cinfo.quant_tbl_ptrs[1]->quantval[i];
500 if (cinfo.quant_tbl_ptrs[2] != NULL)
502 // memcpy(m_pQTableInfo->qtable2, cinfo.quant_tbl_ptrs[2]->quantval, QTABLE_SIZE);
503 for (i = 0; i < QTABLE_SIZE; i++)
505 m_pQTableInfo->qtable2[i] = cinfo.quant_tbl_ptrs[2]->quantval[i];
508 jpeg_destroy_compress (&cinfo);
509 if (m_iColorMode != 0)
512 while (l < compressedsize)
514 if (compressBuf[l] == 0xFF && compressBuf[l+1] == 0xDA)
518 if (l != compressedsize)
520 m_uiGrayscaleOffset = l + 10;
525 void ModeJpeg::taosCompressForJetReady()
528 int bufSize = m_max_file_size;
529 iRet = HPLJJRCompress(compressBuf, (uint32_t *) &bufSize, m_pbyInputBuffer, m_iRowWidth / 3, m_iBandHeight);
530 compressedsize = (iRet < 0) ? 0 : bufSize;