2 * Copyright (C) 2014 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.
19 #include <android/bitmap.h>
23 using namespace jpegutil;
26 * Compresses a YCbCr image to jpeg, applying a crop and rotation.
28 * The input is defined as a set of 3 planes of 8-bit samples, one plane for
29 each channel of Y, Cb, Cr.
30 * The Y plane is assumed to have the same width and height of the entire image.
31 * The Cb and Cr planes are assumed to be downsampled by a factor of 2, to have
32 * dimensions (floor(width / 2), floor(height / 2)).
33 * Each plane is specified by a direct java.nio.ByteBuffer, a pixel-stride, and
34 * a row-stride. So, the sample at coordinate (x, y) can be retrieved from
35 * byteBuffer[x * pixel_stride + y * row_stride].
37 * The pre-compression transformation is applied as follows:
38 * 1. The image is cropped to the rectangle from (cropLeft, cropTop) to
39 * (cropRight - 1, cropBottom - 1). So, a cropping-rectangle of (0, 0) -
40 * (width, height) is a no-op.
41 * 2. The rotation is applied counter-clockwise relative to the coordinate
42 * space of the image, so a CCW rotation will appear CW when the image is
43 * rendered in scanline order. Only rotations which are multiples of
44 * 90-degrees are suppored, so the parameter 'rot90' specifies which multiple
45 * of 90 to rotate the image.
47 * @param env the JNI environment
48 * @param width the width of the image to compress
49 * @param height the height of the image to compress
50 * @param yBuf the buffer containing the Y component of the image
51 * @param yPStride the stride between adjacent pixels in the same row in yBuf
52 * @param yRStride the stride between adjacent rows in yBuf
53 * @param cbBuf the buffer containing the Cb component of the image
54 * @param cbPStride the stride between adjacent pixels in the same row in cbBuf
55 * @param cbRStride the stride between adjacent rows in cbBuf
56 * @param crBuf the buffer containing the Cr component of the image
57 * @param crPStride the stride between adjacent pixels in the same row in crBuf
58 * @param crRStride the stride between adjacent rows in crBuf
59 * @param outBuf a direct java.nio.ByteBuffer to hold the compressed jpeg. This
60 * must have enough capacity to store the result, or an error code will be
62 * @param outBufCapacity the capacity of outBuf
63 * @param quality the jpeg-quality (1-100) to use
64 * @param crop[Left|Top|Right|Bottom] the bounds of the image to crop to before
66 * @param rot90 the multiple of 90 to rotate by
68 extern "C" JNIEXPORT jint JNICALL
69 Java_com_android_camera_util_JpegUtilNative_compressJpegFromYUV420pNative(
70 JNIEnv* env, jclass clazz,
71 /** Input image dimensions */
72 jint width, jint height,
74 jobject yBuf, jint yPStride, jint yRStride,
76 jobject cbBuf, jint cbPStride, jint cbRStride,
78 jobject crBuf, jint crPStride, jint crRStride,
80 jobject outBuf, jint outBufCapacity,
81 /** Jpeg compression parameters */
84 jint cropLeft, jint cropTop, jint cropRight, jint cropBottom,
85 /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree
88 jbyte* y = (jbyte*)env->GetDirectBufferAddress(yBuf);
89 jbyte* cb = (jbyte*)env->GetDirectBufferAddress(cbBuf);
90 jbyte* cr = (jbyte*)env->GetDirectBufferAddress(crBuf);
91 jbyte* out = (jbyte*)env->GetDirectBufferAddress(outBuf);
93 return Compress(width, height, //
94 (unsigned char*)y, yPStride, yRStride, //
95 (unsigned char*)cb, cbPStride, cbRStride, //
96 (unsigned char*)cr, crPStride, crRStride, //
97 (unsigned char*)out, (size_t)outBufCapacity, //
99 cropLeft, cropTop, cropRight, cropBottom, //
104 * Copies the Image.Plane specified by planeBuf, pStride, and rStride to the
107 * @param env the JNI environment
108 * @param clazz the java class
109 * @param width the width of the output image
110 * @param height the height of the output image
111 * @param planeBuf the native ByteBuffer containing the image plane data
112 * @param pStride the stride between adjacent pixels in the same row of
114 * @param rStride the stride between adjacent rows in planeBuf
115 * @param rot90 the multiple of 90 degrees to rotate, one of {0, 1, 2, 3}.
117 extern "C" JNIEXPORT void JNICALL
118 Java_com_android_camera_util_JpegUtilNative_copyImagePlaneToBitmap(
119 JNIEnv* env, jclass clazz, jint width, jint height, jobject planeBuf,
120 jint pStride, jint rStride, jobject outBitmap, jint rot90) {
121 jbyte* src = (jbyte*)env->GetDirectBufferAddress(planeBuf);
124 AndroidBitmap_lockPixels(env, outBitmap, (void**)&dst);
128 for (int y = 0; y < height; y++) {
129 char* srcPtr = reinterpret_cast<char*>(&src[y * rStride]);
130 char* dstPtr = &dst[y * width];
131 for (int x = 0; x < width; x++) {
137 } else if (rot90 == 1) {
138 // 90-degree rotation
139 for (int y = 0; y < height; y++) {
140 for (int x = 0; x < width; x++) {
141 int srcX = height - 1 - y;
143 dst[y * width + x] = src[srcX * pStride + rStride * srcY];
146 } else if (rot90 == 2) {
147 // 180-degree rotation
148 for (int y = 0; y < height; y++) {
149 for (int x = 0; x < width; x++) {
150 int srcX = width - 1 - x;
151 int srcY = height - 1 - y;
152 dst[y * width + x] = src[srcX * pStride + rStride * srcY];
155 } else if (rot90 == 3) {
156 // 270-degree rotation
157 for (int y = 0; y < height; y++) {
158 for (int x = 0; x < width; x++) {
160 int srcY = width - 1 - x;
161 dst[y * width + x] = src[srcX * pStride + rStride * srcY];
166 AndroidBitmap_unlockPixels(env, outBitmap);