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             .client_data = NULL, .err = jpeg_std_error(&jerr)
58     };
59 
60     // Now we can initialize the JPEG compression object.
61     jpeg_create_compress(&cinfo);
62 
63     // Step 2: specify data destination (we will use a memory buffer)
64     struct jpeg_destination_mgr dm = {
65             .init_destination = init_buffer, .empty_output_buffer = empty_buffer,
66             .term_destination = term_buffer, .next_output_byte = buffPtr,
67             .free_in_buffer = (size_t) image_width * image_height * 3
68     };
69     cinfo.dest = &dm;
70 
71     // Step 3: set parameters for compression
72 
73     cinfo.image_width = (JDIMENSION) image_width;
74     cinfo.image_height = (JDIMENSION) image_height;
75     if (destCS == deviceRGB || destCS == adobeRGB) {
76         cinfo.in_color_space = JCS_RGB;
77         cinfo.jpeg_color_space = JCS_RGB;
78         cinfo.input_components = 3;
79     } else {
80         cinfo.in_color_space = JCS_GRAYSCALE;
81         cinfo.jpeg_color_space = JCS_GRAYSCALE;
82         cinfo.input_components = 1;
83     }
84 
85     jpeg_set_defaults(&cinfo);
86 
87     /* Now you can set any non-default parameters you wish to.
88      * Here we just illustrate the use of quality (quantization table) scaling:
89      */
90     jpeg_set_quality(&cinfo, quality, TRUE); // TRUE = limit to baseline-JPEG values
91 
92     // Set the density so that the JFIF header has the correct settings
93     cinfo.density_unit = 1;      // 1=dots-per-inch, 2=dots per cm
94     cinfo.X_density = (UINT16) resolution;
95     cinfo.Y_density = (UINT16) resolution;
96 
97     // set the rows/columns setting to reflect the resolution
98     // MCU = Minimum Coded Unit
99     cinfo.MCUs_per_row = (JDIMENSION) image_width;
100     cinfo.MCU_rows_in_scan = (JDIMENSION) image_height;
101 
102     // Step 4: Start compressor
103     jpeg_start_compress(&cinfo, TRUE);
104 
105     // Step 5: Write scanlines
106 
107     int row_stride; // physical row width in image buffer
108     row_stride = image_width * cinfo.input_components; // JSAMPLEs per row in imageBuffer
109 
110     JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s]
111     while (cinfo.next_scanline < cinfo.image_height) {
112         row_pointer[0] = &imageBuffer[cinfo.next_scanline * row_stride];
113         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
114     }
115 
116     // Step 6: Finish compression
117 
118     jpeg_finish_compress(&cinfo);
119 
120     // Step 7: release JPEG compression object
121 
122     jpeg_destroy_compress(&cinfo);
123 
124     *numCompBytes = (int) (cinfo.dest->next_output_byte - buffPtr);
125 
126     LOGD("write_JPEG_Buff: w=%d, h=%d, r=%d, q=%d compressed to %d", image_width, image_height,
127             resolution, quality, *numCompBytes);
128 }