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

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

ただいまの
回答率

89.10%

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,218

dendenmushi

score 76

前提・実現したいこと

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の方を透過で四角を描けるようにしました。

        public Form1()
        {
            InitializeComponent();
            //プロパティの設定変更
            pictureBox1.AllowDrop = true;
            //描画先とするImageオブジェクトを作成する
            bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);

            pictureBox2.BackColor = Color.Transparent;
            pictureBox2.Parent = pictureBox1;
            pictureBox2.Location = new Point(0, 0);

        }

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

現状(令和元年6月6日)

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

6月6日16時の時点での現状

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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace WindowsFormsApp_20190604
{
    public partial class Form1 : Form
    {
        Point MD = new Point();
        Point MU = new Point();
        Bitmap bmp;
        Bitmap backgroundBitmap;//20190605
        Bitmap offscreenBitmap;
        bool view = false;


        public Form1()
        {
            InitializeComponent();
            //プロパティの設定変更
            pictureBox1.AllowDrop = true;
            //描画先とするImageオブジェクトを作成する
            bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }
        private void pictureBox1_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            for (int i = 0; i < files.Length; i++)
            {
                string fileName = files[i];

                string filename = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
                backgroundBitmap = new Bitmap(filename);
                offscreenBitmap = new Bitmap(backgroundBitmap);//tuika15


                Console.WriteLine("offscreenBitmap:" + offscreenBitmap);

                //表示方法をzoomにする
                pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

                pictureBox1.Image = offscreenBitmap;
            }
        }

        private void pictureBox1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
        }

        private void GetRegion(Point p1, Point p2, ref Point start, ref Point end)
        {
            start.X = Math.Min(p1.X, p2.X);
            start.Y = Math.Min(p1.Y, p2.Y);

            end.X = Math.Max(p1.X, p2.X);
            end.Y = Math.Max(p1.Y, p2.Y);
        }

        private int GetLength(int start, int end)
        {
            return Math.Abs(start - end);
        }

        private void DrawRegion(Point start, Point end)
        {
            Pen blackPen = new Pen(Color.Black);
            Console.WriteLine(bmp);
            Console.WriteLine(offscreenBitmap);

            Graphics g = Graphics.FromImage(offscreenBitmap);

                // 描画する線を点線に設定
                blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

                // 画面を消去
                g.Clear(SystemColors.Control);

                g.DrawRectangle(blackPen, start.X, start.Y, GetLength(start.X, end.X), GetLength(start.Y, end.Y));

                g.Dispose();
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            // 描画フラグON
            view = true;

            // Mouseを押した座標を記録
            MD.X = e.X;
            MD.Y = e.Y;
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {

            Point p = new Point();
            Point start = new Point();
            Point end = new Point();

            // 描画フラグcheck
            if (view == false)
            {
                return;
            }

            // カーソルが示している場所の座標を取得
            p.X = e.X;
            p.Y = e.Y;

            // 座標から(X,Y)座標を計算
            GetRegion(MD, p, ref start, ref end);

            // 領域を描画
            DrawRegion(start, end);

            //backの画像表示方法指定
            pictureBox1.BackgroundImageLayout = ImageLayout.Zoom;
            //初めにとっておいた背景bitmapを表示
            pictureBox1.BackgroundImage = backgroundBitmap;
            //bitmapの透過
            offscreenBitmap.MakeTransparent();

            //Imageを表示
            pictureBox1.Image = offscreenBitmap;
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {

            Point start = new Point();
            Point end = new Point();


            // Mouseを離し た座標を記録
            MU.X = e.X;
            MU.Y = e.Y;

            // 座標から(X,Y)座標を計算
            GetRegion(MD, MU, ref start, ref end);

            // 領域を描画
            DrawRegion(start, end);

            //PictureBox1に表示する

            // 描画フラグOFF
            view = false;
        }
    }
}


イメージ説明

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Q71

    2019/06/06 15:54

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

    キャンセル

  • dendenmushi

    2019/06/06 16:19

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

    キャンセル

回答 1

checkベストアンサー

+1

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

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

で、pitureboxには何かある度に

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/09 08:06

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

    キャンセル

  • 2019/06/09 19: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にしてから点線の表示もずれて、切り取られる場所もずれて、かなり四苦八苦しています。
    何か参考にあるサイトなどご存知ないでしょうか。とても難しいです…。別のスレッド立てようかと思っております。本件と違いますので…

    キャンセル

  • 2019/06/09 19:55

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

    キャンセル

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

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる