Flash在线拍摄用户头象

很多网站在上传用户头象时,除了传统方式上传外,都支持在线摄像头拍照并做简单编辑,完成之后再将图象数据提交到服务端(比如ASP.Net),这几天正好需要这个功能,研究了下,思路如下:

1、先获取摄像头视频

2、利用BitmapData.draw来对视频截图

3、在截图上,放一个方块允许用户手动调整位置,同时允许截图做缩放

4、用户调整完成后,对指定区域的BitmapData做copyPixes处理(即拷贝指定区域的像素)

5、将上一步得到的新BitmapData进行Jpeg编码压缩,然后再转到base64字符串

6、将字符串发送到ASP.Net,然后还原成图片保存即可(即base64的解码)

flash端代码:(第6步省略了)

import flash.media.Camera;
import flash.text.TextField;
import flash.media.Video;
import flash.text.TextFormat;
import fl.controls.Button;
import flash.utils.Timer;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.geom.Rectangle;
import flash.events.Event;

var _cam:Camera;
var _txtInfo:TextField = txtInfo;
var _txtMsg:TextField = txtMsg;
var _btnGet:Button = btnGet;
var _btnSave:Button = btnSave;
var _video:Video = myVideo;
var _timer:Timer;
var _videoIsWorked:Boolean = false;
var _bmp:Bitmap;
var _bmpTest:Bitmap;
var _mask:Sprite;
var _slider:SimpleSlider;

init();

function init():void
{
	this._txtMsg.visible = false;
	this._btnGet.label = "拍 照";
	this._btnSave.label = "保 存";
	this._txtInfo.selectable = false;
	var style:TextFormat = new TextFormat();
	style.font = "宋体";
	style.size = 12;//字体大小
	style.color = 0x000000;//RGB色
	style.leading = 7;//行间距
	this._btnGet.setStyle("textFormat",style);
	this._btnSave.setStyle("textFormat",style);
	getCamera();
}

function getCamera():void
{

	this._btnGet.enabled = false;
	this._btnSave.enabled = false;

	this._cam = Camera.getCamera();
	if (_cam == null)
	{
		this._txtInfo.text = "未检测到摄像头设备!";
		return;
	}



	_cam.addEventListener(StatusEvent.STATUS, cameraStatusHandler);
	_cam.addEventListener(ActivityEvent.ACTIVITY, cameraActivityHandler);

	_cam.setQuality(0,0);
	this._video.attachCamera(this._cam);

}

//用户选择是否摄像头时触发 ;
function cameraStatusHandler(e:StatusEvent):void
{

	if (e.code == "Camera.Muted")
	{
		this._txtInfo.text = "您不允许使用摄像头!";
	}
	else if (e.code == "Camera.Unmuted")
	{
		this._txtInfo.text = "摄像头视频获取中...";
		_timer = new Timer(100,20);//每隔100ms检测摄像头状态,一共检测20次   
		cameraActivityHandler(null);
	}
}


//摄像头有活动时被触发 
function cameraActivityHandler(e:ActivityEvent):void
{
	if (! _videoIsWorked)
	{
		if (_timer != null)
		{
			_timer.addEventListener(TimerEvent.TIMER, checkCamera);
			_timer.addEventListener(TimerEvent.TIMER_COMPLETE, checkCameraComplete);
			_timer.start();
		}
	}
}


//timer回调函数,用于检测摄像头设备是否正确 
function checkCamera(e:TimerEvent):void
{
	this._txtInfo.text = "摄像头视频获取中...";
	if (this._cam.currentFPS > 0)
	{
		_timer.stop();
		_videoIsWorked = true;
		this._txtInfo.text = "";//摄像头工作正常

		this._txtInfo.text = "摄像头正常,请点击拍照";

		//trace("_cam.width=",_cam.width,",_cam.height=",_cam.height);

		this._btnGet.addEventListener(MouseEvent.CLICK,btnGet_Click);
		this._btnGet.enabled = true;

		this._video.width = 240;
		this._video.height = 180;

		//trace(this._video.width,this._video.height);

	}

}


function btnGet_Click(e:MouseEvent):void
{
	var bmd:BitmapData = new BitmapData(_cam.width,_cam.height);
	bmd.draw(_video);
	//trace(bmd.width,bmd.height);
	if (this._bmp == null)
	{
		this._bmp = new Bitmap(bmd);
		addChild(_bmp);
		_bmp.x = 260;
		_bmp.y = 10;
		_bmp.width = _video.width;
		_bmp.height = _video.height;

		if (this._mask == null)
		{
			this._mask = new Sprite();
			this._mask.graphics.beginFill(0xffffff,0.3);
			this._mask.graphics.drawRect(0,0,125,125);
			this._mask.graphics.endFill();
			this._mask.graphics.lineStyle(1,0xff0000,1);
			this._mask.graphics.lineTo(1,124);
			this._mask.graphics.lineTo(124,124);
			this._mask.graphics.lineTo(124,1);
			this._mask.graphics.lineTo(1,1);
			addChild(this._mask);
			this._mask.x = 260 + 57;
			this._mask.y = 10 + 27;
			this._mask.buttonMode = true;
			this._mask.addEventListener(MouseEvent.MOUSE_DOWN,mask_startDrag);
			this.stage.addEventListener(MouseEvent.MOUSE_UP,stage_endDrag);

			if (_slider == null)
			{
				_slider = new SimpleSlider(125,180,180);
				_slider.backWidth = 120;
				_slider.backHeight = 6;
				_slider.handleHeight = 16;
				_slider.addEventListener(Event.CHANGE,slider_Change);
				addChild(_slider);
				_slider.x = 320;
				_slider.y = 205;
				this._txtMsg.visible = true;
			}
		}
	}
	else
	{
		this._bmp.bitmapData = bmd;
	}
	this._btnSave.enabled = true;

	this._txtInfo.text = "拖动左侧方块可调整位置"
	;
	this._btnSave.addEventListener(MouseEvent.CLICK,btnSave_Click);
}


function btnSave_Click(e:Event):void
{
	//因为视频的大小跟摄像头原始像素的尺寸并不一致(即视频可能缩放过了,所以要用比例调整回最初始的状态)
	var ratio:Number = this._cam.width / this._bmp.width;

	var imgWidth:int = this._mask.width * ratio;
	var imgHeight:int = this._mask.height * ratio;
	//trace(ratio);

	var bmd:BitmapData = new BitmapData(imgWidth,imgHeight,false,0xffff99);
	bmd.copyPixels(this._bmp.bitmapData,new Rectangle((this._mask.x-260)*ratio,(this._mask.y - 10)*ratio,imgWidth,imgHeight),new Point());

	if (this._bmpTest == null)
	{
		this._bmpTest = new Bitmap(bmd);
		addChild(_bmpTest);
		_bmpTest.x = 375;
		_bmpTest.y = 230;

	}
	else
	{
		this._bmpTest.bitmapData = bmd;
	}

	_bmpTest.width = this._mask.width;
	_bmpTest.height = this._mask.height;
	trace("_bmpTest.width=",this._mask.width,",_bmpTest.height=",this._mask.height);

	var jpegEncoder:JPGEncoder = new JPGEncoder();
	var jpegArr:ByteArray = jpegEncoder.encode(bmd);//压缩成jpeg  
	
	trace(jpegArr.length);
	
	var base64string:String = Base64.encode(jpegArr);
	
	txtBase64.text = base64string;
	
	trace(base64string.length);

}

function slider_Change(e:Event):void
{
	//trace(e);
	this._bmp.height = this._slider.value;
	this._bmp.width = this._bmp.height * 4 / 3;
}

function mask_startDrag(e:MouseEvent):void
{
	this._mask.startDrag(false,new Rectangle(260,10,240-125,180-125));


}

function stage_endDrag(e:MouseEvent):void
{
	this._mask.stopDrag();
	//trace("x=",_mask.x);
	//trace("y=",_mask.y);
}

function checkCameraComplete(e:TimerEvent):void
{
	this._txtInfo.text = "设备无法使用!(有可能被占用)";
	_timer.removeEventListener(TimerEvent.TIMER, checkCamera);
	_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, checkCameraComplete);
	_timer = null;
}

Flash在线演示(需要电脑上连接好摄像头)

C#端的处理示例:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;

namespace OnlinePhotoCapture
{
    /// <summary>
    /// 将图片base64字符串原还原为图片并调整尺寸后保存(by 菩提树下的杨过http://yjmyzz.cnblogs.com/)   
    /// </summary>    
    public class SavePhoto : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";

            string base64String = "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";

            Image bmp = null;
            MemoryStream ms = null;
            try
            {
                byte[] b = Convert.FromBase64String(base64String);
                ms = new MemoryStream(b);
                bmp = ImageResize(new Bitmap(ms),125,125);
                bmp.Save(context.Request.MapPath("logo.jpg"), ImageFormat.Jpeg);
                context.Response.Write("success");
            }
            catch (Exception ex)
            {
                context.Response.Write("failure:" + ex.Message.ToString());
            }
            finally
            {
                bmp.Dispose();
                ms.Dispose();
            }

        }

       

        /// <summary>
        /// 修改图片尺寸
        /// </summary>
        /// <param name="imgSrc"></param>
        /// <returns></returns>
        private Image ImageResize(Image imgSrc,int width,int height)
        {
            Image newImage = imgSrc.GetThumbnailImage(125, 125, null, new IntPtr());
            Graphics g = Graphics.FromImage(newImage);
            g.DrawImage(newImage, 0, 0, newImage.Width, newImage.Height);
            g.Dispose();
            return newImage;
        }


        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏HansBug's Lab

1455: 罗马游戏

1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 721  Solved: 272 [Subm...

31310
来自专栏.net core新时代

Spire.Doc组件读取与写入Word

  之前写了一篇开源组件DocX读写word的文章,当时时间比较匆忙选了这个组件,使用过程中还是有些不便,不能提前定义好模版,插入Form表单域进行替换。最近无...

29310
来自专栏浅探ARKit

ARKit中控制.dae动画的播放

4.用时间控制动画--CAAnimation 里的 timeOffset 控制开始时间 duration控制播放时间

7747
来自专栏GIS讲堂

Openlayers2中统计图的实现

在前文中,介绍了Arcgis for js和Openlayers3中统计图的实现,在本文,书接上文,介绍在Openlayers2中,统计图的实现。

1503
来自专栏iOS Developer

FFmpeg-iOS获取摄像头麦克风

1812
来自专栏用户2442861的专栏

Android游戏开发十日通(6)- 太空大战

http://blog.csdn.net/silangquan/article/details/16921035

1392
来自专栏Golang语言社区

Golang生产级可靠UDP库

kcp-go is a Production-Grade Reliable-UDP library for golang.

7652
来自专栏菩提树下的杨过

Flash/Flex学习笔记(52):使用TweenLite

TweenLite是第三方出品的专用于各种缓动动画的类库,其性能据说已经超过了Adobe官方的Tween. 从网上找到了一篇中文的说明文档:http://fil...

2085
来自专栏五毛程序员

五毛的cocos2d-x学习笔记08-动画

1965
来自专栏图像识别与深度学习

《Android》Lesson15-学段复习

20010

扫码关注云+社区

领取腾讯云代金券