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
23extern "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 */
33static 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 */
40static 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 */
47static void term_buffer(jpeg_compress_struct *) {
48}
49
50GLOBAL(void)
51write_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}