Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2012 CyberAgent
*
* 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 jp.co.cyberagent.android.gpuimage;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.*;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.IntBuffer;
import java.util.concurrent.Semaphore;
public class GPUImageView extends FrameLayout {
private GLSurfaceView mGLSurfaceView;
private GPUImage mGPUImage;
private GPUImageFilter mFilter;
public Size mForceSize = null;
private float mRatio = 0.0f;
public GPUImageView(Context context) {
super(context);
init(context, null);
}
public GPUImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mGLSurfaceView = new GPUImageGLSurfaceView(context, attrs);
addView(mGLSurfaceView);
mGPUImage = new GPUImage(getContext());
mGPUImage.setGLSurfaceView(mGLSurfaceView);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mRatio != 0.0f) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int newHeight;
int newWidth;
if (width / mRatio < height) {
newWidth = width;
newHeight = Math.round(width / mRatio);
} else {
newHeight = height;
newWidth = Math.round(height * mRatio);
}
int newWidthSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
int newHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
super.onMeasure(newWidthSpec, newHeightSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
/**
* Retrieve the GPUImage instance used by this view.
*
* @return used GPUImage instance
*/
public GPUImage getGPUImage() {
return mGPUImage;
}
// TODO Should be an xml attribute. But then GPUImage can not be distributed as .jar anymore.
public void setRatio(float ratio) {
mRatio = ratio;
mGLSurfaceView.requestLayout();
mGPUImage.deleteImage();
}
/**
* Set the scale type of GPUImage.
*
* @param scaleType the new ScaleType
*/
public void setScaleType(GPUImage.ScaleType scaleType) {
mGPUImage.setScaleType(scaleType);
}
/**
* Sets the rotation of the displayed image.
*
* @param rotation new rotation
*/
public void setRotation(Rotation rotation) {
mGPUImage.setRotation(rotation);
requestRender();
}
/**
* Set the filter to be applied on the image.
*
* @param filter Filter that should be applied on the image.
*/
public void setFilter(GPUImageFilter filter) {
mFilter = filter;
mGPUImage.setFilter(filter);
requestRender();
}
/**
* Get the current applied filter.
*
* @return the current filter
*/
public GPUImageFilter getFilter() {
return mFilter;
}
/**
* Sets the image on which the filter should be applied.
*
* @param bitmap the new image
*/
public void setImage(final Bitmap bitmap) {
mGPUImage.setImage(bitmap);
}
/**
* Sets the image on which the filter should be applied from a Uri.
*
* @param uri the uri of the new image
*/
public void setImage(final Uri uri) {
mGPUImage.setImage(uri);
}
/**
* Sets the image on which the filter should be applied from a File.
*
* @param file the file of the new image
*/
public void setImage(final File file) {
mGPUImage.setImage(file);
}
public void requestRender() {
mGLSurfaceView.requestRender();
}
/**
* Save current image with applied filter to Pictures. It will be stored on
* the default Picture folder on the phone below the given folderName and
* fileName.
* This method is async and will notify when the image was saved through the
* listener.
*
* @param folderName the folder name
* @param fileName the file name
* @param listener the listener
*/
public void saveToPictures(final String folderName, final String fileName,
final OnPictureSavedListener listener) {
new SaveTask(folderName, fileName, listener).execute();
}
/**
* Save current image with applied filter to Pictures. It will be stored on
* the default Picture folder on the phone below the given folderName and
* fileName.
* This method is async and will notify when the image was saved through the
* listener.
*
* @param folderName the folder name
* @param fileName the file name
* @param width requested output width
* @param height requested output height
* @param listener the listener
*/
public void saveToPictures(final String folderName, final String fileName,
int width, int height,
final OnPictureSavedListener listener) {
new SaveTask(folderName, fileName, width, height, listener).execute();
}
/**
* Retrieve current image with filter applied and given size as Bitmap.
*
* @param width requested Bitmap width
* @param height requested Bitmap height
* @return Bitmap of picture with given size
* @throws InterruptedException
*/
public Bitmap capture(final int width, final int height) throws InterruptedException {
// This method needs to run on a background thread because it will take a longer time
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new IllegalStateException("Do not call this method from the UI thread!");
}
mForceSize = new Size(width, height);
final Semaphore waiter = new Semaphore(0);
// Layout with new size
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
waiter.release();
}
});
post(new Runnable() {
@Override
public void run() {
// Show loading
addView(new LoadingView(getContext()));
mGLSurfaceView.requestLayout();
}
});
waiter.acquire();
// Run one render pass
mGPUImage.runOnGLThread(new Runnable() {
@Override
public void run() {
waiter.release();
}
});
requestRender();
waiter.acquire();
Bitmap bitmap = capture();
mForceSize = null;
post(new Runnable() {
@Override
public void run() {
mGLSurfaceView.requestLayout();
}
});
requestRender();
postDelayed(new Runnable() {
@Override
public void run() {
// Remove loading view
removeViewAt(1);
}
}, 300);
return bitmap;
}
/**
* Capture the current image with the size as it is displayed and retrieve it as Bitmap.
* @return current output as Bitmap
* @throws InterruptedException
*/
public Bitmap capture() throws InterruptedException {
final Semaphore waiter = new Semaphore(0);
final int width = mGLSurfaceView.getMeasuredWidth();
final int height = mGLSurfaceView.getMeasuredHeight();
// Take picture on OpenGL thread
final int[] pixelMirroredArray = new int[width * height];
mGPUImage.runOnGLThread(new Runnable() {
@Override
public void run() {
final IntBuffer pixelBuffer = IntBuffer.allocate(width * height);
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
int[] pixelArray = pixelBuffer.array();
// Convert upside down mirror-reversed image to right-side up normal image.
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixelMirroredArray[(height - i - 1) * width + j] = pixelArray[i * width + j];
}
}
waiter.release();
}
});
requestRender();
waiter.acquire();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixelMirroredArray));
return bitmap;
}
/**
* Pauses the GLSurfaceView.
*/
public void onPause() {
mGLSurfaceView.onPause();
}
/**
* Resumes the GLSurfaceView.
*/
public void onResume() {
mGLSurfaceView.onResume();
}
public static class Size {
int width;
int height;
public Size(int width, int height) {
this.width = width;
this.height = height;
}
}
private class GPUImageGLSurfaceView extends GLSurfaceView {
public GPUImageGLSurfaceView(Context context) {
super(context);
}
public GPUImageGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mForceSize != null) {
super.onMeasure(MeasureSpec.makeMeasureSpec(mForceSize.width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mForceSize.height, MeasureSpec.EXACTLY));
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
private class LoadingView extends FrameLayout {
public LoadingView(Context context) {
super(context);
init();
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LoadingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
ProgressBar view = new ProgressBar(getContext());
view.setLayoutParams(
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
addView(view);
setBackgroundColor(Color.BLACK);
}
}
private class SaveTask extends AsyncTask {
private final String mFolderName;
private final String mFileName;
private final int mWidth;
private final int mHeight;
private final OnPictureSavedListener mListener;
private final Handler mHandler;
public SaveTask(final String folderName, final String fileName,
final OnPictureSavedListener listener) {
this(folderName, fileName, 0, 0, listener);
}
public SaveTask(final String folderName, final String fileName, int width, int height,
final OnPictureSavedListener listener) {
mFolderName = folderName;
mFileName = fileName;
mWidth = width;
mHeight = height;
mListener = listener;
mHandler = new Handler();
}
@Override
protected Void doInBackground(final Void... params) {
try {
Bitmap result = mWidth != 0 ? capture(mWidth, mHeight) : capture();
saveImage(mFolderName, mFileName, result);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
private void saveImage(final String folderName, final String fileName, final Bitmap image) {
File path = Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File file = new File(path, folderName + "/" + fileName);
try {
file.getParentFile().mkdirs();
image.compress(Bitmap.CompressFormat.JPEG, 80, new FileOutputStream(file));
MediaScannerConnection.scanFile(getContext(),
new String[]{
file.toString()
}, null,
new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(final String path, final Uri uri) {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onPictureSaved(uri);
}
});
}
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
public interface OnPictureSavedListener {
void onPictureSaved(Uri uri);
}
}