/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.gallery3d.jpegstream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; public class JPEGOutputStream extends FilterOutputStream { private long JNIPointer = 0; // Used by JNI code. Don't touch. private byte[] mTmpBuffer = new byte[1]; private int mWidth = 0; private int mHeight = 0; private int mQuality = 0; private int mFormat = -1; private boolean mValidConfig = false; private boolean mConfigChanged = false; public JPEGOutputStream(OutputStream out) { super(out); } public JPEGOutputStream(OutputStream out, int width, int height, int quality, int format) { super(out); setConfig(width, height, quality, format); } public boolean setConfig(int width, int height, int quality, int format) { // Clamp quality to range (0, 100] quality = Math.max(Math.min(quality, 100), 1); // Make sure format is valid switch (format) { case JpegConfig.FORMAT_GRAYSCALE: case JpegConfig.FORMAT_RGB: case JpegConfig.FORMAT_ABGR: case JpegConfig.FORMAT_RGBA: break; default: return false; } // If valid, set configuration if (width > 0 && height > 0) { mWidth = width; mHeight = height; mFormat = format; mQuality = quality; mValidConfig = true; mConfigChanged = true; } else { return false; } return mValidConfig; } @Override public void close() throws IOException { cleanup(); super.close(); } @Override public void write(byte[] buffer, int offset, int length) throws IOException { if (offset < 0 || length < 0 || (offset + length) > buffer.length) { throw new ArrayIndexOutOfBoundsException(String.format( " buffer length %d, offset %d, length %d", buffer.length, offset, length)); } if (!mValidConfig) { return; } if (mConfigChanged) { cleanup(); int flag = setup(out, mWidth, mHeight, mFormat, mQuality); switch(flag) { case JpegConfig.J_SUCCESS: break; // allow setup to continue case JpegConfig.J_ERROR_BAD_ARGS: throw new IllegalArgumentException("Bad arguments to write"); default: throw new IOException("Error to writing jpeg headers."); } mConfigChanged = false; } int returnCode = JpegConfig.J_ERROR_FATAL; try { returnCode = writeInputBytes(buffer, offset, length); } finally { if (returnCode < 0) { cleanup(); } } if (returnCode < 0) { throw new IOException("Error writing jpeg stream"); } } @Override public void write(byte[] buffer) throws IOException { write(buffer, 0, buffer.length); } @Override public void write(int oneByte) throws IOException { mTmpBuffer[0] = (byte) oneByte; write(mTmpBuffer); } @Override protected void finalize() throws Throwable { try { cleanup(); } finally { super.finalize(); } } native private int setup(OutputStream out, int width, int height, int format, int quality); native private void cleanup(); native private int writeInputBytes(byte[] inBuffer, int offset, int inCount); static { System.loadLibrary("jni_jpegstream"); } }