Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1c32b51

Browse files
author
Patrick Boos
committed
- Added sample code on how to take a picture with filter applied (needs to be refactored into GPUImage)
- Several bugfixes that showed up in camera capture
1 parent c8f08cc commit 1c32b51

File tree

5 files changed

+176
-26
lines changed

5 files changed

+176
-26
lines changed

library/src/jp/cyberagent/android/gpuimage/GPUImage.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.io.FileNotFoundException;
66
import java.io.FileOutputStream;
77
import java.io.IOException;
8+
import java.util.concurrent.Semaphore;
89

910
import jp.cyberagent.android.gpuimage.GPUImageRenderer.Rotation;
1011
import android.annotation.TargetApi;
@@ -16,7 +17,6 @@
1617
import android.graphics.Bitmap.CompressFormat;
1718
import android.graphics.BitmapFactory;
1819
import android.graphics.Matrix;
19-
import android.graphics.SurfaceTexture;
2020
import android.hardware.Camera;
2121
import android.media.ExifInterface;
2222
import android.media.MediaScannerConnection;
@@ -81,17 +81,13 @@ public void setUpCamera(final Camera camera) {
8181

8282
@TargetApi(11)
8383
private void setUpCameraGingerbread(final Camera camera) {
84-
try {
85-
mRenderer.setUpSurfaceTexture(camera);
86-
camera.setPreviewTexture(new SurfaceTexture(0));
87-
} catch (IOException e) {
88-
e.printStackTrace();
89-
}
84+
mRenderer.setUpSurfaceTexture(camera);
9085
}
9186

9287
public void setFilter(final GPUImageFilter filter) {
9388
mFilter = filter;
9489
mRenderer.setFilter(mFilter);
90+
requestRender();
9591
}
9692

9793
public void setImage(final Bitmap bitmap) {
@@ -123,48 +119,64 @@ private String getPath(final Uri uri) {
123119
return path;
124120
}
125121

126-
public Bitmap getBitmapWithFilterApplied() {
122+
public Bitmap getBitmapWithFilterApplied(final Bitmap bitmap) {
127123
mRenderer.deleteImage();
124+
final Semaphore lock = new Semaphore(0);
128125
mRenderer.runOnDraw(new Runnable() {
129126

130127
@Override
131128
public void run() {
132129
mFilter.onDestroy();
130+
lock.release();
133131
}
134132
});
135133
requestRender();
136134

135+
try {
136+
lock.acquire();
137+
} catch (InterruptedException e) {
138+
e.printStackTrace();
139+
}
140+
137141
GPUImageRenderer renderer = new GPUImageRenderer(mFilter);
138-
PixelBuffer buffer = new PixelBuffer(mCurrentBitmap.getWidth(),
139-
mCurrentBitmap.getHeight());
142+
PixelBuffer buffer = new PixelBuffer(bitmap.getWidth(), bitmap.getHeight());
140143
buffer.setRenderer(renderer);
141-
renderer.setImageBitmap(mCurrentBitmap, false);
144+
renderer.setImageBitmap(bitmap, false);
142145
Bitmap result = buffer.getBitmap();
143146
mFilter.onDestroy();
144147
renderer.deleteImage();
145148
buffer.destroy();
146149

147150
mRenderer.setFilter(mFilter);
148-
mRenderer.setImageBitmap(mCurrentBitmap, false);
151+
if (mCurrentBitmap != null) {
152+
mRenderer.setImageBitmap(mCurrentBitmap, false);
153+
}
149154
requestRender();
150155

151156
return result;
152157
}
153158

154159
public void saveToPictures(final String folderName, final String fileName,
155160
final OnPictureSavedListener listener) {
156-
new SaveTask(folderName, fileName, listener).execute();
161+
saveToPictures(mCurrentBitmap, folderName, fileName, listener);
162+
}
163+
164+
public void saveToPictures(final Bitmap bitmap, final String folderName, final String fileName,
165+
final OnPictureSavedListener listener) {
166+
new SaveTask(bitmap, folderName, fileName, listener).execute();
157167
}
158168

159169
private class SaveTask extends AsyncTask<Void, Void, Void> {
160170

171+
private final Bitmap mBitmap;
161172
private final String mFolderName;
162173
private final String mFileName;
163174
private final OnPictureSavedListener mListener;
164175
private final Handler mHandler;
165176

166-
public SaveTask(final String folderName, final String fileName,
177+
public SaveTask(final Bitmap bitmap, final String folderName, final String fileName,
167178
final OnPictureSavedListener listener) {
179+
mBitmap = bitmap;
168180
mFolderName = folderName;
169181
mFileName = fileName;
170182
mListener = listener;
@@ -173,7 +185,7 @@ public SaveTask(final String folderName, final String fileName,
173185

174186
@Override
175187
protected Void doInBackground(final Void... params) {
176-
Bitmap result = getBitmapWithFilterApplied();
188+
Bitmap result = getBitmapWithFilterApplied(mBitmap);
177189
saveImage(mFolderName, mFileName, result);
178190
return null;
179191
}

library/src/jp/cyberagent/android/gpuimage/GPUImageFilter.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.nio.FloatBuffer;
55
import java.nio.ShortBuffer;
66
import java.util.LinkedList;
7-
import java.util.Queue;
87

98
import android.opengl.GLES20;
109

@@ -30,7 +29,7 @@ public class GPUImageFilter {
3029
" gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\n" +
3130
"}";
3231

33-
private final Queue<Runnable> mRunOnDraw;
32+
private final LinkedList<Runnable> mRunOnDraw;
3433
private final String mVertexShader;
3534
private final String mFragmentShader;
3635
private int mGLProgId;
@@ -39,6 +38,7 @@ public class GPUImageFilter {
3938
private int mGLAttribTextureCoordinate;
4039
private int mOutputWidth;
4140
private int mOutputHeight;
41+
private boolean mIsInitialized;
4242

4343
public GPUImageFilter() {
4444
this(NO_FILTER_VERTEX_SHADER, NO_FILTER_FRAGMENT_SHADER);
@@ -56,10 +56,12 @@ public void onInit() {
5656
mGLUniformTexture = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture");
5757
mGLAttribTextureCoordinate = GLES20.glGetAttribLocation(mGLProgId,
5858
"inputTextureCoordinate");
59+
mIsInitialized = true;
5960
}
6061

6162
public void onDestroy() {
6263
GLES20.glDeleteProgram(mGLProgId);
64+
mIsInitialized = false;
6365
}
6466

6567
public void onOutputSizeChanged(final int width, final int height) {
@@ -70,8 +72,9 @@ public void onOutputSizeChanged(final int width, final int height) {
7072
public void onDraw(final int textureId, final FloatBuffer cubeBuffer,
7173
final FloatBuffer textureBuffer, final ShortBuffer indexBuffer) {
7274
GLES20.glUseProgram(mGLProgId);
73-
while (!mRunOnDraw.isEmpty()) {
74-
mRunOnDraw.poll().run();
75+
runPendingOnDrawTasks();
76+
if (!mIsInitialized) {
77+
return;
7578
}
7679

7780
cubeBuffer.position(0);
@@ -92,6 +95,16 @@ public void onDraw(final int textureId, final FloatBuffer cubeBuffer,
9295
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
9396
}
9497

98+
protected void runPendingOnDrawTasks() {
99+
while (!mRunOnDraw.isEmpty()) {
100+
mRunOnDraw.removeFirst().run();
101+
}
102+
}
103+
104+
public boolean isInitialized() {
105+
return mIsInitialized;
106+
}
107+
95108
public int getOutputWidth() {
96109
return mOutputWidth;
97110
}
@@ -148,7 +161,7 @@ public void run() {
148161

149162
protected void runOnDraw(final Runnable runnable) {
150163
synchronized (mRunOnDraw) {
151-
mRunOnDraw.add(runnable);
164+
mRunOnDraw.addLast(runnable);
152165
}
153166
}
154167
}

library/src/jp/cyberagent/android/gpuimage/GPUImageFilterGroup.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ public void onOutputSizeChanged(final int width, final int height) {
121121
@Override
122122
public void onDraw(final int textureId, final FloatBuffer cubeBuffer,
123123
final FloatBuffer textureBuffer, final ShortBuffer indexBuffer) {
124-
if (mFrameBuffers == null || mFrameBufferTextures == null) {
124+
runPendingOnDrawTasks();
125+
if (!isInitialized() || mFrameBuffers == null || mFrameBufferTextures == null) {
125126
return;
126127
}
127128
int previousTexture = textureId;

sample/res/layout/activity_camera.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
android:layout_width="wrap_content"
2929
android:layout_height="wrap_content"
3030
android:text="Choose Filter" />
31+
32+
<ImageButton
33+
android:id="@+id/button_capture"
34+
android:layout_width="wrap_content"
35+
android:layout_height="wrap_content"
36+
android:src="@android:drawable/ic_menu_camera" />
3137
</LinearLayout>
3238

3339
</LinearLayout>

sample/src/jp/cyberagent/android/gpuimage/sample/activity/ActivityCamera.java

Lines changed: 123 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11

22
package jp.cyberagent.android.gpuimage.sample.activity;
33

4+
import java.io.File;
5+
import java.io.FileNotFoundException;
6+
import java.io.FileOutputStream;
7+
import java.io.IOException;
8+
import java.text.SimpleDateFormat;
9+
import java.util.Date;
10+
411
import jp.cyberagent.android.gpuimage.GPUImage;
12+
import jp.cyberagent.android.gpuimage.GPUImage.OnPictureSavedListener;
513
import jp.cyberagent.android.gpuimage.GPUImageFilter;
614
import jp.cyberagent.android.gpuimage.sample.GPUImageFilterTools;
715
import jp.cyberagent.android.gpuimage.sample.GPUImageFilterTools.FilterAdjuster;
816
import jp.cyberagent.android.gpuimage.sample.GPUImageFilterTools.OnGpuImageFilterChosenListener;
917
import jp.cyberagent.android.gpuimage.sample.R;
1018
import android.app.Activity;
19+
import android.graphics.Bitmap;
20+
import android.graphics.BitmapFactory;
1121
import android.hardware.Camera;
1222
import android.hardware.Camera.Parameters;
23+
import android.net.Uri;
1324
import android.opengl.GLSurfaceView;
1425
import android.os.Bundle;
26+
import android.os.Environment;
27+
import android.util.Log;
1528
import android.view.View;
1629
import android.view.View.OnClickListener;
1730
import android.widget.SeekBar;
@@ -31,6 +44,7 @@ public void onCreate(final Bundle savedInstanceState) {
3144
setContentView(R.layout.activity_camera);
3245
((SeekBar) findViewById(R.id.seekBar)).setOnSeekBarChangeListener(this);
3346
findViewById(R.id.button_choose_filter).setOnClickListener(this);
47+
findViewById(R.id.button_capture).setOnClickListener(this);
3448

3549
mGPUImage = new GPUImage(this);
3650
mGPUImage.setGLSurfaceView((GLSurfaceView) findViewById(R.id.surfaceView));
@@ -52,13 +66,116 @@ protected void onPause() {
5266

5367
@Override
5468
public void onClick(final View v) {
55-
GPUImageFilterTools.showDialog(this, new OnGpuImageFilterChosenListener() {
69+
switch (v.getId()) {
70+
case R.id.button_choose_filter:
71+
GPUImageFilterTools.showDialog(this, new OnGpuImageFilterChosenListener() {
72+
73+
@Override
74+
public void onGpuImageFilterChosenListener(final GPUImageFilter filter) {
75+
switchFilterTo(filter);
76+
}
77+
});
78+
break;
79+
80+
case R.id.button_capture:
81+
Camera.Size size = mCamera.mCameraInstance.getParameters().getPictureSize();
82+
Log.i("ASDF", size.width + "x" + size.height);
83+
// TODO get a size that is about the size of the screen
84+
Camera.Parameters params = mCamera.mCameraInstance.getParameters();
85+
params.setPictureSize(1280, 960);
86+
params.setRotation(90);
87+
mCamera.mCameraInstance.setParameters(params);
88+
for (Camera.Size size2 : mCamera.mCameraInstance.getParameters()
89+
.getSupportedPictureSizes()) {
90+
Log.i("ASDF", "Supported: " + size2.width + "x" + size2.height);
91+
}
92+
mCamera.mCameraInstance.autoFocus(new Camera.AutoFocusCallback() {
93+
94+
@Override
95+
public void onAutoFocus(final boolean success, final Camera camera) {
96+
mCamera.mCameraInstance.takePicture(null, null,
97+
new Camera.PictureCallback() {
98+
99+
@Override
100+
public void onPictureTaken(byte[] data, final Camera camera) {
101+
102+
final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
103+
if (pictureFile == null) {
104+
Log.d("ASDF",
105+
"Error creating media file, check storage permissions");
106+
return;
107+
}
108+
109+
try {
110+
FileOutputStream fos = new FileOutputStream(pictureFile);
111+
fos.write(data);
112+
fos.close();
113+
} catch (FileNotFoundException e) {
114+
Log.d("ASDF", "File not found: " + e.getMessage());
115+
} catch (IOException e) {
116+
Log.d("ASDF", "Error accessing file: " + e.getMessage());
117+
}
118+
119+
data = null;
120+
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile
121+
.getAbsolutePath());
122+
// mGPUImage.setImage(bitmap);
123+
final GLSurfaceView view = (GLSurfaceView) findViewById(R.id.surfaceView);
124+
view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
125+
mGPUImage.saveToPictures(bitmap, "GPUImage",
126+
System.currentTimeMillis() + ".jpg",
127+
new OnPictureSavedListener() {
128+
129+
@Override
130+
public void onPictureSaved(final Uri
131+
uri) {
132+
pictureFile.delete();
133+
camera.startPreview();
134+
view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
135+
}
136+
});
137+
}
138+
});
139+
}
140+
});
141+
break;
142+
}
143+
}
144+
145+
public static final int MEDIA_TYPE_IMAGE = 1;
146+
public static final int MEDIA_TYPE_VIDEO = 2;
147+
148+
private static File getOutputMediaFile(final int type) {
149+
// To be safe, you should check that the SDCard is mounted
150+
// using Environment.getExternalStorageState() before doing this.
56151

57-
@Override
58-
public void onGpuImageFilterChosenListener(final GPUImageFilter filter) {
59-
switchFilterTo(filter);
152+
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
153+
Environment.DIRECTORY_PICTURES), "MyCameraApp");
154+
// This location works best if you want the created images to be shared
155+
// between applications and persist after your app has been uninstalled.
156+
157+
// Create the storage directory if it does not exist
158+
if (!mediaStorageDir.exists()) {
159+
if (!mediaStorageDir.mkdirs()) {
160+
Log.d("MyCameraApp", "failed to create directory");
161+
return null;
60162
}
61-
});
163+
}
164+
165+
// Create a media file name
166+
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
167+
File mediaFile;
168+
if (type == MEDIA_TYPE_IMAGE) {
169+
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
170+
"IMG_" + timeStamp + ".jpg");
171+
} else if (type == MEDIA_TYPE_VIDEO) {
172+
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
173+
"VID_" + timeStamp + ".mp4");
174+
} else {
175+
return null;
176+
}
177+
178+
return mediaFile;
62179
}
63180

64181
private void switchFilterTo(final GPUImageFilter filter) {
@@ -94,6 +211,7 @@ public void onResume() {
94211
// TODO adjust by getting supportedPreviewSizes and then choosing
95212
// the best one for screen size (best fill screen)
96213
parameters.setPreviewSize(720, 480);
214+
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
97215
mCameraInstance.setParameters(parameters);
98216

99217
mGPUImage.setUpCamera(mCameraInstance);

0 commit comments

Comments
 (0)