[AS3] 擷取 Flash 畫面上的某一區塊為圖檔 (C#/PHP)

Standard

這次來幫一個常用的功能需求做一下作法筆記,就是「擷取 Flash 畫面上的某一區塊為圖檔」。

使用 ActionScript 3.0,後端程式本例做了兩種版本 PHP 與 C#.Net。

  1. 如範例檔,在畫面上安排兩個元件,用來放置欲擷取區塊的 previewMC,以及擷取鈕 capture_btn。

  1. previewMC 元件的影格配置如下:

as 其實只有擺 stop(); ,圖層 3 放了手寫的 “Hello World”,圖層 1 放了四張不同底色的色塊。

  1. 再來是最主要的部份,主場景上的 ActionScript:
stop();

import com.adobe.images.JPGEncoder;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.utils.ByteArray;

// 網站URL
var siteaddress:String = "http://www.yoursite.com.tw/";
var uploadimage:String = "";

// ==========================================================================
// 擷取鈕 [開始]
// ==========================================================================
capture_btn.buttonMode = true;
capture_btn.addEventListener(MouseEvent.CLICK, previewPic);
function previewPic(e:MouseEvent) {

    // 處理縮圖、儲存圖檔的伺服器端程式
    var _uploadPath:String = MovieClip(root).siteaddress + "_Process/capture.ashx?cachebuster="+ new Date().getTime();

    // 圖的長寬
    var image:BitmapData=new BitmapData(180,180);
    // Draw the button into the BitmapData

    // 將 previewMC 的範圍擷取下來
    image.draw(previewMC);

    // Encode the BitmapData into a ByteArray
    var enc:JPGEncoder=new JPGEncoder(100);
    var bytes:ByteArray=enc.encode(image);

    // and convert the ByteArray to a Base64 encoded string
    var base64Bytes:String=Base64.encodeByteArray(bytes);

    // Add the string to a URLVariables object
    var vars:URLVariables = new URLVariables();
    vars.imageData=base64Bytes;

    // and send it over the wire via HTTP POST
    var url:URLRequest=new URLRequest(_uploadPath);
    url.data=vars;
    url.method=URLRequestMethod.POST;

    var loader:URLLoader = new URLLoader();
    loader.addEventListener(Event.COMPLETE, upload_completeHandler);
    loader.addEventListener(IOErrorEvent.IO_ERROR, upload_errorHandler);
    loader.load(url);
}

function upload_completeHandler(e:Event):void {
    trace("上傳成功");
    trace(e.target.data);
}

function upload_errorHandler(e:Event):void {
    trace("error.....");
}
// ==========================================================================
// 擷取鈕 [結束]
// ==========================================================================

// 點擊 previewMC 會循環變色
previewMC.buttonMode = true;
previewMC.addEventListener(MouseEvent.CLICK, changeColor);
function changeColor(e:MouseEvent):void {

    if(previewMC.currentFrame==4){

        previewMC.gotoAndStop(1);

    } else {

        if(previewMC.currentFrame<5){
            previewMC.nextFrame();
        }

    }
};

在這邊會用上 adobe 函式庫 的 JPGEncoder,可在這邊下載 as3corelib

另外,在此我們會使用 Base64 方式將圖片編碼,而 Base64.as 可以自 as3crypto 的 Google Code 專案中取得。

其中請自行設定網址URL,以及處理擷取畫面的後端程式檔案名稱喔。

  1. 再來後端部分,先貼 C#.Net 部分。
<%@ WebHandler Language="C#" Class="upload" %>

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

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

        string b64 = (string.Empty + System.Web.HttpContext.Current.Request["imageData"]).Trim();
        Image img = Base64ToImage(b64);

        string _saveMapPath;

        // 縮圖放置的路徑
        _saveMapPath = context.Server.MapPath("~/original");

        string _extensionName = ".jpg";
        string _newFileName = getTimeToString() + _extensionName;

        do
        {
            if (FileExists(_saveMapPath + "/" + _newFileName))
            {
                _newFileName = getTimeToString() + _extensionName;
            }
            else
            {
                break;
            }
        } while (true);

        UploadImage(img, 180, 180, _saveMapPath + "/" + _newFileName);

        context.Response.Write(_newFileName);
        context.Response.End();
    }
    public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        return image;
    }
    private string getTimeToString() {
        DateTime _d = DateTime.Now;
        return _d.Year + "_" + _d.Month + "_" + _d.Day + "_" + _d.Hour + "_" + _d.Minute + "_" + _d.Second + "_" + _d.Millisecond;
    }
    public bool FileExists(string FileFullPath)
    {
    FileInfo f = new FileInfo(FileFullPath);
    return f.Exists;

    }
    public bool IsReusable {
        get {
            return false;
        }
    }

    #region 固定模版裁剪並縮放
    ///
    /// 上傳圖片(以Post方式獲取源文件)
    /// 按模版比例最大範圍的裁剪圖片並縮放至模版尺寸
    ///
    /// 原圖HttpPostedFile對象
    /// 模版寬(單位:px)
    /// 模版高(單位:px)
    /// 保存路徑
    public static void UploadImage(System.Drawing.Image img, int templateWidth, int templateHeight, string fileSaveUrl)
    {
        //從文件獲取原始圖片,並使用流中嵌入的顏色管理信息
        //System.Drawing.Image initImage = System.Drawing.Image.FromStream(postedFile.InputStream, true);
        System.Drawing.Image initImage = img;

        //原圖寬高均小於模版,不作處理,直接保存
        if (initImage.Width <= templateWidth && initImage.Height <= templateHeight)
        {
            initImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
        else
        {
            //模版的寬高比例
            double templateRate = double.Parse(templateWidth.ToString()) / templateHeight;
            //原圖片的寬高比例
            double initRate = double.Parse(initImage.Width.ToString()) / initImage.Height;

            //原圖與模版比例相等,直接縮放
            if (templateRate == initRate)
            {
                //按模版大小生成最終圖片
                System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
                System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
                templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                templateG.Clear(Color.White);
                templateG.DrawImage(initImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, initImage.Width, initImage.Height), System.Drawing.GraphicsUnit.Pixel);
                templateImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            //原圖與模版比例不等,裁剪後縮放
            else
            {
                //裁剪對象
                System.Drawing.Image pickedImage = null;
                System.Drawing.Graphics pickedG = null;

                //定位
                Rectangle fromR = new Rectangle(0, 0, 0, 0);//原圖裁剪定位
                Rectangle toR = new Rectangle(0, 0, 0, 0);//目標定位

                //寬為標準進行裁剪
                if (templateRate > initRate)
                {
                    //裁剪對象實例化
                    pickedImage = new System.Drawing.Bitmap(initImage.Width, int.Parse(Math.Floor(initImage.Width / templateRate).ToString()));
                    pickedG = System.Drawing.Graphics.FromImage(pickedImage);

                    //裁剪源定位
                    fromR.X = 0;
                    fromR.Y = int.Parse(Math.Floor((initImage.Height - initImage.Width / templateRate) / 2).ToString());
                    fromR.Width = initImage.Width;
                    fromR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());

                    //裁剪目標定位
                    toR.X = 0;
                    toR.Y = 0;
                    toR.Width = initImage.Width;
                    toR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());
                }
                //高為標準進行裁剪
                else
                {
                    pickedImage = new System.Drawing.Bitmap(int.Parse(Math.Floor(initImage.Height * templateRate).ToString()), initImage.Height);
                    pickedG = System.Drawing.Graphics.FromImage(pickedImage);

                    fromR.X = int.Parse(Math.Floor((initImage.Width - initImage.Height * templateRate) / 2).ToString());
                    fromR.Y = 0;
                    fromR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
                    fromR.Height = initImage.Height;

                    toR.X = 0;
                    toR.Y = 0;
                    toR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
                    toR.Height = initImage.Height;
                }

                //設置質量
                pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                //裁剪
                pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);

                //按模版大小生成最終圖片
                System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
                System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
                templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                templateG.Clear(Color.White);
                templateG.DrawImage(pickedImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, pickedImage.Width, pickedImage.Height), System.Drawing.GraphicsUnit.Pixel);
                templateImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);

                //釋放資源
                templateG.Dispose();
                templateImage.Dispose();

                pickedG.Dispose();
                pickedImage.Dispose();
            }
        }

        //釋放資源
        initImage.Dispose();
    }
    #endregion
}
  1. 再來是 PHP 版本,這個就沒做縮圖了。
<?php
require_once("JSON.php");

$errors = "";

$imageData = @$_POST['imageData'];

function base64_to_jpeg( $inputfile, $outputfile ) {
  /* encode & write data (binary) */
  $ifp = fopen( 'original/' . $outputfile, "wb" );
  fwrite( $ifp, base64_decode( $inputfile ) );
  fclose( $ifp );
  /* return output filename */
  return( $outputfile );
}

function getRandomFileName() {
    return date('ymdhis').rand(100, 999) . '.' . 'jpg';
}

if( $imageData != "" ) {

    $data = array(
        'result' => 'Y',
        'thumb' => base64_to_jpeg($imageData, getRandomFileName())
    );

    $json = new Services_JSON();
    echo $json->encode($data);
    exit();

} else {

    $data = array(
        'result' => 'Y',
        'error' => 'no file'
    );

    $json = new Services_JSON();
    echo $json->encode($data);
    exit();
}
?>

大致就是醬子啦。

範例檔下載 (CS4)

參考資料:Pass Image from Flash to ASP.NET

5 thoughts on “[AS3] 擷取 Flash 畫面上的某一區塊為圖檔 (C#/PHP)

  1. 我的環境是 AS 2.0 ,後端是 ASP ,
    如此舊的組合,有辦法達到相同的功能嗎?

    如果無法從flash 內部來啟動這個擷圖,
    是否其它solution ?

    謝謝您!

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *