[WinRT] デスクトップで閲覧しているURLをSurface RTに送る – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4718
[WinRT] Surface RT で閲覧しているURLをデスクトップに送る – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4723
送るシリーズの第3弾…って訳ではないですが、メモ的に。
Surface RTからURLをデスクトップに送る仕組みを応用して、画像ファイルを送ります。ここではWindows RT標準装備の「フォト」で共有した場合。他にも SkyDrive をやってみたいのですが、これは方式が違うのでまた別途ソースを書きおこします。内部動作が違っても、表面的な UI は同じほうがいいですからね。
■Surface から共有させる
マニフェストの宣言で「サポートされるファイルの種類」を増やしておきます。ここでは、画像ファイルしか扱わないので、まめに「.jpeg」とか書いていきます。「すべてのファイルの種類をサポートする」にチェックを入れてもokなんですが、なんかの理由付けがないと審査で落ちそうな感じがするし、まあ用途としては制限させたほうがいいので。
共有しているところの、ShareTargetPage.xaml.cs を書き換えます。
フォトからは StandardDataFormats.StorageItems を使って送られてくるので、これで受け取り。複数のファイルが送れるのですが、今回は最初の1枚だけを対象に。
public async void Activate(ShareTargetActivatedEventArgs args)
{
this._shareOperation = args.ShareOperation;
...略
if (this._shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
Debug.WriteLine("contain StorageItems");
var files = await this._shareOperation.Data.GetStorageItemsAsync();
foreach (StorageFile f in files)
{
Debug.WriteLine("name: {0}", f.Path);
}
}
}
画像転送は、HTTPのPUTを使ってBASE64で送ります。このあたりは先行きXMLシリアライズを使うつもりなので、ざっと書き下し。バイト配列とのコンバートは、慣れると…とはいえ慣れても面倒なのですが、この通りに各と動きます。
private async void ShareButton_Click(object sender, RoutedEventArgs e)
{
this.DefaultViewModel["Sharing"] = true;
this._shareOperation.ReportStarted();
// TODO: this._shareOperation.Data を使用して共有シナリオに適した
// 作業を実行します。通常は、カスタム ユーザー インターフェイス要素を介して
// このページに追加されたカスタム ユーザー インターフェイス要素を介して
// this.DefaultViewModel["Comment"]
...略
if (this._shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
var files = await this._shareOperation.Data.GetStorageItemsAsync();
var file = files[0] as StorageFile;
// 画像データを転送
var stream = await file.OpenReadAsync();
using (var mem = new MemoryStream())
{
var rs = stream.AsStreamForRead();
await rs.CopyToAsync(mem);
byte[] data = mem.ToArray();
string url = "http://mars:8090/PutImage";
HttpClient cl = new HttpClient();
string b64 = System.Convert.ToBase64String(data);
StringContent cont = new StringContent(b64);
var res = await cl.PutAsync( url, cont );
}
}
this._shareOperation.ReportCompleted();
}
}
c# – WinRT image handling – Stack Overflow
http://stackoverflow.com/questions/10013799/winrt-image-handling
DataPackageView.GetStorageItemsAsync | getStorageItemsAsync Method (Windows)
http://msdn.microsoft.com/ja-jp/library/windows/apps/windows.applicationmodel.datatransfer.datapackageview.getstorageitemsasync
このあたりを読んで、まめに実装するがよいかと。
■デスクトップで画像を受ける
Listener のタスクが長くなってきたので、別関数にくくりだし。Task の中からは GUI コントロールを直接さわれないので、Invoke を使います。いろいろやってこれが簡単な方法かと。
画像ファイルは、BASE64 からバイナリ配列に直して Bitmap を作るという手順です。このあたりの流れは、適度に隠蔽化してしまうと楽になると思います。
private void Form1_Load(object sender, EventArgs e)
{
listener = new HttpListener();
listener.Prefixes.Add("http://*:8090/");
listener.Start();
// 受信待ちタスク
Task tsk = new Task( ListenLoop );
tsk.Start();
}
async void ListenLoop()
{
while (true)
{
var cont = listener.GetContext();
var req = cont.Request;
var res = cont.Response;
if (req.RawUrl.StartsWith("/GetUrl"))
{
Debug.WriteLine(string.Format("req {0}", req.RawUrl));
var tw = new StreamWriter(res.OutputStream);
tw.Write(_text);
tw.Close();
res.Close();
}
else if (req.RawUrl.StartsWith("/PutUrl") == true)
{
Debug.WriteLine(string.Format("req {0}", req.RawUrl));
var text = req.RawUrl.Replace("/PutUrl/", "");
text = System.Uri.UnescapeDataString(text);
// textBox1.Text = text;
textBox1.Invoke((MethodInvoker)(() => textBox1.Text = text));
var tw = new StreamWriter(res.OutputStream);
tw.Write("OK");
tw.Close();
res.Close();
}
else if (req.RawUrl.StartsWith("/PutImage") == true)
{
// 画像をBASE64で受け取る
Debug.WriteLine(string.Format("req {0}", req.RawUrl));
var st = req.InputStream;
var sr = new StreamReader(st);
string b64 = await sr.ReadToEndAsync();
byte[] data = System.Convert.FromBase64String(b64);
var mem = new MemoryStream(data);
Bitmap bmp = new Bitmap(mem);
// pictureBox1.Image = bmp;
pictureBox1.Invoke((MethodInvoker)(() => pictureBox1.Image =bmp ));
var tw = new StreamWriter(res.OutputStream);
tw.Write("OK");
tw.Close();
res.Close();
}
else
{
var tw = new StreamWriter(res.OutputStream);
tw.Write("ERROR");
tw.Close();
res.Close();
}
}
}
■動かしてみる
フォトから共有させて、
フォームアプリに転送するだけです。

そのままファイルに保存してもいいし、Clipboard.SetImage(pictureBox1.Image) な風にしてい、クリップボードに送るのもいいでしょう。
■サンプルソース
サンプルソースはこちら。
http://sdrv.ms/10mK1ch


