asmxよ、永遠に。

HTML5でCanvasを使ってお絵かきをして、その結果を画像ファイルとしてサーバーに保存することを考える。

方法としては何も目新しいものはなく、
canvas.toDataURL()で得られる画像(Base64でエンコードが掛っている)を
サーバーに送って、サーバー側でデコードして.pngファイルに落とすだけです。

Perl,PHP,ASP.NET等、何を使っても実現可能ですが、
開発寿命の近づいている、.asmxを使ってWEBサービスで処理してみます。
今ならWCFですが、メンテ等では見る機会があるかもしれないのでメモとして残しておきます。

下記に示す方法を何と言うのかわかりませんが、microsoftajax.jsを使っているので
ブラウザは何でも良く、Client側はMSのルールに縛られずに
(サーバーがIISであることは必須ですが、ASP用の宣言や定義とかは不要、)、
自由な .htmlや .js を並べることができます。
.asmxもBuildの必要はなく、ソースとしてアップできるので、簡単に修正できます。

出力ファイル名(相対パス)を fname、Base64でエンコードされたデータ
(先頭の'data:image/png;base64,'は削除済み)を datauri として、大概は次のようになります。

    [WebMethod]
    public void imgwrite(string fname, string datauri)
    {
        byte[] todecode_byte = null;
        try{
            System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
            System.Text.Decoder utf8Decode = encoder.GetDecoder();

            todecode_byte = Convert.FromBase64String(datauri);

        }catch (Exception e){
            throw new Exception("Error in imgwrite:" + e.Message);
        }

        string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
        FileStream fs = null;
        BinaryWriter bw = null;
        try{
            fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
            bw = new BinaryWriter(fs);
            bw.Write(todecode_byte);

        }catch (Exception e){
            throw new Exception("Error in imgwrite:" + e.Message);
        }finally{
            if (bw != null) bw.Close();
            if (fs != null) fs.Close();
        }
    }

これだけだとつまらないので、javascriptのみでサーバー側のファイル操作を可能にするサービス集合にします。
まずは、UploadService.asmx

<%@ WebService Language="C#" CodeBehind="UploadService.asmx.cs" Class="UploadService.UploadService" %>

続いて、UploadService.asmx.cs です。

// (c) Copyright HUNDREDSOFT Corporation 2012
//	All Rights Reserved.
//
//	NAME
//		UploadService.asmx.cs
//
using System;
using System.Data;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;

namespace UploadService
{
    /// <summary>
    /// imgupload()
    /// imgwrite(fname, datauri)
    /// txtwrite(fname, cname, datatxt)
    /// download(fname, uri)
    /// filecopy(fname, src)
    /// filedelete(fname)
    /// filemove(fname, src)
    /// 
    /// [fname]
    /// 出力ファイル名(相対パス)
    /// 
    /// [uri]
    /// 入力ファイル名(URLアドレス)
    /// 
    /// [src]
    /// 入力ファイル名(相対パス)
    /// 
    /// [datauri]
    /// 画像データをBase64でエンコードした文字列
    /// 
    /// [cname]
    /// 出力文字エンコード(例)
    /// "shift_jis"
    /// "EUC-JP"
    /// "UNICODE"
    /// "UTF-8"
    /// 
    /// [datatxt]
    /// 文字列
    /// 
    /// imguploadは、次のように呼び出す。
    ///  <form method='POST' enctype='multipart/form-data' action='UploadService.asmx/imgupload'>
    ///  <input type='text' name='filename'></input>
    ///  <input type='file' name='file'></input>
    ///  <input type='submit' value='imgupload'></input>
    ///  </form>
    /// 
    /// (注)imgwrite,txtwriteでは、100kを超える文字列は100k以下で分割して送信すること
    /// 
    /// </summary>
    /// 
    [WebService(Namespace = "http://localhost/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    [ToolboxItem(false)]

    public class UploadService : System.Web.Services.WebService
    {
        // function imgupload
        // Multi-formでUploadされたバイナリファイルをサーバー上に書き出します。
        //
        [WebMethod]
        public void imgupload()
        {
            FileStream fs = null;
            try{
                HttpFileCollection hfc = HttpContext.Current.Request.Files;

                if (hfc.Count > 0){
                    string fname = HttpContext.Current.Request.Form["filename"];
                    string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");

                    Stream his = hfc[0].InputStream;
                    byte[] bdata = new byte[his.Length];
                    his.Read(bdata, 0, (int)his.Length);

                    fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
                    fs.Write(bdata, 0, bdata.Length);
                }

            }catch (Exception e){
                throw new Exception("Error in imgupload:" + e.Message);
            }finally{
                if (fs != null) fs.Close();
            }
        }

        // function imgwrite
        // Base64でエンコードされたバイナリファイルをサーバー上でデコードして書き出します。
        //
        [WebMethod]
        public void imgwrite(string fname, string datauri)
        {
            byte[] todecode_byte = null;
            try{
                System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
                System.Text.Decoder utf8Decode = encoder.GetDecoder();

                todecode_byte = Convert.FromBase64String(datauri);

            }catch (Exception e){
                throw new Exception("Error in imgwrite:" + e.Message);
            }

            string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
            FileStream fs = null;
            BinaryWriter bw = null;
            try{
                fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
                bw = new BinaryWriter(fs);
                bw.Write(todecode_byte);

            }catch (Exception e){
                throw new Exception("Error in imgwrite:" + e.Message);
            }finally{
                if (bw != null) bw.Close();
                if (fs != null) fs.Close();
            }
        }

        // function txtwrite
        // サーバー上に、様々な日本語コードでテキストファイルに出力します。
        //
        [WebMethod]
        public void txtwrite(String fname, String cname, String datatxt)
        {
            System.IO.StreamWriter sw = null;
            try{
                System.Text.Encoding enc = System.Text.Encoding.GetEncoding(cname);
                // BOMなし
                if (cname == "UTF-8"){
                    enc = new System.Text.UTF8Encoding(false);
                }else if (cname == "UNICODE"){
                    enc = new System.Text.UnicodeEncoding(false, false);
                }
                string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
                sw = new System.IO.StreamWriter(filename, true, enc);
                sw.Write(datatxt);

            }catch (Exception e){
                throw new Exception("Error in txtwrite:" + e.Message);
            }finally{
                if (sw != null) sw.Close();
            }
        }

        // function download
        // URIで指定されたファイルを、サーバー上にダウンロードします。
        //
        [WebMethod]
        public void download(string fname, string uri)
        {
            BinaryReader br = null;
            FileStream fs = null;
            BinaryWriter bw = null;
            try{
                WebClient wc = new WebClient();
                br = new BinaryReader(wc.OpenRead(uri));
                byte[] read_byte = null;
                int read_count = 0;

                string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
                fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
                bw = new BinaryWriter(fs);

                do{
                    read_byte = br.ReadBytes(1024);
                    read_count = read_byte.Length;
                    bw.Write(read_byte);
                } while (read_count == 1024);

            }catch (Exception e){
                throw new Exception("Error in download:" + e.Message);
            }finally{
                if (br != null) br.Close();
                if (bw != null) bw.Close();
                if (fs != null) fs.Close();
            }
        }

        // function filecopy, filedelete, filemove
        // サーバー上でファイルをコピー、削除、移動します。
        //
        [WebMethod]
        public void filecopy(string fname, string src)
        {
            try{
                string psrc = HttpContext.Current.Request.MapPath(src);
                string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
                File.Copy(psrc, filename, true);

            }catch (Exception e){
                throw new Exception("Error in filecopy:" + e.Message);
            }
        }

        [WebMethod]
        public void filedelete(string fname)
        {
            try{
                string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
                File.Delete(filename);

            }catch (Exception e){
                throw new Exception("Error in filedelete:" + e.Message);
            }
        }

        [WebMethod]
        public void filemove(string fname, string src)
        {
            try{
                string psrc = HttpContext.Current.Request.PhysicalApplicationPath + src.Replace("/", "\\");
                string filename = HttpContext.Current.Request.PhysicalApplicationPath + fname.Replace("/", "\\");
                File.Move(psrc, filename);

            }catch (Exception e){
                throw new Exception("Error in filemove:" + e.Message);
            }
        }

        // function getfilenames
        // サーバー上のファイル一覧を取得します。
        //
        [WebMethod]
        public string getfilenames(string src)
        {
            string ret = "";
            try{
                string psrc = HttpContext.Current.Request.PhysicalApplicationPath + src.Replace("/", "\\");
                ret = getdir(psrc, ret);

            }catch (Exception e){
                throw new Exception("Error in getfilenames:" + e.Message);
            }
            return ret;
        }

        private string getdir(string dir, string ret)
        {
            string[] files = Directory.GetFiles(dir);
            foreach (string s in files){
                ret += s + ",";
            }
            string[] dirs = Directory.GetDirectories(dir);
            foreach (string s in dirs){
                ret = getdir(s, ret);
            }
            char[] tc = {','};
            return ret.TrimEnd(tc);
        }
    }
}

最後にテスト用の test.html です。(テスト用なので,IE9(canvasサポート)だけを選ばない。)


<html>
<head>
<title>test UploadService.asmx</title>
<script type="text/javascript" src="microsoftajax.js" ></script>
<script type="text/javascript" src="uploadservice.asmx/js" ></script>
<script type="text/javascript">
function test_imgwrite()
{
	var data =
	'R0lGODlhIQAkAPcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'/wD//////yH+DEh1bmRyZWRzb2Z0AAAsAAAAACEAJAAACM0A/wkcSLCgwYMIEypcyLDhQn8QI0qcSHEiv4IQ+2' +
	'ncyLGjx40QLw7M2M+hQY0hCZI0WRClP5ECV7Ic6BLmP5kz/9VU6U9jToE7R/b8SJRoSqEVkyo9GnNo0acgX/L0' +
	'+TNoU6o5rd4c+lNnP6Zbsc7UinPsV6lCoao9a3Op24pt38oFG5EjSZd2nZK9ezav37xx574N/Bdv1I50+SrWy5' +
	'ctT8FuCR+ebDiq5Mp9Ke+FvPRyZswfEzMeDRXsVs5wDfJbzbq169euu8qefTAgADs=';

	UploadService.UploadService.imgwrite("save/b.gif", data, 
		function(){
			alert("OK");
		}, function(){
			alert("error");
		}
	);
}

function test_txtwrite()
{
	UploadService.UploadService.txtwrite("save/sjis.txt", "shift_jis", "abcあいうえお0123456789",
		function(){}, function(){});

	UploadService.UploadService.txtwrite("save/UNICODE.txt", "UNICODE", "abcあいうえお0123456789",
		function(){}, function(){});

	UploadService.UploadService.txtwrite("save/UTF-8.txt", "UTF-8", "abcあいうえお0123456789",
		function(){}, function(){});
}

function test_download()
{
	UploadService.UploadService.download("save/a.gif", "http://www.hundredsoft.jp/hundredsoft.gif", 
		function(){
			alert("OK");
		}, function(){
			alert("error");
		}
	);
}

function test_filecopy()
{
	UploadService.UploadService.filecopy("save/b.gif", "save/a.gif", 
		function(){
			alert("OK");
		}, function(){
			alert("error");
		}
	);
}

function test_filedelete()
{
	UploadService.UploadService.filedelete("save/b.gif", 
		function(){
			alert("OK");
		}, function(){
			alert("error");
		}
	);
}

function test_filemove()
{
	UploadService.UploadService.filemove("save/b.gif", "save/a.gif", 
		function(){
			alert("OK");
		}, function(){
			alert("error");
		}
	);
}

function test_getfilenames()
{
	UploadService.UploadService.getfilenames("save",
		function(dirstr){
			//var dirs = dirstr.split(",");
			var dirs = dirstr.replace(/,/g, "\r\n");
			alert(dirs);
		}, function(){
			alert("error");
		}
	);
}
</script>
</head>
<body>
<h3>test UploadService.asmx</h3>
<hr />
 <input type="button" id="test01button" name="test01" value="test_imgwrite" onclick="test_imgwrite()"></input>
 <input type="button" id="test02button" name="test02" value="test_txtwrite" onclick="test_txtwrite()"></input>
 <input type="button" id="test03button" name="test03" value="test_download" onclick="test_download()"></input>
 <input type="button" id="test04button" name="test04" value="test_filecopy" onclick="test_filecopy()"></input>
 <input type="button" id="test05button" name="test05" value="test_filedelete" onclick="test_filedelete()"></input>
 <input type="button" id="test06button" name="test06" value="test_filemove" onclick="test_filemove()"></input>
 <input type="button" id="test07button" name="test07" value="test_getfilenames" onclick="test_getfilenames()"></input>
<br />
<hr />
test_imgupload<br />
<form method="POST" enctype="multipart/form-data" action="UploadService.asmx/imgupload" target="idmy">
保存パス  : <input type="text" name="filename"></input><br />
画像ファイル: <input type="file" name="file"></input>
 <input type="submit" value="imgupload"></input>
</form>
<hr />
<iframe name="idmy" width="0" height="0" style="visibility:hidden"></iframe>
</body>
</html>

上記、実行環境をまとめたものを置きます。
.NET Framework V4.0が入った環境なら、App_Codeフォルダにソースだけ入れておけば良いのですが、
それ以前の環境だと、binフォルダにコンパイルしたものを入れないと、うまく動きませんでした。
   .NET V4.0以降 (App_Code)
   .NET V3.5以前 (bin)
違いはBuild済みか、そうでないかだけですので実行に違いはありません。

さて、一番問題になる環境構築について説明しますが、
作業したことがある人なら「釈迦に説法」なので、以降は適当に読み飛ばしてください。




Tags: プログラムメモ
続きを読む>>
author : HUNDREDSOFT | - | -