Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpcups / ModeJpeg.cpp
1 /*****************************************************************************\
2   ModeJpeg.cpp : Jpeg compressor implementation
3
4   Copyright (c) 1996 - 2009, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
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.
18
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 \*****************************************************************************/
30
31 #include "CommonDefinitions.h"
32 #include <setjmp.h>
33 #include "ModeJpeg.h"
34 #include <dlfcn.h>
35 #include "Utils.h"
36
37 #define MAX_JPEG_FILE_SIZE 2097152    // 2 Mgabytes
38
39 extern "C"
40 {
41     int (*HPLJJRCompress) (BYTE        *pCompressedData,
42                            uint32_t    *pCompressedDataLen,
43                            BYTE        *InputData,
44                            const uint32_t    uiLogicalImageWidth,
45                            const uint32_t    uiLogicalImageHeight);
46 }
47
48 ModeJpeg::ModeJpeg(unsigned int raster_width) : Compressor (raster_width, false)
49 {
50     m_eCompressor       = COMPRESSOR_JPEG_QUICKCONNECT;
51     m_iColorMode        = 0;
52     m_max_file_size     = MAX_JPEG_FILE_SIZE;;
53     compressedsize      = 0;
54     m_iRowWidth         = (int) raster_width * 3;
55     m_iRowNumber        = 0;
56     m_iBandHeight       = 0;
57     m_uiGrayscaleOffset = 0;
58     m_pbyInputBuffer    = NULL;
59     m_hHPLibHandle      = NULL;
60     compressBuf         = NULL;
61
62 //  Don't need originalKData buffer allocate by Compressor, delete it
63     if (originalKData)
64     {
65         delete [] originalKData;
66         originalKData = NULL;
67     }
68 }
69
70 DRIVER_ERROR ModeJpeg::Init(int max_file_size, int page_height)
71 {
72     int    buffer_size = m_iRowWidth * (page_height + 2);
73     m_pbyInputBuffer = new BYTE[buffer_size];
74     if (m_pbyInputBuffer == NULL)
75     {
76         return ALLOCMEM_ERROR;
77     }
78     if (max_file_size > 0)
79     {
80         m_max_file_size = (unsigned int) max_file_size;
81     }
82     compressBuf = new BYTE[m_max_file_size];
83     if (compressBuf == NULL)
84     {
85         return ALLOCMEM_ERROR;
86     }
87     m_iBandHeight = page_height;
88     return NO_ERROR;
89 }
90
91 DRIVER_ERROR ModeJpeg::Init(int color_mode, int band_height, COMPRESS_MODE *eCompressMode, QTableInfo *qtable_info)
92 {
93     DRIVER_ERROR    err;
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);
98     if (err != NO_ERROR)
99     {
100         return err;
101     }
102
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)
106     {
107         m_hHPLibHandle = LoadPlugin ("lj.so");
108         if (m_hHPLibHandle)
109         {
110             dlerror ();
111             *(void **) (&HPLJJRCompress) = dlsym (m_hHPLibHandle, "HPJetReadyCompress");
112             if (HPLJJRCompress == NULL)
113             {
114                 dlclose(m_hHPLibHandle);
115                 m_hHPLibHandle = NULL;
116                 *eCompressMode = COMPRESS_MODE_JPEG;
117             }
118             else
119             {
120                 m_eCompressor = COMPRESSOR_TAOS;
121             }
122         }
123     }
124     return err;
125 }
126
127 ModeJpeg::~ModeJpeg()
128 {
129     if (m_hHPLibHandle)
130     {
131         dlclose(m_hHPLibHandle);
132     }
133     if (m_pbyInputBuffer)
134     {
135         delete [] m_pbyInputBuffer;
136     }
137 }
138
139 void ModeJpeg::Flush()
140 {
141     if (m_iRowNumber > 0)
142     {
143         compress();
144     }
145 }
146
147 #define RGBTOGRAY(rgb) (BYTE) ((rgb[0] * 30 + rgb[1] * 59 + rgb[2] * 11) / 100)
148 void ModeJpeg::rgbToGray(BYTE *rgbData, int iNumBytes)
149 {
150     if (m_eCompressor == COMPRESSOR_TAOS)
151     {
152         BYTE    *p = m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth);
153         for (int i = 0; i < iNumBytes; i += 3, rgbData += 3)
154         {
155             *p++ = RGBTOGRAY(rgbData);
156             *p++ = 0;
157             *p++ - 0;
158         }
159         return;
160     }
161     BYTE    *p = m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth / 3);
162     for (int i = 0; i < iNumBytes; i += 3, rgbData += 3)
163     {
164         *p++ = 255 - RGBTOGRAY(rgbData);
165     }
166 }
167
168 bool ModeJpeg::Process(RASTERDATA *input)
169 {
170     if (input == NULL)
171     {
172         return false;
173     }
174     if (input->rasterdata[COLORTYPE_COLOR])
175     {
176         if (m_iColorMode == 0)
177         {
178             memcpy(m_pbyInputBuffer + (m_iRowNumber * m_iRowWidth), input->rasterdata[COLORTYPE_COLOR],
179                    input->rastersize[COLORTYPE_COLOR]);
180         }
181         else
182         {
183             rgbToGray(input->rasterdata[COLORTYPE_COLOR], input->rastersize[COLORTYPE_COLOR]);
184         }
185     }
186     m_iRowNumber++;
187     if (m_iRowNumber == m_iBandHeight)
188     {
189         compress();
190         return true;
191     }
192     return false;
193 }
194
195 bool ModeJpeg::NextOutputRaster (RASTERDATA &next_raster)
196 {
197     if (iRastersReady == 0)
198     {
199         return false;
200     }
201     if (myplane == COLORTYPE_COLOR && compressedsize != 0)
202     {
203         next_raster.rastersize[COLORTYPE_COLOR] = compressedsize - m_uiGrayscaleOffset;
204         next_raster.rasterdata[COLORTYPE_COLOR] = compressBuf + m_uiGrayscaleOffset;
205     }
206     else
207     {
208         next_raster.rastersize[COLORTYPE_COLOR] = 0;
209         next_raster.rasterdata[COLORTYPE_COLOR] = NULL;
210     }
211     next_raster.rastersize[COLORTYPE_BLACK] = 0;
212     next_raster.rasterdata[COLORTYPE_BLACK] = NULL;
213
214     iRastersReady = 0;
215     m_uiGrayscaleOffset = 0;
216     return true;
217 }
218
219 static void output_buffer_callback (JOCTET *outbuf, BYTE *buffer, int size)
220 {
221     ModeJpeg    *pModeJpeg = (ModeJpeg *) outbuf;
222     pModeJpeg->StoreJpegData (buffer, size);
223 }
224
225 void ModeJpeg::StoreJpegData (BYTE *buffer, int iSize)
226 {
227     compressedsize += iSize;
228     if (compressedsize < m_max_file_size)
229     {
230         memcpy (compressBuf + compressedsize - iSize, buffer, iSize);
231     }
232     else
233     {
234         compressedsize = m_max_file_size + 1;
235     }
236 }
237
238 //----------------------------------------------------------------
239 // These are "overrides" to the JPEG library error routines
240 //----------------------------------------------------------------
241
242 static void HPJpeg_error (j_common_ptr cinfo)
243 {
244
245 }
246
247 extern "C"
248 {
249     void jpeg_buffer_dest (j_compress_ptr cinfo, JOCTET* outbuff, void* flush_output_buffer_callback);
250     void hp_rgb_ycc_setup (int iFlag);
251 }
252
253 void ModeJpeg::compress () 
254 {
255     switch(m_eCompressor)
256     {
257         case COMPRESSOR_JPEG_QUICKCONNECT:
258         {
259             jpegCompressForQuickConnect();
260             break;
261         }
262         case COMPRESSOR_JPEG_JETREADY:
263         {
264             jpegCompressForJetReady();
265             break;
266         }
267         case COMPRESSOR_TAOS:
268         {
269             taosCompressForJetReady();
270             break;
271         }
272     }
273     m_iRowNumber = 0;
274     iRastersReady = 1;
275     memset(m_pbyInputBuffer, 0xFF, m_iRowWidth * m_iBandHeight);
276 }
277
278 void ModeJpeg::jpegCompressForQuickConnect()
279 {
280     BYTE    *p;
281     int     iQuality = 100;
282
283 /*
284  *  Convert the byte buffer to jpg, if converted size is greater than 2MB, delete it and
285  *  convert with a higher compression factor.
286  */
287
288     struct jpeg_compress_struct cinfo;
289     struct jpeg_error_mgr       jerr;
290     jmp_buf                     setjmp_buffer;
291
292     bool    bRedo;
293
294 //  Use the standard RGB to YCC table rather than the modified one for JetReady
295
296     hp_rgb_ycc_setup (0);
297     do
298     {
299         bRedo = 0;
300         compressedsize = 0;
301         memset (compressBuf, 0xFF, m_max_file_size);
302         p = m_pbyInputBuffer;
303
304         cinfo.err = jpeg_std_error (&jerr);
305         jerr.error_exit = HPJpeg_error;
306         if (setjmp (setjmp_buffer))
307         {
308             jpeg_destroy_compress (&cinfo);
309             return;
310         }
311
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++)
324         {
325             pRowArray[0] = (JSAMPROW) p;
326             jpeg_write_scanlines (&cinfo, pRowArray, 1);
327             p += (m_iRowWidth);
328             if (compressedsize > m_max_file_size)
329             {
330                 compressedsize = 0;
331                 bRedo = 1;
332             }
333         }
334         jpeg_finish_compress (&cinfo);
335         jpeg_destroy_compress (&cinfo);
336         iQuality -= 10;
337         if (iQuality == 0)
338         {
339             compressedsize = 0;
340             return;
341         }
342     } while (bRedo);
343     return;
344 }
345
346 void ModeJpeg::jpegCompressForJetReady()
347 {
348     struct jpeg_compress_struct cinfo;
349     struct jpeg_error_mgr       jerr;
350     jmp_buf                     setjmp_buffer;
351
352
353 //  Use the modified Mojave CSC table
354     hp_rgb_ycc_setup (1);
355
356     compressedsize = 0;
357     memset (compressBuf, 0xFF, m_max_file_size);
358
359     cinfo.err = jpeg_std_error (&jerr);
360     jerr.error_exit = HPJpeg_error;
361     if (setjmp (setjmp_buffer))
362     {
363         jpeg_destroy_compress (&cinfo);
364         return;
365     }
366
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;
374
375     // Create a static quant table here. 
376
377     static unsigned int mojave_quant_table1[64] =  {
378                                                     2,3,4,5,5,5,5,5,
379                                                     3,6,5,8,5,8,5,8,
380                                                     4,5,5,5,5,5,5,5,
381                                                     5,8,5,8,5,8,5,8,
382                                                     5,5,5,5,5,5,5,5,
383                                                     5,8,5,8,5,8,5,8,
384                                                     5,5,5,5,5,5,5,5,
385                                                     5,8,5,8,5,8,5,8
386                                                     };
387     
388     //
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.
399     //
400     //  Please refer to sRGBLaserHostBasedSoftwareERS.doc v9.0 section 5.2.5.3.1.1
401     //  for more details.
402     //
403     //  [NOTE] These loop needs to be further optimized.
404     //
405     for (int i = 0; i < 3; i++)
406     {
407         // Adding Q-Table.
408
409         jpeg_add_quant_table(&cinfo, i, mojave_quant_table1,  0, FALSE );
410         //
411         // Scaling the Q-Table elements. 
412         // Reset the element to 255, if it is greater than 255.
413         //
414
415         for(int j = 1; j < 64; j++)
416         {
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++)
419
420         //
421         // Special scaling for first 6 elements in the table.
422         // Reset the specially scaled elements 255, if it is greater than 255.
423         //
424
425         //
426         // 1st component in the table. Unchanged, I need not change anything here.
427         //
428         cinfo.quant_tbl_ptrs[i]->quantval[0] = (UINT16)mojave_quant_table1[0];
429         
430         //
431         // 2nd and 3rd components in the zig zag order
432         //
433         // The following dTemp is being used  to ceil the vales: e.g 28.5 to 29
434         //
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;
437         
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;
440        
441         //
442         // 4th, 5th and 6th components in the zig zag order
443         //
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;
446         
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;
449         
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++)
453
454     // Hard code to use sampling mode 4:4:4
455
456     cinfo.comp_info[0].h_samp_factor = 1;
457     cinfo.comp_info[0].v_samp_factor = 1;
458
459     jpeg_buffer_dest (&cinfo, (JOCTET *) this, (void *) (output_buffer_callback));
460
461     int    row_width = m_iRowWidth;
462     if (m_iColorMode != 0)
463     {
464         row_width = m_iRowWidth / 3;
465         cinfo.write_JFIF_header = FALSE;
466         cinfo.write_Adobe_marker = FALSE;
467         jpeg_suppress_tables(&cinfo, TRUE);
468     }
469
470     jpeg_start_compress (&cinfo, TRUE);
471     JSAMPROW    pRowArray[1];
472     BYTE        *pScanLine = m_pbyInputBuffer;
473     int         i;
474     for (i = 0; i < m_iBandHeight; i++)
475     {
476         pRowArray[0] = (JSAMPROW) pScanLine;
477         jpeg_write_scanlines (&cinfo, pRowArray, 1);
478         pScanLine += (row_width);
479     }
480     jpeg_finish_compress (&cinfo);
481
482 //  Read the quantization table used for this compression
483
484     if (cinfo.quant_tbl_ptrs[0] != NULL)
485     {
486 //        memcpy(m_pQTableInfo->qtable0, cinfo.quant_tbl_ptrs[0]->quantval, QTABLE_SIZE);
487         for (i = 0; i < QTABLE_SIZE; i++)
488         {
489             m_pQTableInfo->qtable0[i] = cinfo.quant_tbl_ptrs[0]->quantval[i];
490         }
491     }
492     if (cinfo.quant_tbl_ptrs[1] != NULL)
493     {
494 //        memcpy(m_pQTableInfo->qtable1, cinfo.quant_tbl_ptrs[1]->quantval, QTABLE_SIZE);
495         for (i = 0; i < QTABLE_SIZE; i++)
496         {
497             m_pQTableInfo->qtable1[i] = cinfo.quant_tbl_ptrs[1]->quantval[i];
498         }
499     }
500     if (cinfo.quant_tbl_ptrs[2] != NULL)
501     {
502 //        memcpy(m_pQTableInfo->qtable2, cinfo.quant_tbl_ptrs[2]->quantval, QTABLE_SIZE);
503         for (i = 0; i < QTABLE_SIZE; i++)
504         {
505             m_pQTableInfo->qtable2[i] = cinfo.quant_tbl_ptrs[2]->quantval[i];
506         }
507     }
508     jpeg_destroy_compress (&cinfo);
509     if (m_iColorMode != 0)
510     {
511         unsigned int    l = 0;
512         while (l < compressedsize)
513         {
514             if (compressBuf[l] == 0xFF && compressBuf[l+1] == 0xDA)
515                 break;
516             l++;
517         }
518         if (l != compressedsize)
519         {
520             m_uiGrayscaleOffset = l + 10;
521         }
522     }
523 }
524
525 void ModeJpeg::taosCompressForJetReady()
526 {
527     int    iRet;
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;
531 }
532