1a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk/* 2a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * Copyright (C) 2013 The Android Open Source Project 3a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * 4a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License"); 5a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * you may not use this file except in compliance with the License. 6a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * You may obtain a copy of the License at 7a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * 8a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * http://www.apache.org/licenses/LICENSE-2.0 9a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * 10a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * Unless required by applicable law or agreed to in writing, software 11a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS, 12a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * See the License for the specific language governing permissions and 14a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk * limitations under the License. 15a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk */ 16a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 17a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunkpackage com.android.gallery3d.jpegstream; 18a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 19a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunkimport java.io.FilterOutputStream; 20a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunkimport java.io.IOException; 21a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunkimport java.io.OutputStream; 22a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunkpublic class JPEGOutputStream extends FilterOutputStream { 23a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private long JNIPointer = 0; // Used by JNI code. Don't touch. 24a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 25a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private byte[] mTmpBuffer = new byte[1]; 26a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private int mWidth = 0; 27a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private int mHeight = 0; 28a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private int mQuality = 0; 29a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private int mFormat = -1; 30a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private boolean mValidConfig = false; 31a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk private boolean mConfigChanged = false; 32a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 33a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public JPEGOutputStream(OutputStream out) { 34a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk super(out); 35a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 36a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 37a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public JPEGOutputStream(OutputStream out, int width, int height, int quality, 38a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk int format) { 39a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk super(out); 40a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk setConfig(width, height, quality, format); 41a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 42a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 43a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public boolean setConfig(int width, int height, int quality, int format) { 44a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk // Clamp quality to range (0, 100] 45a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk quality = Math.max(Math.min(quality, 100), 1); 46a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 47a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk // Make sure format is valid 48a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk switch (format) { 49a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.FORMAT_GRAYSCALE: 50a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.FORMAT_RGB: 51a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.FORMAT_ABGR: 52a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.FORMAT_RGBA: 53a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk break; 54a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk default: 55a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk return false; 56a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 57a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 58a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk // If valid, set configuration 59a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (width > 0 && height > 0) { 60a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mWidth = width; 61a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mHeight = height; 62a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mFormat = format; 63a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mQuality = quality; 64a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mValidConfig = true; 65a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mConfigChanged = true; 66a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } else { 67a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk return false; 68a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 69a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 70a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk return mValidConfig; 71a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 72a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 73a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk @Override 74a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public void close() throws IOException { 75a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk cleanup(); 76a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk super.close(); 77a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 78a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 79a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk @Override 80a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public void write(byte[] buffer, int offset, int length) throws IOException { 81a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (offset < 0 || length < 0 || (offset + length) > buffer.length) { 82a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk throw new ArrayIndexOutOfBoundsException(String.format( 83a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk " buffer length %d, offset %d, length %d", 84a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk buffer.length, offset, length)); 85a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 86a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (!mValidConfig) { 87a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk return; 88a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 89a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (mConfigChanged) { 90a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk cleanup(); 91a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk int flag = setup(out, mWidth, mHeight, mFormat, mQuality); 92a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk switch(flag) { 93a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.J_SUCCESS: 94a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk break; // allow setup to continue 95a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk case JpegConfig.J_ERROR_BAD_ARGS: 96a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk throw new IllegalArgumentException("Bad arguments to write"); 97a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk default: 98a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk throw new IOException("Error to writing jpeg headers."); 99a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 100a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mConfigChanged = false; 101a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 102a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk int returnCode = JpegConfig.J_ERROR_FATAL; 103a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk try { 104a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk returnCode = writeInputBytes(buffer, offset, length); 105a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } finally { 106a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (returnCode < 0) { 107a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk cleanup(); 108a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 109a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 110a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk if (returnCode < 0) { 111a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk throw new IOException("Error writing jpeg stream"); 112a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 113a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 114a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 115a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk @Override 116a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public void write(byte[] buffer) throws IOException { 117a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk write(buffer, 0, buffer.length); 118a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 119a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 120a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk @Override 121a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk public void write(int oneByte) throws IOException { 122a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk mTmpBuffer[0] = (byte) oneByte; 123a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk write(mTmpBuffer); 124a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 125a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 126a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk @Override 127a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk protected void finalize() throws Throwable { 128a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk try { 129a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk cleanup(); 130a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } finally { 131a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk super.finalize(); 132a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 133a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 134a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 135a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk native private int setup(OutputStream out, int width, int height, int format, int quality); 136a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 137a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk native private void cleanup(); 138a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 139a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk native private int writeInputBytes(byte[] inBuffer, int offset, int inCount); 140a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk 141a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk static { 142a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk System.loadLibrary("jni_jpegstream"); 143a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk } 144a8221bbdb8ece9b02dbf7b72565f9fbc5b314f7cRuben Brunk} 145