YuvImage.java revision bca2d613e0d6d2630fedd302c0d779b7610adbcf
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package android.graphics; 18 19import java.io.OutputStream; 20 21/** 22 * @hide pending API council approval 23 * 24 * YuvImage contains YUV data and provides a method that compresses a region of 25 * the YUV data to a Jpeg. The YUV data should be provided as a single byte 26 * array irrespective of the number of image planes in it. The stride of each 27 * image plane should be provided as well. 28 * 29 * To compress a rectangle region in the YUV data, users have to specify a 30 * region by width, height and offsets, where each image plane has a 31 * corresponding offset. All offsets are measured as a displacement in bytes 32 * from yuv[0], where yuv[0] is the beginning of the yuv data. 33 */ 34public class YuvImage { 35 36 /** 37 * Number of bytes of temp storage we use for communicating between the 38 * native compressor and the java OutputStream. 39 */ 40 private final static int WORKING_COMPRESS_STORAGE = 4096; 41 42 /** 43 * The YUV format as defined in {@link PixelFormat}. 44 */ 45 private int mFormat; 46 47 /** 48 * The raw YUV data. 49 * In the case of more than one image plane, the image planes must be 50 * concatenated into a single byte array. 51 */ 52 private byte[] mData; 53 54 /** 55 * The number of row bytes in each image plane. 56 */ 57 private int[] mStrides; 58 59 /** 60 * Construct an YuvImage. 61 * 62 * @param yuv The YUV data. In the case of more than one image plane, all the planes must be 63 * concatenated into a single byte array. 64 * @param format The YUV data format as defined in {@link PixelFormat}. 65 * @param strides Row bytes of each image plane. 66 */ 67 public YuvImage(byte[] yuv, int format, int[] strides) { 68 if ((yuv == null) || (strides == null)) { 69 throw new IllegalArgumentException( 70 "yuv or strides cannot be null"); 71 } 72 mData = yuv; 73 mFormat = format; 74 mStrides = strides; 75 } 76 77 /** 78 * Compress a rectangle region in the YuvImage to a jpeg. 79 * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I 80 * are supported for now. 81 * 82 * @param width The width of the rectangle region. 83 * @param height The height of the rectangle region. 84 * @param offsets The offsets of the rectangle region in each image plane. 85 * The offsets are measured as a displacement in bytes from 86 * yuv[0], where yuv[0] is the beginning of the yuv data. 87 * @param quality Hint to the compressor, 0-100. 0 meaning compress for 88 * small size, 100 meaning compress for max quality. 89 * @param stream The outputstream to write the compressed data. 90 * 91 * @return true if successfully compressed to the specified stream. 92 * 93 */ 94 public boolean compressToJpeg(int width, int height, int[] offsets, int quality, 95 OutputStream stream) { 96 if (!validate(mFormat, width, height, offsets)) { 97 return false; 98 } 99 100 if (quality < 0 || quality > 100) { 101 throw new IllegalArgumentException("quality must be 0..100"); 102 } 103 104 if (stream == null) { 105 throw new NullPointerException(); 106 } 107 108 return nativeCompressToJpeg(mData, mFormat, width, height, offsets, 109 mStrides, quality, stream, new byte[WORKING_COMPRESS_STORAGE]); 110 } 111 112 /** 113 * @return the YUV data. 114 */ 115 public byte[] getYuvData() { 116 return mData; 117 } 118 119 /** 120 * @return the YUV format as defined in {@link PixelFormat}. 121 */ 122 public int getYuvFormat() { 123 return mFormat; 124 } 125 126 /** 127 * @return the number of row bytes in each image plane. 128 */ 129 public int[] getStrides() { 130 return mStrides; 131 } 132 133 protected boolean validate(int format, int width, int height, int[] offsets) { 134 if (format != PixelFormat.YCbCr_420_SP && 135 format != PixelFormat.YCbCr_422_I) { 136 throw new IllegalArgumentException( 137 "only support PixelFormat.YCbCr_420_SP " + 138 "and PixelFormat.YCbCr_422_I for now"); 139 } 140 141 if (offsets.length != mStrides.length) { 142 throw new IllegalArgumentException( 143 "the number of image planes are mismatched"); 144 } 145 146 if (width <= 0 || height <= 0) { 147 throw new IllegalArgumentException( 148 "width and height must large than 0"); 149 } 150 151 int requiredSize; 152 if (format == PixelFormat.YCbCr_420_SP) { 153 requiredSize = height * mStrides[0] +(height >> 1) * mStrides[1]; 154 } else { 155 requiredSize = height * mStrides[0]; 156 } 157 158 if (requiredSize > mData.length) { 159 throw new IllegalArgumentException( 160 "width or/and height is larger than the yuv data"); 161 } 162 163 return true; 164 } 165 166 //////////// native methods 167 168 private static native boolean nativeCompressToJpeg(byte[] oriYuv, 169 int format, int width, int height, int[] offsets, int[] strides, 170 int quality, OutputStream stream, byte[] tempStorage); 171} 172