1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  * Copyright (C) 2016 Mopria Alliance, Inc.
4  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <stdio.h>
20 #include "common_defines.h"
21 #include <wprint_debug.h>
22 
23 extern "C"
24 {
25 #include <jpeglib.h>
26 }
27 
28 #define TAG "genJPEGStrips"
29 
30 /*
31  * Function for setting up the buffer (which we already did)
32  */
init_buffer(jpeg_compress_struct *)33 static void init_buffer(jpeg_compress_struct *) {
34 }
35 
36 /*
37  * Function for handling buffer overlow (should not happen because we allocated a large
38  * buffer)
39  */
empty_buffer(jpeg_compress_struct *)40 static boolean empty_buffer(jpeg_compress_struct *) {
41     return TRUE;
42 }
43 
44 /*
45  * Function for finalizing the buffer (which we do not need to do)
46  */
term_buffer(jpeg_compress_struct *)47 static void term_buffer(jpeg_compress_struct *) {
48 }
49 
50 GLOBAL(void)
write_JPEG_Buff(ubyte * buffPtr,int quality,int image_width,int image_height,JSAMPLE * imageBuffer,int resolution,colorSpaceDisposition destCS,int * numCompBytes)51 write_JPEG_Buff(ubyte *buffPtr, int quality, int image_width, int image_height,
52         JSAMPLE *imageBuffer, int resolution, colorSpaceDisposition destCS, int *numCompBytes) {
53     struct jpeg_error_mgr jerr;
54 
55     // Step 1: allocate and initialize JPEG compression object
56     struct jpeg_compress_struct cinfo = {
57             .err = jpeg_std_error(&jerr),
58             .client_data = NULL,
59     };
60 
61     // Now we can initialize the JPEG compression object.
62     jpeg_create_compress(&cinfo);
63 
64     // Step 2: specify data destination (we will use a memory buffer)
65     struct jpeg_destination_mgr dm = {
66             .next_output_byte = buffPtr,
67             .free_in_buffer = (size_t) image_width * image_height * 3,
68             .init_destination = init_buffer, .empty_output_buffer = empty_buffer,
69             .term_destination = term_buffer,
70     };
71     cinfo.dest = &dm;
72 
73     // Step 3: set parameters for compression
74 
75     cinfo.image_width = (JDIMENSION) image_width;
76     cinfo.image_height = (JDIMENSION) image_height;
77     if (destCS == deviceRGB || destCS == adobeRGB) {
78         cinfo.in_color_space = JCS_RGB;
79         cinfo.jpeg_color_space = JCS_RGB;
80         cinfo.input_components = 3;
81     } else {
82         cinfo.in_color_space = JCS_GRAYSCALE;
83         cinfo.jpeg_color_space = JCS_GRAYSCALE;
84         cinfo.input_components = 1;
85     }
86 
87     jpeg_set_defaults(&cinfo);
88 
89     /* Now you can set any non-default parameters you wish to.
90      * Here we just illustrate the use of quality (quantization table) scaling:
91      */
92     jpeg_set_quality(&cinfo, quality, TRUE); // TRUE = limit to baseline-JPEG values
93 
94     // Set the density so that the JFIF header has the correct settings
95     cinfo.density_unit = 1;      // 1=dots-per-inch, 2=dots per cm
96     cinfo.X_density = (UINT16) resolution;
97     cinfo.Y_density = (UINT16) resolution;
98 
99     // set the rows/columns setting to reflect the resolution
100     // MCU = Minimum Coded Unit
101     cinfo.MCUs_per_row = (JDIMENSION) image_width;
102     cinfo.MCU_rows_in_scan = (JDIMENSION) image_height;
103 
104     // Step 4: Start compressor
105     jpeg_start_compress(&cinfo, TRUE);
106 
107     // Step 5: Write scanlines
108 
109     int row_stride; // physical row width in image buffer
110     row_stride = image_width * cinfo.input_components; // JSAMPLEs per row in imageBuffer
111 
112     JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
113     while (cinfo.next_scanline < cinfo.image_height) {
114         row_pointer[0] = &imageBuffer[cinfo.next_scanline * row_stride];
115         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
116     }
117 
118     // Step 6: Finish compression
119 
120     jpeg_finish_compress(&cinfo);
121 
122     // Step 7: release JPEG compression object
123 
124     jpeg_destroy_compress(&cinfo);
125 
126     *numCompBytes = (int) (cinfo.dest->next_output_byte - buffPtr);
127 
128     LOGD("write_JPEG_Buff: w=%d, h=%d, r=%d, q=%d compressed to %d", image_width, image_height,
129             resolution, quality, *numCompBytes);
130 }
131