Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8901

Visual Studio 2019のC#・Android環境にて、指定した画像中に任意のファイルを埋め込む。コードのサンプルです。

$
0
0

表題の通り
Visual Studio 2019のC#にて、
Visual Studio 2019のC#にて、直接バイナリを叩いて指定した画像中に任意のファイル情報を埋め込む。
ステガノグラフィーに関する。コードのサンプルでございます。

特段、NuGetなどで他のプラグインや
別途外部dllを必要としないようにしています。

概要

任意のファイルを、画像に埋め込む際に
バイナリを以下のように、直接叩いています。

1.指定した画像のバイナリを一旦すべて読み込む。
2.埋め込む任意のファイルのバイナリも、すべて読み込む。
3.画像の各バイナリを8桁の2進数にして、11111111とのようにする。
4.8桁の2進数の内、下位4桁をバッサリと切り捨て、1111----とのようにする。
5.埋め込むファイルの各バイナリを8桁の2進数にして、00000000とのようにする。
6.8桁の2進数の内、上位4桁と下位4桁に分割して、0000/0000とのようにする。
7.画像の各バイナリを上位4桁の2進数に、
  埋め込むファイルの下位4桁を結合して、11110000とのようにする。
8.上記のように、画像の2バイトにつき、埋め込むファイル1バイトが埋まっていく。
9.埋め込みが終わった画像バイナリから、画像に戻す。
10.可逆圧縮であるpng形式で、出力する。

そして、埋め込んだファイルを取り出す際は、
この逆をしています。

今回は、キリ良く4ビットの深度で埋め込んでいます。
4ビット深度なら、(幅x高さx4)/2 バイトの情報が入ります。
尚、1ビット深度~7ビット深度で、好みの深さで埋め込めます。
深度が浅いほど、容量が減る半面、画像が荒くならないです。
1ビット深度なら、荒さが目立たず、入っているとは、気づきにくいです。

また、今回は、サンプルなので
ARGBすべてのビットに対して埋め込んでいますが、
必要に応じて、必要な部分だけ選択して埋め込むことも可能です。

また、この方法により、
画像しか送受信できない環境や、
exeなど直接メールに添付できないような環境でも、
画像に一旦、埋め込むことで、やり取りすることが可能になります。

ただし、やり取りの過程で画像が加工されたりしてしまうと、
内部の情報が壊れるため、
画像が加工されずに、そのままやり取りできる環境が必要になります。

注意事項

この記事でのコードは、
最低限の記述にとどめているため、解放など不十分な部分や、
記述を省略している箇所があります。

コード中のURLは、参考にさせていただきましたサイト様のものでございます。
勝手ながら、参考にさせていただいたサイト様には、この場にて厚く御礼致します。

下準備

記事本題のC#のコードを使用するために、
下記のxmlレイアウトを使用しています。

GM_world.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:id="@+id/back1"><Buttonandroid:id="@+id/btn1"android:layout_width="match_parent"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/btn2"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>

要は、埋め込み用のボタンと
取り出し用のボタン2つを
下図のように用意致したレイアウトとしております。

本題

標題にある機能のための
Visual Studio 2019 C#での
Android開発環境でのコードは、以下の通りでございます。

MainActivity.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Text;usingAndroid.App;usingAndroid.Content;usingAndroid.Graphics;usingAndroid.OS;usingAndroid.Support.V7.App;usingAndroid.Widget;namespaceApp2{[Activity(Label="@string/app_name",Theme="@style/AppTheme.NoActionBar",MainLauncher=true)]publicclassMainActivity:AppCompatActivity{readonlystringOutput_DirName=Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim).ToString();BitmapBaseImage=null;//基礎側のバイト配列の現在位置を格納intbase_cnt=0;publicasyncSystem.Threading.Tasks.TaskOutput_Sukashi_Bitmap_Making(Android.Net.UrifileUris){//★指定ファイルを画像に埋めて暗号化するところ//出力画像を組み立てるところstringerr_str="0";//どこでエラーになったかを把握するための文字列try{//基礎となる画像のロードif(BaseImage==null){err_str="WebClient";using(System.Net.WebClientwebClient=newSystem.Net.WebClient()){//今回は、ネット空間からDLする。err_str="DownloadDataTaskAsync";byte[]imageBytes=awaitwebClient.DownloadDataTaskAsync(newUri("https://blog-imgs-110.fc2.com/o/y/k/oyk3865b/2017_05_03_290.jpg"));err_str="imageBytes : "+(imageBytes==null);if(imageBytes!=null&&imageBytes.Length>0){err_str="DecodeByteArrayAsync";BaseImage=awaitBitmapFactory.DecodeByteArrayAsync(imageBytes,0,imageBytes.Length);Array.Clear(imageBytes,0,imageBytes.Length);}}}//色設定をARGB8888に統一する。//https://stackoverflow.com/questions/7320392/how-to-draw-text-on-imageAndroid.Graphics.Bitmap.ConfigbitmapConfig=Android.Graphics.Bitmap.Config.Argb8888;BaseImage=BaseImage.Copy(bitmapConfig,true);//Bitmapのバイナリ置き換えの準備//https://qiita.com/aymikmts/items/7139fa6c4da3b57cb4fcerr_str="byteBuffer";Java.Nio.ByteBufferbyteBuffer=Java.Nio.ByteBuffer.Allocate(BaseImage.ByteCount);err_str="CopyPixelsToBuffer";BaseImage.CopyPixelsToBuffer(byteBuffer);err_str="Flip";byteBuffer.Flip();err_str="bmparr";//基礎Bitmapのバイナリへの置き換えbyte[]bmparr=newbyte[byteBuffer.Capacity()];err_str="Get";byteBuffer.Duplicate().Get(bmparr);err_str="Clear";byteBuffer.Clear();//埋め込むファイルの名前の取得stringfilename=Get_FileName_From_Uri(fileUris);//埋め込むファイルのバイナリ格納List<byte>bs=newList<byte>();//埋め込むファイルのバイナリを格納//https://stackoverflow.com/questions/2436385/android-getting-from-a-uri-to-an-inputstream-to-a-byte-array/2436413err_str="Err_3 "+filename;using(StreaminputStream=ContentResolver.OpenInputStream(fileUris)){err_str="Err_4 "+filename;intbufferSize=1024;using(Java.IO.BufferedInputStreamstream=newJava.IO.BufferedInputStream(inputStream,bufferSize)){//ファイルを開くintlen=0;//読み込み用バッファの準備//https://stackoverflow.com/questions/2436385/android-getting-from-a-uri-to-an-inputstream-to-a-byte-array/2436413byte[]buffer=newbyte[bufferSize];//ファイルを読み込む//http://d.hatena.ne.jp/curest/20090829/1251532479err_str="Err_5 "+filename;while((len=stream.Read(buffer,0,buffer.Length))!=-1){if(len<=0){break;}//終端で出る  elseif(len==bufferSize){//1024満願の場合bs.AddRange(buffer);//埋め込むデータのバイナリをそのまま全てリストに読み込む}else{//終端手前の場合byte[]temp_buf=newbyte[len];Array.Copy(buffer,0,temp_buf,0,len);bs.AddRange(temp_buf);//埋め込むデータのバイナリを必要分だけリストに読み込むArray.Clear(temp_buf,0,temp_buf.Length);}}//閉じるerr_str="Err_6 "+filename;stream.Close();}err_str="Err_7 "+filename;inputStream.Close();}//冒頭には、埋め込んだファイル情報を入れるbyte[]name_data=Encoding.UTF8.GetBytes(filename);//名前のサイズ4バイトbyte[]size_data=BitConverter.GetBytes((Int32)name_data.Length);//基礎の埋め込み開始位置の初期化base_cnt=0;//※※※今回は、下位4ビットに埋め込んでいくとする。※※※//→つまり、4バイト埋めるのには、2倍の8バイト領域が必要err_str="埋め込んでいく";for(inti=0;i<(size_data.Length);i++){data_umekomi(refbmparr[base_cnt],refbmparr[base_cnt+1],size_data[i]);}//続いて、名前バイナリを埋め込むerr_str="name_data";for(inti=0;i<(name_data.Length);i++){data_umekomi(refbmparr[base_cnt],refbmparr[base_cnt+1],name_data[i]);}//いったん初期化err_str="Array.Clear";Array.Clear(size_data,0,size_data.Length);//次に、埋め込むファイル本体のサイズerr_str="BitConverter.GetBytes";size_data=BitConverter.GetBytes((Int32)bs.Count);err_str="size_data";for(inti=0;i<(size_data.Length);i++){data_umekomi(refbmparr[base_cnt],refbmparr[base_cnt+1],size_data[i]);}//埋め込み側のバイナリ本体を埋め込むerr_str="byteary.Length";for(inti=0;i<(bs.Count);i++){//安全装置if(base_cnt+1>bmparr.Length-1){Toast.MakeText(Application.Context,"埋め込められる容量 "+i.ToString()+"B を超えました。",ToastLength.Long).Show();break;}data_umekomi(refbmparr[base_cnt],refbmparr[base_cnt+1],bs[i]);}//string check_filepath = System.IO.Path.Combine(Output_DirName, "check1.txt");//await System.IO.File.WriteAllBytesAsync(check_filepath, bs.ToArray());//set_SendBroadcast_state(check_filepath);bs.Clear();//最後に適当に乱数を埋めるerr_str="System.Random()";System.Randomrnd=newSystem.Random();//乱数を配列に埋め込むArray.Clear(size_data,0,size_data.Length);size_data=newbyte[bmparr.Length-base_cnt];rnd.NextBytes(size_data);for(inti=0;i<(size_data.Length);i++){//安全装置       if(base_cnt+1>bmparr.Length-1){break;}data_umekomi(refbmparr[base_cnt],refbmparr[base_cnt+1],size_data[i]);}//埋め込んだバイナリを再びBitmapに戻す準備err_str="CreateBitmap";Bitmapbitmap=Bitmap.CreateBitmap(BaseImage.Width,BaseImage.Height,bitmapConfig);//埋め込んだバイナリを再びBitmapに戻すerr_str="Wrap";byteBuffer=Java.Nio.ByteBuffer.Wrap(bmparr);err_str="CopyPixelsFromBuffer";bitmap.CopyPixelsFromBuffer(byteBuffer);//埋め込み前画像の解放BaseImage.Recycle();BaseImage.Dispose();BaseImage=null;//解放byteBuffer.Clear();byteBuffer.Dispose();//出来上がった画像の保存パスの作成err_str="bitmap_save "+(bitmap==null)+" "+bmparr.Length;//+ " " + byteBuffer.Capacity();stringfilepath=System.IO.Path.Combine(Output_DirName,"kikikanri.png");//出来上がった画像の保存出力err_str="bitmap_save";bitmap_save(bitmap,filepath,true,this);//出来上がった画像を開くerr_str="open_start_file";open_start_file(filepath,this);//できた画像の解放bitmap.Recycle();bitmap.Dispose();Array.Clear(bmparr,0,bmparr.Length);}catch{//エラー時の表示Toast.MakeText(Application.Context,err_str,ToastLength.Long).Show();}}publicasyncSystem.Threading.Tasks.TaskInput_Sukashi_Bitmap_Making(Android.Net.UrifilePath){//★埋めたファイルを復号するところstringerr_str="Input_Sukashi_Bitmap_Making";try{//指定した画像を開くerr_str="DecodeStream";Bitmapbitmap=null;using(varinputStream=ContentResolver.OpenInputStream(filePath)){// URI指定の場合//http://www.united-bears.co.jp/blog/archives/909bitmap=BitmapFactory.DecodeStream(inputStream,null,null);inputStream.Close();}//Bitmapのバイナリ置き場の準備//https://qiita.com/aymikmts/items/7139fa6c4da3b57cb4fcerr_str="byteBuffer3";Java.Nio.ByteBufferbyteBuffer=Java.Nio.ByteBuffer.Allocate(bitmap.ByteCount);err_str="CopyPixelsToBuffer3 "+(bitmap==null)+" "+bitmap.ByteCount;bitmap.CopyPixelsToBuffer(byteBuffer);err_str="Flip3";byteBuffer.Flip();err_str="bmparr3";//基礎Bitmapのバイナリの格納byte[]bmparr=newbyte[byteBuffer.Capacity()];err_str="Get3";byteBuffer.Duplicate().Get(bmparr);err_str="Clear3";byteBuffer.Clear();bitmap.Recycle();bitmap.Dispose();//埋め込むファイルのバイナリ格納用リストerr_str="List<byte>";List<byte>bs=newList<byte>();//各初期化bs.Clear();base_cnt=0;err_str="名前のサイズを取得";do{//まずは、埋め込んだファイルの名前のサイズを取得[Int32 = s4バイト固定]bs.Add(data_toridashi(bmparr[base_cnt],bmparr[base_cnt+1]));}while(bs.Count<4);//4バイト貯まるまでループerr_str="名前領域の取り出し";Int32data_size=BitConverter.ToInt32(bs.ToArray());bs.Clear();do{//埋め込んだファイルの名前を取得bs.Add(data_toridashi(bmparr[base_cnt],bmparr[base_cnt+1]));}while(bs.Count<data_size);//先に取得したサイズまでループ//UTF8にてバイナリを文字列に戻すerr_str="出力先パスの完成";stringload_filepath=System.Text.Encoding.UTF8.GetString(bs.ToArray());load_filepath=System.IO.Path.Combine(Output_DirName,load_filepath);err_str="本体バイナリのサイズを取得";bs.Clear();do{//埋め込んだファイルのサイズの取得[4バイト固定]bs.Add(data_toridashi(bmparr[base_cnt],bmparr[base_cnt+1]));}while(bs.Count<4);data_size=BitConverter.ToInt32(bs.ToArray());err_str="本体バイナリの取得";bs.Clear();do{//埋め込んだファイルのバイナリの取得bs.Add(data_toridashi(bmparr[base_cnt],bmparr[base_cnt+1]));if(bs.Count==data_size){break;}}while(bs.Count<data_size);//先に取得したファイルサイズが貯まるまで周回//string check_filepath = System.IO.Path.Combine(Output_DirName, "check2.txt");//await System.IO.File.WriteAllBytesAsync(check_filepath, bs.ToArray());//set_SendBroadcast_state(check_filepath);err_str="ファイルに書き出す";awaitSystem.IO.File.WriteAllBytesAsync(load_filepath,bs.ToArray());bs.Clear();//復号したファイルを開くerr_str="open_start_file3";open_start_file(load_filepath,this);//復号したファイルをPCからも見えるようにする。err_str="set_SendBroadcast_state3";set_SendBroadcast_state(load_filepath);}catch{//エラー時の表示Toast.MakeText(Application.Context,err_str,ToastLength.Long).Show();}}publicstringGet_FileName_From_Uri(Android.Net.Uriuri){//Uriから、ファイルバスを取得する。//https://qiita.com/CUTBOSS/items/3476e164b86a63b02b2e//安全装置if(null==uri){returnnull;}//スキームの取得stringscheme=uri.Scheme;//スキームによる分岐stringfileName=null;switch(scheme){case"content":String[]projection={Android.Provider.MediaStore.MediaColumns.DisplayName};Android.Database.ICursorcursor=this.ContentResolver.Query(uri,projection,null,null,null);if(cursor!=null){if(cursor.MoveToFirst()){fileName=cursor.GetString(cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.MediaColumns.DisplayName));}cursor.Close();}break;case"file":fileName=newJava.IO.File(uri.Path).Name;break;default:break;}returnfileName;}privatevoiddata_umekomi(refbytebase1,refbytebase2,byteumekomi_byte){//指定されたバイト数値にデータを埋め込む所 //基礎画像の下位4ビットをカットする。stringbase1_str=Convert.ToString(base1,2).PadLeft(8,'0');//8桁の二進数にする。base1_str=base1_str.Substring(0,4);//上位4ビットのみ取得。stringbase2_str=Convert.ToString(base2,2).PadLeft(8,'0');//8桁の二進数にする。base2_str=base2_str.Substring(0,4);//上位4ビットのみ取得。//空いた下位4ビットにデータを埋め込むstringumekomi_str=Convert.ToString(umekomi_byte,2).PadLeft(8,'0');//8桁の二進数にする。base1_str=base1_str+umekomi_str.Substring(0,4);//下位4ビットに埋め込むbase1=Convert.ToByte(base1_str,2);//2進数からbyteに変換base2_str=base2_str+umekomi_str.Substring(4,4);//下位4ビットに埋め込むbase2=Convert.ToByte(base2_str,2);//2進数からbyteに変換//基礎側のバイナリは2つ進むbase_cnt+=2;}privatebytedata_toridashi(bytebase1,bytebase2){//指定されたバイト数値からデータを取り出す所 //基礎画像の上位4ビットをカットする。stringbase1_str=Convert.ToString(base1,2).PadLeft(8,'0');//8桁の二進数にする。base1_str=base1_str.Substring(4,4);//下位4ビットのみ取得。stringbase2_str=Convert.ToString(base2,2).PadLeft(8,'0');//8桁の二進数にする。base2_str=base2_str.Substring(4,4);//下位4ビットのみ取得。//空いた下位4ビットにデータを埋め込むstringtoridashi_str=base1_str+base2_str;//基礎側のバイナリは2つ進むbase_cnt+=2;returnConvert.ToByte(toridashi_str,2);//2進数からbyteに変換}publicvoidbitmap_save(Bitmapbitmap,stringfilePath,boolSendBroadcast_flg,Activityac){//指定場所に画像の保存try{if(!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(filePath))){//保存先フォルダがない場合//作るSystem.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));}if(bitmap.Width<=0||bitmap.Height<=0){//大きさのない画像の場合return;//出る}//ファイル書き込みusing(System.IO.FileStreamfos=System.IO.File.Create(filePath)){if(System.IO.Path.GetExtension(filePath).ToLower()==".jpg"||System.IO.Path.GetExtension(filePath).ToLower()==".tmp"){//JPEG保存の場合bitmap.Compress(Bitmap.CompressFormat.Jpeg,100,fos);}elseif(System.IO.Path.GetExtension(filePath).ToLower()==".png"){//PNG保存の場合bitmap.Compress(Bitmap.CompressFormat.Png,100,fos);}else{bitmap.Compress(Bitmap.CompressFormat.Webp,100,fos);}fos.Close();};//PCからも見られるように設定する場合。if(SendBroadcast_flg&&(System.IO.Path.GetExtension(filePath).ToLower()!=".tmp")){//一時ファイルでない場合set_SendBroadcast_state(filePath);}//↓★ここで解放してはならない//bitmap.Dispose();}catch{}}publicvoidset_SendBroadcast_state(stringOutput_Path){//PCからも見られるように設定する。//https://qiita.com/wasnot/items/ae1e6282d2c33626b604//https://developer.xamarin.com/api/member/Android.Content.Context.SendBroadcast/p/Android.Content.Intent///https://bluefish.orz.hm/sdoc/android_file.html#%E6%96%B0%E8%A6%8F%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E4%BD%9C%E6%88%90try{if(System.IO.File.Exists(Output_Path)){//安全措置using(Java.IO.Filej_file=newJava.IO.File(Output_Path)){Android.Net.Uriuri=Android.Net.Uri.FromFile(j_file);IntentmediaScanIntent=newIntent(Intent.ActionMediaScannerScanFile,uri);Application.Context.SendBroadcast(mediaScanIntent);mediaScanIntent.Dispose();uri.Dispose();}}}catch{}}publicvoidopen_start_file(stringfilepath,Activityac){//指定のファイルを開くinterr_flg=0;try{//ファイルが存在するかの確認if(System.IO.File.Exists(filepath)){err_flg=100;stringapplication="image/jpeg";//初期は画像Android.Net.Uriuri;using(Java.IO.Filefile=newJava.IO.File(filepath)){file.SetReadable(true);err_flg=103;if(System.IO.Path.GetExtension(filepath).ToLower().Contains(".pdf")){//PDFの場合application="application/pdf";}elseif(System.IO.Path.GetExtension(filepath).ToLower().Contains(".zip")){//zipの場合application="application/zip";}elseif(System.IO.Path.GetExtension(filepath).ToLower().Contains(".xlsx")){//xlsxの場合//https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_typesapplication="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";}elseif(System.IO.Path.GetExtension(filepath).ToLower().Contains(".ods")){//odsの場合application="application/vnd.oasis.opendocument.spreadsheet";}elseif(System.IO.Path.GetExtension(filepath).ToLower().Contains(".png")){//pngの場合application="image/png";}err_flg=1;// ストレージとカメラの権限の確認if(Build.VERSION.SdkInt>=BuildVersionCodes.M){//Android6.0以上の場合//作ったファイルを開きたい//https://www.petitmonte.com/java/android_fileprovider.html//https://stackoverflow.com/questions/40462245/fileprovider-xamarin-not-displaying-file//https://stackoverflow.com/questions/50072057/android-proper-way-to-share-public-files-between-appserr_flg=100;uri=Android.Support.V4.Content.FileProvider.GetUriForFile(Application.Context,Application.Context.PackageName+".provider",file);err_flg=101;Intentintent=newIntent(Intent.ActionView);intent.SetDataAndType(uri,application);intent.SetFlags(ActivityFlags.NoHistory);intent.SetFlags(ActivityFlags.GrantReadUriPermission);err_flg=102;Intentintent2=Intent.CreateChooser(intent,"Open File");if(intent2.ResolveActivity(ac.PackageManager)!=null){err_flg=103;Application.Context.StartActivity(intent2);}else{//開けるファイルがない場合Toast.MakeText(Application.Context,"この環境には、"+System.IO.Path.GetExtension(filepath).ToLower()+"形式ファイルを開けるアプリがありません。"+Convert.ToChar(13)+Convert.ToChar(10)+"アプリをインストールするか、他の環境で開いてください。",ToastLength.Long).Show();}}else{//Android6.0未満の場合uri=Android.Net.Uri.FromFile(file);Intentintent=newIntent(Intent.ActionView);err_flg=2;intent.SetDataAndType(uri,application);intent.SetFlags(ActivityFlags.NoHistory);intent.SetFlags(ActivityFlags.ClearWhenTaskReset|ActivityFlags.NewTask);err_flg=4;//ちゃんと開けるアプリがあるのかを確認//https://developer.android.com/guide/components/intents-filters?hl=jaif(intent.ResolveActivity(ac.PackageManager)!=null){err_flg=5;//実行Application.Context.StartActivity(intent);}else{//開けるファイルがない場合Toast.MakeText(Application.Context,"この環境には、"+System.IO.Path.GetExtension(filepath).ToLower()+"形式ファイルを開けるアプリがありません。"+Convert.ToChar(13)+Convert.ToChar(10)+"アプリをインストールするか、他の環境で開いてください。",ToastLength.Long).Show();}}}}}catch{//エラー時は無視Toast.MakeText(Application.Context,"エラー発生:"+err_flg.ToString(),ToastLength.Long).Show();}}//権限がなければ上がるboolno_Permission_flg=false;protectedoverridevoidOnCreate(BundlesavedInstanceState){base.OnCreate(savedInstanceState);// Set our view from the "main" layout resourceSetContentView(Resource.Layout.activity_main);// ストレージ権限の確認try{if(Build.VERSION.SdkInt>=BuildVersionCodes.M){//Android6.0以上の場合のみstring[]Manifest_Permissions={Android.Manifest.Permission.WriteExternalStorage,Android.Manifest.Permission.ReadExternalStorage,Android.Manifest.Permission.Internet};//各権限をループforeach(System.StringPermission_strinManifest_Permissions){//https://docs.microsoft.com/ja-jp/xamarin/android/app-fundamentals/permissions?tabs=windows//https://www.petitmonte.com/java/android_fileprovider.htmlif(ApplicationContext.CheckCallingOrSelfPermission(Permission_str)!=Android.Content.PM.Permission.Granted){//許可されていない場合no_Permission_flg=true;// ストレージの権限の許可を求めるダイアログを表示するif(Android.Support.V4.App.ActivityCompat.ShouldShowRequestPermissionRationale(this,Permission_str)){//Android.Support.V4.App.ActivityCompat.RequestPermissions(this,//        new string[] { Permission_str }, (int)Android.Content.PM.RequestedPermission.Required);Android.Support.V4.App.ActivityCompat.RequestPermissions(this,Manifest_Permissions,(int)Android.Content.PM.RequestedPermission.Required);}else{Toasttoast=Toast.MakeText(ApplicationContext,"アプリ実行の権限が必要です",ToastLength.Long);toast.Show();Android.Support.V4.App.ActivityCompat.RequestPermissions(this,Manifest_Permissions,(int)Android.Content.PM.RequestedPermission.Required);}}}}Buttonbtn1=FindViewById<Button>(Resource.Id.btn1);btn1.Text="ファイル埋め込み";btn1.Click+=delegate{if(!no_Permission_flg){//権限がなければ無効//https://developer.xamarin.com/recipes/android/data/files/selecting_a_gallery_image/using(IntentimageIntent=newIntent(Intent.ActionGetContent)){//埋め込みファイル選択imageIntent.SetType("*/*");//複数画像選択可能で固定//https://stackoverflow.com/questions/19585815/select-multiple-images-from-android-galleryimageIntent.PutExtra(Intent.ExtraAllowMultiple,false);imageIntent.SetAction(Intent.ActionGetContent);StartActivityForResult(Intent.CreateChooser(imageIntent,"画像に埋め込むファイルを選択してください。"),0);}}};Buttonbtn2=FindViewById<Button>(Resource.Id.btn2);btn2.Text="ファイル取り出し";btn2.Click+=delegate{if(!no_Permission_flg){//権限がなければ無効//https://developer.xamarin.com/recipes/android/data/files/selecting_a_gallery_image/using(IntentimageIntent=newIntent(Intent.ActionGetContent)){//埋め込みファイル選択imageIntent.SetType("image/png");//複数画像選択可能で固定//https://stackoverflow.com/questions/19585815/select-multiple-images-from-android-galleryimageIntent.PutExtra(Intent.ExtraAllowMultiple,false);imageIntent.SetAction(Intent.ActionGetContent);StartActivityForResult(Intent.CreateChooser(imageIntent,"埋め込んだ画像ファイルを選択してください。"),1);}}};}catch{}}protectedoverrideasyncvoidOnActivityResult(intrequestCode,ResultresultCode,Intentdata){base.OnActivityResult(requestCode,resultCode,data);stringerr_str="0";LinearLayoutback1=FindViewById<LinearLayout>(Resource.Id.back1);try{if(requestCode==0||requestCode==1){//◆◆◆以下、画像選択時のイベント◆◆◆if(resultCode==Result.Ok){//OK(ズドン)//複数画像を選択した場合。back1.SetBackgroundColor(Color.Indigo);awaitSystem.Threading.Tasks.Task.Delay(5);//URIの記憶//サムネイルにしたい画像のURIの格納Android.Net.Uriselected_fileuri=null;//初期化err_str="selected_fileuris.Clear";if(data.ClipData!=null){//複数選択された場合if(data.ClipData.ItemCount>0){selected_fileuri=data.ClipData.GetItemAt(0).Uri;}}elseif(data.Data!=null){//1つだけの選択時selected_fileuri=data.Data;}err_str="selected_fileuri";//ポジフィルムの作成時if(requestCode==0){//URI指定の場合awaitOutput_Sukashi_Bitmap_Making(selected_fileuri);}else{//今度は、埋め込んだファイルを復号する。awaitInput_Sukashi_Bitmap_Making(selected_fileuri);}back1.SetBackgroundColor(Color.Ivory);awaitSystem.Threading.Tasks.Task.Delay(5);}}}catch{//全体を通しての、エラー時Android.Widget.Toast.MakeText(Application.Context,err_str,Android.Widget.ToastLength.Long).Show();}}}}

なお、埋め込んだファイルが確実に復号できているかを確認するために
CRC-32等のハッシュ値を併せて埋め込んでおくと、より確実に思います。

サンプル

上記のコードで、
画像に、私作成であり
Vector様のサイトで公開している
『オフタイマー弐式』という、
Windowsソフトの、exeファイルを
埋め込んでおります。

exeファイルは、直接だったり
zipに圧縮してメールでやり取りしようとしても、
セキュリティにて、止められたりしますが

画像に埋め込んであるので
途中で加工さえされなければ、
そこは、すり抜けます。

人に見られたくないファイルの
保存にも向きますが、

消えると困る大切なファイルの埋め込みには向かないと
私は感じております。


Viewing all articles
Browse latest Browse all 8901

Trending Articles