1 /* 2 * Copyright (C) 2013 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 17 package com.android.gallery3d.jpegstream; 18 19 import java.io.FilterOutputStream; 20 import java.io.IOException; 21 import java.io.OutputStream; 22 public class JPEGOutputStream extends FilterOutputStream { 23 private long JNIPointer = 0; // Used by JNI code. Don't touch. 24 25 private byte[] mTmpBuffer = new byte[1]; 26 private int mWidth = 0; 27 private int mHeight = 0; 28 private int mQuality = 0; 29 private int mFormat = -1; 30 private boolean mValidConfig = false; 31 private boolean mConfigChanged = false; 32 JPEGOutputStream(OutputStream out)33 public JPEGOutputStream(OutputStream out) { 34 super(out); 35 } 36 JPEGOutputStream(OutputStream out, int width, int height, int quality, int format)37 public JPEGOutputStream(OutputStream out, int width, int height, int quality, 38 int format) { 39 super(out); 40 setConfig(width, height, quality, format); 41 } 42 setConfig(int width, int height, int quality, int format)43 public boolean setConfig(int width, int height, int quality, int format) { 44 // Clamp quality to range (0, 100] 45 quality = Math.max(Math.min(quality, 100), 1); 46 47 // Make sure format is valid 48 switch (format) { 49 case JpegConfig.FORMAT_GRAYSCALE: 50 case JpegConfig.FORMAT_RGB: 51 case JpegConfig.FORMAT_ABGR: 52 case JpegConfig.FORMAT_RGBA: 53 break; 54 default: 55 return false; 56 } 57 58 // If valid, set configuration 59 if (width > 0 && height > 0) { 60 mWidth = width; 61 mHeight = height; 62 mFormat = format; 63 mQuality = quality; 64 mValidConfig = true; 65 mConfigChanged = true; 66 } else { 67 return false; 68 } 69 70 return mValidConfig; 71 } 72 73 @Override close()74 public void close() throws IOException { 75 cleanup(); 76 super.close(); 77 } 78 79 @Override write(byte[] buffer, int offset, int length)80 public void write(byte[] buffer, int offset, int length) throws IOException { 81 if (offset < 0 || length < 0 || (offset + length) > buffer.length) { 82 throw new ArrayIndexOutOfBoundsException(String.format( 83 " buffer length %d, offset %d, length %d", 84 buffer.length, offset, length)); 85 } 86 if (!mValidConfig) { 87 return; 88 } 89 if (mConfigChanged) { 90 cleanup(); 91 int flag = setup(out, mWidth, mHeight, mFormat, mQuality); 92 switch(flag) { 93 case JpegConfig.J_SUCCESS: 94 break; // allow setup to continue 95 case JpegConfig.J_ERROR_BAD_ARGS: 96 throw new IllegalArgumentException("Bad arguments to write"); 97 default: 98 throw new IOException("Error to writing jpeg headers."); 99 } 100 mConfigChanged = false; 101 } 102 int returnCode = JpegConfig.J_ERROR_FATAL; 103 try { 104 returnCode = writeInputBytes(buffer, offset, length); 105 } finally { 106 if (returnCode < 0) { 107 cleanup(); 108 } 109 } 110 if (returnCode < 0) { 111 throw new IOException("Error writing jpeg stream"); 112 } 113 } 114 115 @Override write(byte[] buffer)116 public void write(byte[] buffer) throws IOException { 117 write(buffer, 0, buffer.length); 118 } 119 120 @Override write(int oneByte)121 public void write(int oneByte) throws IOException { 122 mTmpBuffer[0] = (byte) oneByte; 123 write(mTmpBuffer); 124 } 125 126 @Override finalize()127 protected void finalize() throws Throwable { 128 try { 129 cleanup(); 130 } finally { 131 super.finalize(); 132 } 133 } 134 setup(OutputStream out, int width, int height, int format, int quality)135 native private int setup(OutputStream out, int width, int height, int format, int quality); 136 cleanup()137 native private void cleanup(); 138 writeInputBytes(byte[] inBuffer, int offset, int inCount)139 native private int writeInputBytes(byte[] inBuffer, int offset, int inCount); 140 141 static { 142 System.loadLibrary("jni_jpegstream"); 143 } 144 } 145