Skip to content

Instantly share code, notes, and snippets.

@vvakame
Created September 1, 2010 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vvakame/560780 to your computer and use it in GitHub Desktop.
Save vvakame/560780 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.vvakame.polkodotter" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:name=".MyApplication" android:debuggable="true">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".DotActivity" android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:configChanges="keyboardHidden|orientation">
</activity>
</application>
<uses-permission android:name="android.permission.CAMERA" />
</manifest>
package net.vvakame.polkodotter;
import java.io.InputStream;
import roboguice.inject.InjectExtra;
import android.app.Activity;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.DisplayMetrics;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class BitmapFromUriExtraProvider implements Provider<Bitmap> {
@Inject
protected Activity act;
@InjectExtra("mediaImageUri")
protected Uri mediaUri;
@Override
public Bitmap get() {
ContentResolver resolver = act.getContentResolver();
Bitmap bitmap = null;
if (mediaUri != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream is = resolver.openInputStream(mediaUri);
BitmapFactory.decodeStream(is, null, options);
DisplayMetrics metrics = new DisplayMetrics();
act.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// 端末にあわせるため、幅が広い方を高さ、狭い方を幅とする。後の事は渡した先でやってくれ
final int width;
final int height;
if (options.outWidth < options.outHeight) {
width = options.outWidth;
height = options.outHeight;
} else {
width = options.outHeight;
height = options.outWidth;
}
if (metrics.widthPixels * 2 < width
|| metrics.heightPixels * 2 < height) {
// 端末解像度 〜 端末解像度 * 2 の範囲に収まるサイズにする
int scaleW = width / metrics.widthPixels;
int scaleH = height / metrics.heightPixels;
options.inSampleSize = Math.max(scaleW, scaleH);
}
is = resolver.openInputStream(mediaUri);
options.inJustDecodeBounds = false;
// NativeHeapから確保
// https://twitter.com/shoozhoo/statuses/22621375376
BitmapFactory.Options.class.getField("inNativeAlloc")
.setBoolean(options, true);
bitmap = BitmapFactory.decodeStream(is, null, options);
} catch (Exception e) {
e.printStackTrace();
}
}
return bitmap;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frame" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:gravity="center_vertical|center_horizontal">
<ImageView android:id="@+id/baseImage" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
package net.vvakame.polkodotter;
import java.util.ArrayList;
import java.util.List;
import roboguice.activity.GuiceActivity;
import roboguice.inject.InjectView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.media.FaceDetector;
import android.media.FaceDetector.Face;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.google.inject.Inject;
public class DotActivity extends GuiceActivity {
@SuppressWarnings("unused")
private final Activity self = this;
private List<CircleF> circleList = new ArrayList<CircleF>();
private boolean first = true;
// Powered by BitmapFromUriExtraProvider
@Inject
private Bitmap mBGBitmap;
private Bitmap mBGThumb;
private Bitmap mClipBitmap;
private Canvas mCanvas;
private Paint mPaint;
@InjectView(R.id.frame)
LinearLayout mFrame;
@InjectView(R.id.baseImage)
ImageView mBaseImage;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dot); // Injection now!!
mBaseImage.setBackgroundDrawable(new BitmapDrawable(mBGBitmap));
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!first) {
return;
}
final int height;
final int width;
if (mFrame.getWidth() < mBGBitmap.getWidth()
&& mFrame.getHeight() < mBGBitmap.getHeight()) {
width = mFrame.getWidth();
height = mFrame.getHeight();
mBGThumb = Bitmap
.createScaledBitmap(mBGBitmap, width, height, true);
} else {
width = mBGBitmap.getWidth();
height = mBGBitmap.getHeight();
mBGThumb = mBGBitmap;
}
Face[] faces = new Face[1];
FaceDetector detector = new FaceDetector(width, height, faces.length);
int num = detector.findFaces(mBGThumb, faces);
for (int i = 0; i < num; i++) {
Face face = faces[i];
PointF point = new PointF();
face.getMidPoint(point);
float eyesDistance = face.eyesDistance();
// 美人顔の人の比率 目と目の間の長さ = 鼻の幅, 鼻の幅 * 4 = 顔の横幅
// 顔の横幅 * 1.5 = 顔の高さ ↓でもこのMagicNumberは適当に決めた
circleList.add(new CircleF(point.x, point.y,
(float) (eyesDistance * 1.7)));
}
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
// Clip
mClipBitmap = Bitmap.createBitmap(width, height, c);
mCanvas = new Canvas();
mCanvas.setBitmap(mClipBitmap);
mPaint = new Paint();
mPaint.setColor(Color.argb(255, 255, 255, 255));
mPaint.setAntiAlias(true);
for (CircleF circle : circleList) {
mCanvas.drawCircle(circle.cx, circle.cy, circle.radius, mPaint);
}
// 前景の作成
final int color = Color.argb(0, 120, 255, 255);
int[] pixels = new int[width * height];
mClipBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
final int length = pixels.length;
for (int i = 0; i < length; i++) {
// ^ 0xff000000 Alphaの反転
// & 0xff000000 Alpha以外の切り捨て
// | color Alpha以外の値の設定
pixels[i] = pixels[i] ^ 0xff000000 & 0xff000000 | color;
}
mClipBitmap.setPixels(pixels, 0, width, 0, 0, width, height);
mBaseImage.setImageBitmap(mClipBitmap);
first = false;
}
class CircleF {
float cx;
float cy;
float radius;
public CircleF(float cx, float cy, float radius) {
this.cx = cx;
this.cy = cy;
this.radius = radius;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:gravity="center_vertical|center_horizontal">
<ImageButton android:id="@+id/gallery" android:src="@android:drawable/ic_menu_gallery"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
package net.vvakame.polkodotter;
import roboguice.activity.GuiceActivity;
import roboguice.inject.InjectView;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
public class MainActivity extends GuiceActivity {
@SuppressWarnings("unused")
private final Activity self = this;
private final int REQUEST_PICK_CONTACT = 0;
@InjectView(R.id.gallery)
ImageButton mButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // Injection now!!
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_PICK_CONTACT);
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_PICK_CONTACT) {
data.setClass(this, DotActivity.class);
Uri pictUri = data.getData();
if (pictUri != null) {
data.putExtra("mediaImageUri", pictUri);
startActivity(data);
}
}
}
}
package net.vvakame.polkodotter;
import java.util.List;
import com.google.inject.Module;
import roboguice.application.GuiceApplication;
public class MyApplication extends GuiceApplication {
protected void addApplicationModules(List<Module> modules) {
modules.add(new MyModule());
}
}
package net.vvakame.polkodotter;
import android.graphics.Bitmap;
import roboguice.config.AbstractAndroidModule;
public class MyModule extends AbstractAndroidModule {
@Override
protected void configure() {
bind(Bitmap.class).toProvider(BitmapFromUriExtraProvider.class);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment