質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

1回答

4819閲覧

画像表示後にドラッグ&ドロップで四角形選択時に画像が消えてしまう。

dendenmushi

総合スコア98

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2019/06/05 12:38

編集2019/06/06 07:39

前提・実現したいこと

C#Windowsformデスクトップアプリ内に、ローカル画像をドラッグ&ドロップ(以下D&D)で運んで表示したあとに、その表示された画像の上でD&Dで四角を任意選択して画像を切り取り保存をしたいです。

環境:windows10 64bit
開発ツール:Visual Studio 2017 community
言語:C#(windows Forms visual C#)
イメージ説明

発生している問題・エラーメッセージ

画像をローカルからD&Dでアプリ側で表示し、その上でD&Dをした際に四角形は出現して枠組みまではできますが、その際に下の表示されている画像が消えてしまいます。

###コード
わかりづらくなってしまうので当初のpicturebox2つ使おうとしていたコードは削除しました。

試したこと

paintイベントの中にgraphics含め描画のメソッドを入れていくことも行いましたが、paintの外側にあるマウスダウンイベントなどの中でメソッド呼び込みをどうしたらよいかわからず、そもそもpaintイベントの中にマウスイベントじたいも入れ込まなければいけないのかいろいろなサイトや書籍(C#)を見てますが、解決できませんでした。
参考サイト:
PictureBoxに線が描けません。
ラバーランドでのドラッグ範囲の切り抜き
基本描画画像が消える
イメージプロパティによくある勘違い

pictureboxを2つ重ねて上側を透過trancerateをbackcolorを選択しても四角形描画が始まるとはじめの画像表示は消えてしまいました。
あと試していない(できなかった)のはpictureboxを2つ作り、親子の関係にして上のを透過させる方法です。
最終的には四角形で切り抜き保存までを行いたいだけです。
かなり苦戦しております。どなたかご教授頂けないでしょうか。

###その後試したこと
親子関係を作りpicturebox2の方を透過で四角を描けるようにしました。

C#

1 public Form1() 2 { 3 InitializeComponent(); 4 //プロパティの設定変更 5 pictureBox1.AllowDrop = true; 6 //描画先とするImageオブジェクトを作成する 7 bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height); 8 9 pictureBox2.BackColor = Color.Transparent; 10 pictureBox2.Parent = pictureBox1; 11 pictureBox2.Location = new Point(0, 0); 12 13 }

それでも画像の方は四角指定の際のD&Dで消えてしまいました。

###現状(令和元年6月6日)
デザイン…picture1の上にあえてpicture2をずらして上に置いています。テストのため。
イメージ説明
ドラッグ中…はじめに置いた画像picture1がpicture2が出てきたことで上半分欠ける(子の透過ができていない)
イメージ説明
ドロップ後…四角形は最終的に目当てと違う場所に残ったが意図しない場所(picuture2だが座標がおかしい)
イメージ説明

###6月6日16時の時点での現状
・なんとか元画像の上に四角枠を表示することができました。ありがとうございます。
・残りの課題は、四角の表示される位置が非常にずれています。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Drawing; 6using System.Drawing.Imaging; 7using System.IO; 8using System.Linq; 9using System.Text; 10using System.Threading.Tasks; 11using System.Windows.Forms; 12 13 14namespace WindowsFormsApp_20190604 15{ 16 public partial class Form1 : Form 17 { 18 Point MD = new Point(); 19 Point MU = new Point(); 20 Bitmap bmp; 21 Bitmap backgroundBitmap;//20190605 22 Bitmap offscreenBitmap; 23 bool view = false; 24 25 26 public Form1() 27 { 28 InitializeComponent(); 29 //プロパティの設定変更 30 pictureBox1.AllowDrop = true; 31 //描画先とするImageオブジェクトを作成する 32 bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height); 33 } 34 private void pictureBox1_DragDrop(object sender, DragEventArgs e) 35 { 36 string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false); 37 for (int i = 0; i < files.Length; i++) 38 { 39 string fileName = files[i]; 40 41 string filename = ((string[])e.Data.GetData(DataFormats.FileDrop))[0]; 42 backgroundBitmap = new Bitmap(filename); 43 offscreenBitmap = new Bitmap(backgroundBitmap);//tuika15 44 45 46 Console.WriteLine("offscreenBitmap:" + offscreenBitmap); 47 48 //表示方法をzoomにする 49 pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; 50 51 pictureBox1.Image = offscreenBitmap; 52 } 53 } 54 55 private void pictureBox1_DragEnter(object sender, DragEventArgs e) 56 { 57 if (e.Data.GetDataPresent(DataFormats.FileDrop)) 58 e.Effect = DragDropEffects.Copy; 59 } 60 61 private void GetRegion(Point p1, Point p2, ref Point start, ref Point end) 62 { 63 start.X = Math.Min(p1.X, p2.X); 64 start.Y = Math.Min(p1.Y, p2.Y); 65 66 end.X = Math.Max(p1.X, p2.X); 67 end.Y = Math.Max(p1.Y, p2.Y); 68 } 69 70 private int GetLength(int start, int end) 71 { 72 return Math.Abs(start - end); 73 } 74 75 private void DrawRegion(Point start, Point end) 76 { 77 Pen blackPen = new Pen(Color.Black); 78 Console.WriteLine(bmp); 79 Console.WriteLine(offscreenBitmap); 80 81 Graphics g = Graphics.FromImage(offscreenBitmap); 82 83 // 描画する線を点線に設定 84 blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; 85 86 // 画面を消去 87 g.Clear(SystemColors.Control); 88 89 g.DrawRectangle(blackPen, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y)); 90 91 g.Dispose(); 92 } 93 94 private void pictureBox1_MouseDown(object sender, MouseEventArgs e) 95 { 96 // 描画フラグON 97 view = true; 98 99 // Mouseを押した座標を記録 100 MD.X = e.X; 101 MD.Y = e.Y; 102 } 103 104 private void pictureBox1_MouseMove(object sender, MouseEventArgs e) 105 { 106 107 Point p = new Point(); 108 Point start = new Point(); 109 Point end = new Point(); 110 111 // 描画フラグcheck 112 if (view == false) 113 { 114 return; 115 } 116 117 // カーソルが示している場所の座標を取得 118 p.X = e.X; 119 p.Y = e.Y; 120 121 // 座標から(X,Y)座標を計算 122 GetRegion(MD, p, ref start, ref end); 123 124 // 領域を描画 125 DrawRegion(start, end); 126 127 //backの画像表示方法指定 128 pictureBox1.BackgroundImageLayout = ImageLayout.Zoom; 129 //初めにとっておいた背景bitmapを表示 130 pictureBox1.BackgroundImage = backgroundBitmap; 131 //bitmapの透過 132 offscreenBitmap.MakeTransparent(); 133 134 //Imageを表示 135 pictureBox1.Image = offscreenBitmap; 136 } 137 138 private void pictureBox1_MouseUp(object sender, MouseEventArgs e) 139 { 140 141 Point start = new Point(); 142 Point end = new Point(); 143 144 145 // Mouseを離し た座標を記録 146 MU.X = e.X; 147 MU.Y = e.Y; 148 149 // 座標から(X,Y)座標を計算 150 GetRegion(MD, MU, ref start, ref end); 151 152 // 領域を描画 153 DrawRegion(start, end); 154 155 //PictureBox1に表示する 156 157 // 描画フラグOFF 158 view = false; 159 } 160 } 161}

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Q71

2019/06/06 06:54

本文に書かれていることが非常にわかりにくいです。やったことは、短文で書く様にして見てください。 pictureBox2は、なんのためにありますか?
dendenmushi

2019/06/06 07:19

すいません。今現在の状態を再アップします。pictureboxは下記アドバイスによりひとつにまとめました。
guest

回答1

0

ベストアンサー

こんにちは。
検証していないのでいい加減な内容になってしまいますが参考までに。

ドラッグ&ドロップした画像のBitmapは未加工のままメンバに取っておいてください(orgBitmap等)。
それとは別にpictureboxと同じサイズのBitmapを用意しておきます(canvasBitmap等)。

で、pitureboxには何かある度に

①canvasBitmapをクリア
②canvasBitmapにorgBitmapを描画
③canvasBitmapにトリミング用の枠を描画(なければ何もしない)
④pitureboxにcanvasBitmapを表示

・・・というようにしてみてください。

②のときアスペクト比や表示倍率の計算をしっかりやらないと、いざトリミングするときのピクセル座標がわけわからないことになりますので、その点だけご注意ください。

投稿2019/06/06 01:06

編集2019/06/06 07:10
takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dendenmushi

2019/06/06 02:44

回答頂き感謝します。これはpictureboxはひとつで完結しているお話でしょうか。その中にBitmapをGraphic表示するというものを2つ作り、1つは元々の、2つ目は描画する際に1つ目を描画してから四角形を描画という認識で間違えないでしょうか。
takabosoft

2019/06/06 04:02

そんな認識で合ってます。
dendenmushi

2019/06/06 06:31

string filename = "~ディレクトリパス"; backgroundBitmap = new Bitmap(filename); Bitmap offscreenBitmap = new Bitmap(backgroundBitmap); pictureBox1.Image = offscreenBitmap; Graphics g = Graphics.FromImage(offscreenBitmap); このようにbackgroundBitmapとして保存しつつ、offscreenBitmapを表示してから、そこにGraphicで四角形を書くように変えたのですが、画像を置いた後に中でダブルクリックすると透過されていないbitmapで上書きされて画像が見えなくなってしまうようです…
takabosoft

2019/06/06 07:14 編集

それをやるなら、何か画面を更新するときには g.Clear() gにoffscreenBitmapを描画 gにラバーバンドを描画 pictureBox1更新 という手順を踏んでください。
dendenmushi

2019/06/06 07:21

ありがとうございます。なんとか上に四角枠を描画することができました。…がしかしめちゃくちゃ座標がずれています…pictureにD&Dした際に、そのImage幅でbitmapの大きさを指定しているためだと今のところは思っています。なんとか合わせないとですね…。今最新のコードアップします。
dendenmushi

2019/06/06 07:57

>②のときアスペクト比や表示倍率の計算をしっかりやらない takabosoftさんのおっしゃるとおりその倍率の関係でしょうか。表示されている四角が異様にずれて表示されています…
takabosoft

2019/06/06 08:17

今の作りだと、PictureBoxが画像の位置を勝手にレイアウトしたり縮小したりすると思うので(?)、その位置&倍率とマウスでクリックした座標がさっぱり一致しないと思います。 なので、私のおすすめとしては回答欄にあるとおり、offscreenBitmapをpictureboxと同じサイズで作って、乗っかる画像の位置倍率を自分で計算して描画する方法です。 それであれば、マウスカーソルとの辻褄合わせも制御しやすいです(自分で倍率決めて描画しているので当然倍率は判っていることになりますよね)。 ちなみにそうなってくるとpictureboxを使わなくても、PanelやUserControlから派生クラスを作ってOnPaintで自前で描画コードを書いた方が手っ取り早い、という話になってきます。
dendenmushi

2019/06/06 08:45 編集

>offscreenBitmapをpictureboxと同じサイズで作って おそらくこちらは、offscreenBitmap = new Bitmap(pictureBox1.Width, pictureBox.Height); と思い実装したのですが、結局そのあとに offscreenBitmap = new Bitmap(backgroundBitmap); をするのでダメでした。 >乗っかる画像の位置倍率を自分で計算して描画する方法 この方法の詳細ご教授頂けないでしょうか。イメージがさっぱりわかないです。 今のpictureboxの画像から取得して表示される方法はzoomを使っております。 最終目標はただ切り取りをしたいだけになります。(言い換えれば範囲指定以外は白塗り?)その他は真っ白同じ大きさで構わないと思っております。元ある画像倍率のまま、ただ切り抜きしたいだけになります。どうかアドバイスよろしくお願い致します。
takabosoft

2019/06/06 08:46

> をするのでダメでした。 そりゃそうです。 offscreenBitmap = new Bitmap(pictureBox1.Width, pictureBox.Height); で作ったインスタンスをnew Bitmap(backgroundBitmap)という新しいインスタンスで上書きしてしまっているのですから、最初に作ったインスタンスは無かったことになります。 そうではなく、 Graphics.DrawImage(だっけ?)でoffscreenBitmapに対してbackgroundBitmapを描画先の位置・サイズを指定して描画してやります。 > この方法の詳細ご教授頂けないでしょうか。イメージがさっぱりわかないです。 表示倍率は縮小のみであれば、たぶん float scale = Math.Min(ピクチャーボックスの幅 / 画像の幅, ピクチャーボックスの高さ / 画像の高さ); scale = Math.Min(scale, 1); で出ますので、検証してみてください(違ったらごめんなさい)。
takabosoft

2019/06/06 08:49

あ、zoomであれば、scale = Math.Min(scale, 1);は不要です。
dendenmushi

2019/06/06 09:49

素晴らしい回答ありがとうございました。非常に助かりました。またぜひ勉強させて下さい。
dendenmushi

2019/06/08 23:04

すみません。もしまたこちら見られていましたら…画像をAutosizeでやり過ごしていたのですが、やはりzoomで全体をD&Dしていく必要がありまして…その画像表示時をzoomにしてからD&D範囲指定の座標合わせについて、何か参考になるサイトなどないでしょうか。具体的に画像のzoomの倍率をしってその分、マウスにもどのように反映させるのかご教授頂けないでしょうか。よろしくお願い致します。
dendenmushi

2019/06/08 23:06

ごめんなさい。上の方法でした。まず試してみます。
dendenmushi

2019/06/09 10:44

//アプリ内画像の範囲指定の際のD&Dをし始めた座標取得 private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { // 描画フラグON view = true; //縮小された長さと元の長さの差分をstar.XやYに足せばよい int eX = e.X - (e.X * (int)scale - pictureBox1.Width / 2); int eY = e.Y - (e.Y * (int)scale - pictureBox1.Height / 2); // Mouseを押した座標を記録 MD.X = e.X;//e.X →eX MD.Y = e.Y;//e.Y →eY } //縮小された長さと元の長さの差分をstar.XやYに足せばよい start.X = start.X - (start.X * (int)scale - pictureBox1.Width / 2); start.Y = start.Y - (start.Y * (int)scale - pictureBox1.Height / 2); end.X = end.X - (end.X * (int)scale - pictureBox1.Width / 2); end.Y = end.Y - (end.Y * (int)scale - pictureBox1.Height / 2); g.DrawRectangle(blackPen, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y)); zoomにしてから点線の表示もずれて、切り取られる場所もずれて、かなり四苦八苦しています。 何か参考にあるサイトなどご存知ないでしょうか。とても難しいです…。別のスレッド立てようかと思っております。本件と違いますので…
dendenmushi

2019/06/09 10:55

なぜかzoomの倍率が求められていないため、pictureBoxのzoomを使わずに自分で指定倍率で縮小してみるアプローチも今考えています。おそらく使われる対象の画像はだいたい同じ大きさですのでそれで一回チャレンジしてみたいと思っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問