[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