2 * Copyright (C) 2013 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "jpeg_hook.h"
18 #include "jpeg_writer.h"
19 #include "error_codes.h"
24 JpegWriter::JpegWriter() : mInfo(),
29 mScanlineBytesRemaining(0),
34 JpegWriter::~JpegWriter() {
35 if (reset() != J_SUCCESS) {
36 LOGE("Failed to destroy compress object, may leak memory.");
40 const int32_t JpegWriter::DEFAULT_X_DENSITY = 300;
41 const int32_t JpegWriter::DEFAULT_Y_DENSITY = 300;
42 const int32_t JpegWriter::DEFAULT_DENSITY_UNIT = 1;
44 int32_t JpegWriter::setup(JNIEnv *env, jobject out, int32_t width, int32_t height,
45 Jpeg_Config::Format format, int32_t quality) {
46 if (mFinished || mSetup) {
49 if (env->ExceptionCheck()) {
52 if (height <= 0 || width <= 0 || quality <= 0 || quality > 100) {
53 return J_ERROR_BAD_ARGS;
55 // Setup error handler
56 SetupErrMgr(reinterpret_cast<j_common_ptr>(&mInfo), &mErrorManager);
58 // Set jump address for error handling
59 if (setjmp(mErrorManager.setjmp_buf)) {
64 jpeg_create_compress(&mInfo);
66 // Setup global java refs
67 int32_t flags = MakeDst(&mInfo, env, out);
68 if (flags != J_SUCCESS) {
72 // Initialize width, height, and color space
73 mInfo.image_width = width;
74 mInfo.image_height = height;
75 const int components = (static_cast<int>(format) & 0xff);
78 mInfo.input_components = 1;
79 mInfo.in_color_space = JCS_GRAYSCALE;
83 mInfo.input_components = 3;
84 mInfo.in_color_space = JCS_RGB;
87 return J_ERROR_BAD_ARGS;
91 jpeg_set_defaults(&mInfo);
92 mInfo.density_unit = DEFAULT_DENSITY_UNIT; // JFIF code for pixel size units:
94 mInfo.X_density = DEFAULT_X_DENSITY; // Horizontal pixel density
95 mInfo.Y_density = DEFAULT_Y_DENSITY; // Vertical pixel density
97 // Set compress quality
98 jpeg_set_quality(&mInfo, quality, TRUE);
102 // Setup scanline buffer
103 mScanlineBuflen = width * components;
104 mScanlineBytesRemaining = mScanlineBuflen;
105 mScanlineBuf = (JSAMPLE *) (mInfo.mem->alloc_small)(
106 reinterpret_cast<j_common_ptr>(&mInfo), JPOOL_PERMANENT,
107 mScanlineBuflen * sizeof(JSAMPLE));
108 mScanlineIter = mScanlineBuf;
111 jpeg_start_compress(&mInfo, TRUE);
116 int32_t JpegWriter::write(int8_t* bytes, int32_t length) {
118 return J_ERROR_FATAL;
123 // Set jump address for error handling
124 if (setjmp(mErrorManager.setjmp_buf)) {
125 return J_ERROR_FATAL;
127 if (length < 0 || bytes == NULL) {
128 return J_ERROR_BAD_ARGS;
131 int32_t total_length = length;
132 JSAMPROW row_pointer[1];
133 while (mInfo.next_scanline < mInfo.image_height) {
134 if (length < mScanlineBytesRemaining) {
135 // read partial scanline and return
136 memcpy((void*) mScanlineIter, (void*) bytes,
137 length * sizeof(int8_t));
138 mScanlineBytesRemaining -= length;
139 mScanlineIter += length;
141 } else if (length > 0) {
142 // read full scanline
143 memcpy((void*) mScanlineIter, (void*) bytes,
144 mScanlineBytesRemaining * sizeof(int8_t));
145 bytes += mScanlineBytesRemaining;
146 length -= mScanlineBytesRemaining;
147 mScanlineBytesRemaining = 0;
149 // Do in-place pixel formatting
150 formatPixels(static_cast<uint8_t*>(mScanlineBuf), mScanlineBuflen);
151 row_pointer[0] = mScanlineBuf;
153 if (jpeg_write_scanlines(&mInfo, row_pointer, 1) != 1) {
154 return J_ERROR_FATAL;
156 // Reset scanline buffer
157 mScanlineBytesRemaining = mScanlineBuflen;
158 mScanlineIter = mScanlineBuf;
160 jpeg_finish_compress(&mInfo);
162 return total_length - length;
165 // Does in-place pixel formatting
166 void JpegWriter::formatPixels(uint8_t* buf, int32_t len) {
167 // Assumes len is a multiple of 4 for RGBA and ABGR pixels.
168 assert((len % 4) == 0);
171 case Jpeg_Config::FORMAT_RGBA: {
173 for (int i = 0; i < len / 4; ++i, buf += 4) {
180 case Jpeg_Config::FORMAT_ABGR: {
181 // Strips alphas and flips endianness
188 for (int i = 1; i < len / 4; ++i, buf += 4) {
202 void JpegWriter::updateEnv(JNIEnv *env) {
203 UpdateDstEnv(&mInfo, env);
206 int32_t JpegWriter::reset() {
207 // Set jump address for error handling
208 if (setjmp(mErrorManager.setjmp_buf)) {
209 return J_ERROR_FATAL;
211 // Clean up global java references
213 // Wipe compress struct, free memory pools
214 jpeg_destroy_compress(&mInfo);