Created
October 11, 2010 15:25
-
-
Save shomah4a/620689 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package path.to.pkg | |
import android.app | |
import android.os | |
import android.content | |
import android.hardware | |
import android.view | |
import android.hardware | |
import android.graphics | |
import android.provider | |
import android.content.res | |
import java.io | |
import java.util | |
import scala.collection | |
import scala.math | |
import scala.actors | |
object SupportFuncs | |
{ | |
def YUV422toARGB9999(src: Array[Byte], dest: Array[Int], w: Int, h: Int) | |
{ | |
0 until h foreach { | |
y=> | |
{ | |
0 until w foreach { | |
x=> | |
{ | |
val i = y * w | |
val s = src(i).asInstanceOf[Int] & 0xff | |
dest(i) = 0xff000000 | s << 16 | s << 8 | s | |
} | |
} | |
} | |
} | |
} | |
} | |
class PictureCallback(prev: Preview, ctx: content.Context) extends hardware.Camera.PictureCallback | |
{ | |
val SDROOT = "/sdcard/" | |
def onPictureTaken(data: Array[Byte], cam: hardware.Camera) | |
{ | |
prev.log("Take Photo") | |
try | |
{ | |
val name = "photo_" + String.valueOf(util.Calendar.getInstance.getTimeInMillis) + ".jpg" | |
this.saveDataToSD(data, name) | |
} | |
catch | |
{ | |
case e => | |
{ | |
prev.log(e) | |
prev.cameraRelease | |
} | |
} | |
} | |
def saveDataToSD(data: Array[Byte], name: String) | |
{ | |
try | |
{ | |
val out = new java.io.FileOutputStream(this.SDROOT + name) | |
try | |
{ | |
out.write(data) | |
} | |
finally | |
{ | |
out.close | |
} | |
} | |
catch | |
{ | |
case e => | |
{ | |
prev.log(e) | |
prev.cameraRelease | |
} | |
} | |
} | |
def saveDataToURI(data: Array[Byte], name: String) | |
{ | |
val resolver = ctx.getContentResolver | |
val bmp = graphics.BitmapFactory.decodeByteArray(data, 0, data.length) | |
val vals = new content.ContentValues | |
vals.put(provider.MediaStore.MediaColumns.DISPLAY_NAME, name) | |
vals.put(provider.MediaStore.Images.ImageColumns.DESCRIPTION, "taken with me!") | |
vals.put(provider.MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") | |
val uri = resolver.insert(provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, vals) | |
try | |
{ | |
val out = resolver.openOutputStream(uri) | |
bmp.compress(graphics.Bitmap.CompressFormat.JPEG, 90, out) | |
out.close | |
} | |
catch | |
{ | |
case e => | |
{ | |
prev.log(e) | |
prev.cameraRelease | |
} | |
} | |
} | |
def onPause | |
{ | |
prev.cameraRelease | |
} | |
def onResume | |
{ | |
prev.cameraRelease | |
} | |
} | |
class CameraPreview(val par: Preview) extends hardware.Camera.PreviewCallback | |
{ | |
override def onPreviewFrame(data: Array[Byte], cam: hardware.Camera) | |
{ | |
par.log("preview") | |
val parm = cam.getParameters | |
val size = parm.getPreviewSize | |
par.setRawImage(data, size.width, size.height) | |
} | |
} | |
class Preview(val context: content.Context) extends view.SurfaceView(context) | |
with view.SurfaceHolder.Callback | |
with Runnable | |
{ | |
val holder = this.getHolder | |
var camera: hardware.Camera = null | |
var rawImage: Array[Byte] = null | |
var rawImageInt: Array[Int] = null | |
var rawImageSize: (Int, Int) = null | |
var bitmap: graphics.Bitmap = null | |
var thread: Thread = null | |
var visible = false | |
private val paint = new graphics.Paint() | |
paint.setColor(0xffffffff) | |
paint.setTextSize(32) | |
paint.setTextAlign(graphics.Paint.Align.LEFT) | |
paint.setLinearText(true) | |
paint.setAntiAlias(true) | |
paint.setStrokeWidth(2) | |
paint.setStrokeCap(graphics.Paint.Cap.ROUND) | |
paint.setStyle(graphics.Paint.Style.STROKE) | |
private val TAG = "Camera" | |
def log[T](out: T) | |
{ | |
android.util.Log.v(this.TAG, out.toString) | |
} | |
holder.addCallback(this) | |
// サーフェイスタイプ指定 | |
// SURFACE_TYPE_PUSH_BUFFERS だと lockCanvas できない | |
// holder.setType(view.SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) | |
holder.setType(view.SurfaceHolder.SURFACE_TYPE_NORMAL) | |
def surfaceCreated(holder: view.SurfaceHolder) | |
{ | |
try | |
{ | |
this.log("surfaceCreated") | |
this.camera = hardware.Camera.open | |
// RGB_565 にしても RGB_565 では取れない | |
// val parm = this.camera.getParameters | |
// parm.setPreviewFormat(graphics.ImageFormat.RGB_565) | |
// this.camera.setParameters(parm) | |
// SURFACE_TYPE_NORMAL なので setPreviewDisplay が使えない | |
// this.camera.setPreviewDisplay(holder) | |
this.camera.setPreviewCallback(new CameraPreview(this)) | |
// 即 startPreview したら真っ暗だったので、ちょっと待ってから | |
actors.Actor.actor{ | |
Thread.sleep(3000) | |
this.camera.startPreview | |
} | |
// 描画スレッド開始 | |
this.thread = new Thread(this) | |
this.thread.start | |
this.visible = true | |
this.log("surfaceCreated finish") | |
} | |
catch | |
{ | |
case e => | |
{ | |
this.log("************* Errpr *************") | |
this.log(e) | |
this.cameraRelease | |
} | |
} | |
} | |
def surfaceDestroyed(holder: view.SurfaceHolder) | |
{ | |
this.camera.stopPreview | |
this.cameraRelease | |
// 描画スレッド終了 | |
try | |
{ | |
this.thread.stop | |
} | |
catch | |
{ | |
case e => {} | |
} | |
this.thread = null | |
this.visible = false | |
} | |
def cameraRelease() | |
{ | |
if (this.camera != null) | |
{ | |
this.camera.setPreviewCallback(null) | |
this.camera.stopPreview | |
this.camera.release | |
this.camera = null | |
} | |
} | |
def getOptimalPreviewSize(sizes: List[hardware.Camera#Size], | |
w: Int, h: Int): hardware.Camera#Size = | |
{ | |
val AS_TOL = 0.05 | |
val targetratio = w.asInstanceOf[Double] / h | |
val targetheight = h | |
if (sizes == null) | |
{ | |
return null | |
} | |
val (optsize, mindiff) = sizes.foldLeft((null: hardware.Camera#Size, Double.MaxValue)) { | |
(x, y) => | |
{ | |
val (optimalSize, minDiff) = x | |
val ratio = y.width.asInstanceOf[Double] / y.height | |
if (math.abs(ratio - targetratio) > AS_TOL) | |
{ | |
x | |
} | |
else if (math.abs(y.height - targetheight) < minDiff) | |
{ | |
(y, math.abs(y.height - targetheight)) | |
} | |
else | |
{ | |
x | |
} | |
} | |
} | |
if (optsize == null) | |
{ | |
val (osize, diff) = sizes.foldLeft((optsize, Double.MaxValue)) { | |
(x, y) => | |
{ | |
val (optimalSize, minDiff) = x | |
if (math.abs(y.height - targetheight) < minDiff) | |
{ | |
(y, math.abs(y.height - targetheight)) | |
} | |
else | |
{ | |
x | |
} | |
} | |
} | |
osize | |
} | |
else | |
{ | |
optsize | |
} | |
} | |
def surfaceChanged(holder: view.SurfaceHolder, fmt: Int, w: Int, h: Int) | |
{ | |
this.log("surfaceChanged") | |
val parms = this.camera.getParameters | |
val sizes = collection.JavaConversions.asIterable(parms.getSupportedPreviewSizes).toList | |
val optsize = this.getOptimalPreviewSize(sizes, w, h) | |
parms.setPreviewSize(optsize.width, optsize.height) | |
this.camera.setParameters(parms) | |
this.camera.startPreview | |
this.log("surfaceChanged finish") | |
} | |
override def onTouchEvent(evt: view.MotionEvent): Boolean = | |
{ | |
this.log("touch: " + evt.getAction.toString) | |
if (evt.getAction == view.MotionEvent.ACTION_DOWN) | |
{ | |
this.log("takePhoto!") | |
actors.Actor.actor{ | |
this.camera.takePicture(null, null, new PictureCallback(this, context)) | |
} | |
actors.Actor.actor{ | |
Thread.sleep(3000) | |
this.camera.startPreview | |
} | |
} | |
this.log("touch finish") | |
true | |
} | |
def setRawImage(data: Array[Byte], width: Int, height: Int) | |
{ | |
this.rawImage = data | |
this.rawImageSize = (width, height) | |
if (this.rawImageInt == null || this.rawImageInt.length != width * height) | |
{ | |
this.rawImageInt = new Array[Int](width*height) | |
this.bitmap = graphics.Bitmap.createBitmap(width, height, graphics.Bitmap.Config.ARGB_8888) | |
} | |
if (this.rawImageInt != null) | |
{ | |
} | |
} | |
def run | |
{ | |
while (true) | |
{ | |
if (!this.visible) | |
{ | |
return | |
} | |
try | |
{ | |
this.doDraw | |
} | |
catch | |
{ | |
case e => {} | |
} | |
// 遅いからいいや | |
// Thread.sleep(33) | |
} | |
} | |
def doDraw() | |
{ | |
if (this.rawImage == null) | |
{ | |
return | |
} | |
val (w, h) = this.rawImageSize | |
val st = System.currentTimeMillis | |
// YUV422 -> ARGB8888 | |
// SupportFuncs.YUV422toARGB8888(this.rawImage, this.rawImageInt, w, h) | |
Utils.YUV422toARGB8888(this.rawImage, this.rawImageInt, w, h) | |
val yuv = System.currentTimeMillis | |
// Bitmap 生成 | |
this.bitmap.setPixels(this.rawImageInt, 0, w, 0, 0, w, h) | |
// val bmp = graphics.Bitmap.createBitmap(this.rawImageInt, w, h, graphics.Bitmap.Config.ARGB_8888) | |
val conv = System.currentTimeMillis | |
this.draw { | |
cv=>{ | |
// 描画 | |
cv drawColor 0xff8833bb | |
cv.drawBitmap(this.bitmap, 0, 0, this.paint) | |
// cv.drawBitmap(this.rawImageInt, 0, w, 0, 0, w, h, true, this.paint) | |
// cv.drawBitmap(bmp, 0, 0, this.paint) | |
val ed = System.currentTimeMillis | |
// デバッグ | |
cv.drawText("Conv YUV " + (yuv-st).toString, 200, 100, this.paint) | |
cv.drawText("Convert " + (conv-yuv).toString, 200, 150, this.paint) | |
cv.drawText("Draw " + (ed-conv).toString, 200, 200, this.paint) | |
cv.drawText("FPS " + (1000 / (ed-st)).toString, 200, 250, this.paint) | |
}} | |
} | |
def draw(f: graphics.Canvas=>Unit) | |
{ | |
val cv = this.holder.lockCanvas | |
try | |
{ | |
cv.save | |
f(cv) | |
cv.restore | |
} | |
finally | |
{ | |
this.holder unlockCanvasAndPost cv | |
} | |
} | |
} | |
class Camera extends app.Activity | |
{ | |
var preview: Preview = null | |
override def onCreate(savedInstanceState: os.Bundle) | |
{ | |
super.onCreate(savedInstanceState) | |
this.requestWindowFeature(view.Window.FEATURE_NO_TITLE) | |
this.preview = new Preview(this) | |
this.setContentView(this.preview) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment