/* * Copyright (C) 2016 The Android Open Source Project * Copyright (C) 2016 Mopria Alliance, Inc. * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "common_defines.h" #include extern "C" { #include } #define TAG "genJPEGStrips" /* * Function for setting up the buffer (which we already did) */ static void init_buffer(jpeg_compress_struct *) { } /* * Function for handling buffer overlow (should not happen because we allocated a large * buffer) */ static boolean empty_buffer(jpeg_compress_struct *) { return TRUE; } /* * Function for finalizing the buffer (which we do not need to do) */ static void term_buffer(jpeg_compress_struct *) { } GLOBAL(void) write_JPEG_Buff(ubyte *buffPtr, int quality, int image_width, int image_height, JSAMPLE *imageBuffer, int resolution, colorSpaceDisposition destCS, int *numCompBytes) { struct jpeg_error_mgr jerr; // Step 1: allocate and initialize JPEG compression object struct jpeg_compress_struct cinfo = { .client_data = NULL, .err = jpeg_std_error(&jerr) }; // Now we can initialize the JPEG compression object. jpeg_create_compress(&cinfo); // Step 2: specify data destination (we will use a memory buffer) struct jpeg_destination_mgr dm = { .init_destination = init_buffer, .empty_output_buffer = empty_buffer, .term_destination = term_buffer, .next_output_byte = buffPtr, .free_in_buffer = (size_t) image_width * image_height * 3 }; cinfo.dest = &dm; // Step 3: set parameters for compression cinfo.image_width = (JDIMENSION) image_width; cinfo.image_height = (JDIMENSION) image_height; if (destCS == deviceRGB || destCS == adobeRGB) { cinfo.in_color_space = JCS_RGB; cinfo.jpeg_color_space = JCS_RGB; cinfo.input_components = 3; } else { cinfo.in_color_space = JCS_GRAYSCALE; cinfo.jpeg_color_space = JCS_GRAYSCALE; cinfo.input_components = 1; } jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE); // TRUE = limit to baseline-JPEG values // Set the density so that the JFIF header has the correct settings cinfo.density_unit = 1; // 1=dots-per-inch, 2=dots per cm cinfo.X_density = (UINT16) resolution; cinfo.Y_density = (UINT16) resolution; // set the rows/columns setting to reflect the resolution // MCU = Minimum Coded Unit cinfo.MCUs_per_row = (JDIMENSION) image_width; cinfo.MCU_rows_in_scan = (JDIMENSION) image_height; // Step 4: Start compressor jpeg_start_compress(&cinfo, TRUE); // Step 5: Write scanlines int row_stride; // physical row width in image buffer row_stride = image_width * cinfo.input_components; // JSAMPLEs per row in imageBuffer JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &imageBuffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } // Step 6: Finish compression jpeg_finish_compress(&cinfo); // Step 7: release JPEG compression object jpeg_destroy_compress(&cinfo); *numCompBytes = (int) (cinfo.dest->next_output_byte - buffPtr); LOGD("write_JPEG_Buff: w=%d, h=%d, r=%d, q=%d compressed to %d", image_width, image_height, resolution, quality, *numCompBytes); }