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

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

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

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

Q&A

3回答

9514閲覧

【C#】画像にリッチテキストを合成したい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

2グッド

1クリップ

投稿2016/03/26 02:44

編集2016/03/27 03:31

photoshopのように画像の上にテキストを編集できるようなWindows Formアプリを作りたいと思っています。

  1. pictureBoxに画像を表示
  2. 画像をクリックするとテキスト(richText)を入力できる
  3. 最終的に画像と文字を合成してファイルに出力する【合成処理】

というような処理をしたいのですが、どのような方法で実現できるのでしょうか?
Bitmapに文字を入れ込むことができるのはわかります。

しかしrichTextを合成する方法がわかりません。

GUI側(編集モード)では画像をクリックしたときにpictureBoxの上にrichTextBoxを配置して文字を入力するようにすれば良いと思います(ただしbackgroundをtransparencyにする方法は未解決です)。

3.の【合成処理】は、画像にrichTextを合成できればと思っていますが方法があればお教えください。

※キャプチャ以外の方法を模索しています
・画面キャプチャで合成だとフォームの上に別の描画があった場合に一緒にキャプチャされるのでこれを回避できる方法を探しています。
・また、Form上で文字追加をする場合は画像が縮小表示されて編集します。元画像が2000x2000pxの場合、例えば500x500pxに縮小表示して文字を入力し、3.の画像と文字を合成する処理の場合は元画像の大きさの2000x2000pxで合成するといった感じです。

※今回の質問はwindows form アプリですが、WPFは未経験ですが検討したいと思っています。

どうぞよろしくお願い致します。

開発環境:
.Net Framework 4.0
windows8 64bit
visualstudio 2012 express

アプリの動作環境:
windows Vista以上(32/64bit)

lib, n.k8808👍を押しています

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

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

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

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

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

lib

2016/03/26 07:21

windows formの開発は、.Net frameworkのバージョンによって、挙動の差異、ご使用のフレームワークによって異なり想定されない動きをするため、せめてご使用のバージョン、使用OS等の明記はお願いします。また、最近の傾向からWPFを使った設計もあるので合わせてご検討いただければ。
退会済みユーザー

退会済みユーザー

2016/03/27 03:26

ご指摘ありがとうございます。追記させて頂きました。
guest

回答3

0

フォーム上で描写されているRichTextBoxのイメージ取る形でよければこんな感じでしょうか?
やってることは、RichTextBox(Control)の座標を元にキャプチャしてるだけです。
PictureBoxを指定すれば、RichTextBoxを埋め込んだ感じのイメージがとれるかと。

C#

1public static Bitmap ToBmp(Control control) 2{ 3 control.Update(); 4 Bitmap bmp = new Bitmap(control.Width, control.Height); 5 using (Graphics graphics = Graphics.FromImage(bmp)) 6 { 7 graphics.CopyFromScreen(control.PointToScreen(Point.Empty), Point.Empty, control.Size); 8 } 9 return bmp; 10}

注意:フォームに描画されていないものはこの方法でとれなかったはず。

追記

要件が追加されたので違うサンプルを。gdi32 BitBltを使う方法になります。
PrintWindowあたりでもいーんですが取れないことがあるんでこっちで。
BitBlt
PrintWindow

C#

1//using System.Drawing; 2//using System.Windows.Forms; 3//using System.Runtime.InteropServices; 4[DllImport("gdi32.dll")] 5private static extern int BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop); 6public static Bitmap CaptureControl(Control target) 7{ 8 Bitmap caputuredBitmap; 9 using (Graphics targetGraphic = target.CreateGraphics()) 10 { 11 caputuredBitmap = new Bitmap(target.Width, target.Height); 12 using (Graphics capturedGraphics = Graphics.FromImage(caputuredBitmap)) 13 { 14 IntPtr targetDc = targetGraphic.GetHdc(); 15 IntPtr capturedDc = capturedGraphics.GetHdc(); 16 BitBlt(capturedDc, 0, 0, target.Width, target.Height, targetDc, 0, 0, 0xCC0020); 17 targetGraphic.ReleaseHdc(targetDc); 18 capturedGraphics.ReleaseHdc(capturedDc); 19 } 20 } 21 22 return caputuredBitmap; 23}

投稿2016/03/26 03:30

編集2016/03/26 07:50
umed0025

総合スコア851

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

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

退会済みユーザー

退会済みユーザー

2016/03/26 03:52

ありがとうございます! これからコード実行を確認させていただきますが、キャプチャということは画面が他のフォームとかで隠れていたらダメでしょうか? もしダメならキャプチャ以外の方法を知りたいです。 どうぞよろしくお願い致します。
lib

2016/03/26 05:00

横から失礼します。 すいませんアイディアを募集するのは質問の姿勢としていかがでしょうか? そもそも、いただいた内容を検証した上でよりよい案と試行錯誤の上で実装していくことが設計なので、Aがだめだから他はありませんか。ということを聞いていることになります。もし質問が不適切であれば見直した上で再質問していただいたらどうでしょうか。 定番のリンクを掲載します。https://teratail.com/blog/article/ba10とhttps://teratail.com/help/avoid-asking もう一度質問を考え直していただけますか?案外その中で解決策がみえてくるものです。
退会済みユーザー

退会済みユーザー

2016/03/26 05:55 編集

すみませんがここでその類の議論をここでやらないとダメでしょうか? 質問内容は要点も書きましたし悪気は全くないです。 補足は追加させていただきましたが、せっかく質問させていただいたのに回答がつかなくなると困るので別の議論で荒らさないでほしいのですが・・・。
lib

2016/03/26 07:19

設計の議論であれば、歓迎ですが、誤解を招きそうな表現がありましたため指摘しました。 また、質問の改変内容から総合的に判断した上で、よい質問の方向とすることにしました。
guest

0

フォームあるいはコントロールの表示イメージをファイルにする場合は、画面キャプチャーではなくDrawToBitmapメソッドの利用をお勧めします。DrawToBitmapメソッドでフォームやコントロールの表示イメージをビットマップにすることができます。
詳しい使い方はDrawToBitmapのリファレンスを参照してください。

しかしrichTextを合成する方法がわかりません。

これについては、フォームアプリでは難しいかもしれません。RichTextBoxは背景色にTransparentを選択できないので、いい感じに合成できません。WPFアプリで作ることも検討された方が良いでしょう。

どうしてもフォームアプリで作るなら、リッチテキスト部分は別フォームにして、TransparencyKeyにリッチテキストの背景色を設定して重ねることで文字部分だけを合成することができますが、1枚絵への合成は自力で行う必要があり、親フォームの移動やサイズ変更に追従させる必要もあるので、面倒ではあります。

投稿2016/03/26 12:18

catsforepaw

総合スコア5938

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

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

退会済みユーザー

退会済みユーザー

2016/03/27 03:22

ありがとうございます。 Stack Overflowや海外サイトでも探していますが、どれもtextBoxやrichTextの背景を透明にしたり合成することはできないようなことしか書いていませんでした。 解決策のコードが書いてあっても、コメントで「それは実行できない」という投稿が多く、自分も試しましたがダメでした。 WebBrowserオブジェクトでWebサイトとして画像を表示させて画像の上のcontenteditable=trueで文字入力も検討しましたが、そもそもForm上の画像が100%の大きさで表示されるわけではなく、例えば2000x2000pixelの画像を500x500pixelで表示させて文字を入力し、実際の文字と画像の合成は2000x2000pixelでやりたいのでキャプチャ自体が使えません。 それとWPFで作るほうがよいのですね。WPFは未経験ですがちょっと挑戦してみようと思います。 アドバイスありがとうございました。
guest

0

ほぼ同じようなアプリ開発の経験があります。

Wordアートのように選択して再編集が無いのであればPictureBoxでもいいですが、
私なら、この手のお絵かきアプリはUserControlを使い、

this.SetStyle(ControlStyles.DoubleBuffer, true); this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

というお決まりの設定をしておきます。

2000,2000のBitamapをメンバ変数m_BmpSourceで保持し、

protected override void OnPaint(PaintEventArgs e) { base.OnPaint (e); //ここでm_BmpSourceをDrawImageで描画 }

と、あくまでも、m_BmpSourceを描画する処理だけにしておきます。
このm_BmpSource.Save()でキャプチャと同等ですね。

では、文字の合成ですが、
m_BmpSourceからGraphicsオブジェクトgBmpを取得し、
gBmp.DrawStringでメンバ変数の画像に描画してしまえばいいのです。
ブラシをカスタムすれば、色々なデザインに対応できますね。

最後にTextBoxの背景ですが、私が作ったアプリでは透過しないでOKの仕様でしたが
「FormのTransparencyKeyは子コントロールにも有効」というルールに乗っかってみましょう。

つまり、Form2をつくりそこにRitchTextBoxを全面に貼り付けます。
Form2は枠もコントロールBoxも無い丸坊主スタイルで。
RitchTextBoxの背景をWhiteにして、Form2のTransparencyKeyにWhiteを設定します。
Form2は枠なしで同じサイズのRitchTextBoxが乗っている訳なので、あたかも透明のRitchTextBoxになる訳です。

元のFormでクリックされた位置をPointToScreenで計算し、Form2を上に表示されてしまえば、
まるで透明のRitchTextBoxが乗っているようになります。

Form2がフォーカスを失ったイベントを確定とし、文字を取得しm_BmpSourceに描画、
Update(true)で画面に反映させる流れです。

ちょっと面倒で難しそうな事を書いていますが、ただの画面の組み合わせだけで
Graphicsの概念が分かっていればすぐに完成できると思いますよ。

投稿2016/03/27 06:42

skltn00

総合スコア31

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

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

退会済みユーザー

退会済みユーザー

2016/03/30 14:45

ありがとうございます。とても参考になります! なかなかロジックが面倒ですがそのような方法があるのですね! ちょっと返信が遅れましたが、作業していたPCが故障したので実験していたものが中途半端になりましたが、結局BitmapにDrawStringでテキストを入力するようにしてみました。 入力位置は、ただの四角の枠なので何でもpictureBoxの上に乗せればいいのでそれで入力位置とサイズを取得してGraphics.DrawStringする場所を割り出そうと思っています(まだやっていません)。 Graphics.DrawStringだとrichTextのように文字の色や大きさを個別にできないのですが、もしかしたら文字のピクセル長が取れるようなのでそこでがんばって対応しようかと思っています。 そしてなぜGraphics.DrawStringにしたかというと、pictureBoxで表示する画像の大きさが、pictureBoxのサイズ変更(ウインドウサイズ変更などで)に追従するようにしたかったからです。なのでキャプチャの方法だと実際の画像サイズと表示している画像サイズが違うので無理かなと思って採用しませんでした(もしかしたら可能なのかもしれませんが・・・)。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問