Skip to content

Instantly share code, notes, and snippets.

@shomah4a
Created October 11, 2010 15:25
Show Gist options
  • Save shomah4a/620689 to your computer and use it in GitHub Desktop.
Save shomah4a/620689 to your computer and use it in GitHub Desktop.
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