- PR -

C#[WPF] BitmapEncoderが機能しない

1
投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2008-05-11 18:20
「C#(WPF) DrawingImageオブジェクトをJPEGファイルに保存する方法」という題目で掲載しましたが、
問題をきちんと把握しないまま質問してしまいすみませんでした。
より具体的に質問できる状態になりましたので、再トライしてみたいと考え掲載することにしました。
宜しくお願いします

サンプルコードをご参照願います。

【現象】
・JPEGファイルが生成されるが、中身は真っ黒なままである。
・画面には丸底フラスコが表示されることを確認済みである。

【課題】
水で満たされた丸底フラスコをImageコントロール(WPF)を使って画面表示する。
また、描画内容をJPEG形式のファイルに保存する。

【質問1】
Bitmapファイルの中身が真っ黒なままの原因が分かりません。
(FurasukoLibのSaveBmp()の記述に問題があると考えています)

【質問2】
RenderTargetBitmap render = new RenderTargetBitmap(100, 200, 96, 96, PixelFormats.Pbgra32);
のPixelFormats.Pbgra32を別の形式に変更すると実行時エラーが発生し、変更できない原因が分かりません。
24bitRGB形式で出力にしたいのですが、どうすればよいのでしょうか?


以下、サンプルコード

(呼び出し元、呼び出し先の2つに分かれています)

// 呼び出し元のソースコード
// XAML連携の相互作用ロジックと記載されていますが、実際はWindowを呼び出しているだけで、
// XAMLで特別な処理をしているわけではありません。必要な参照があれば実行できるはずです。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

[assembly: CLSCompliant(true)]
namespace WpfApplication1
{
/// <summary>
/// Window1.xaml の相互作用ロジック
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)
{

Image img = new Image();

// 水を120満たした丸底フラスコを作成します。
// Fura.CreateFura()はDrasingImageを返します。
img.Source = FurasukoLib.CreateFura(120);
img.Width = 100;
img.Height = 200;
img.Stretch = Stretch.None;

// JPEGファイルを作成します。(Bitmapファイルが作成されるが、画像は真っ黒である)
FurasukoLib.SaveJpeg("new.jpg", img.Source);

Window wnd = new Window();
wnd.Content = img;

// 水に満たされた丸底フラスコを表示します。(正しく表示できることを確認済み)
wnd.ShowDialog();

}
}
}


// 呼び出し先のソースコード


using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace WpfApplication1
{
public static class FurasukoLib
{
/// <summary>
/// 丸底フラスコを描画オブジェクトを作成します。
/// </summary>
/// <param name="waterDepth">水深</param>
/// <returns>描画オブジェクト</returns>
public static DrawingImage CreateFura(double waterDepth)
{
// 丸底フラスコの底

EllipseGeometry sokoPgeo = new EllipseGeometry(new Rect(0, 0, 100, 100));

// 丸底フラスコの首

RectangleGeometry kubiPgeo = new RectangleGeometry(new Rect(0, 0, 50, 150));

// 水の領域(深さが変化します)
// 練習のためRectangleGeometryを使わず線分から組み立てます。

// STEP1 線分を作成します。
// 始点は(0,200)を想定しています。
PolyLineSegment mizuSeg = new PolyLineSegment();
mizuSeg.Points.Add(new Point(100, 200));
mizuSeg.Points.Add(new Point(100, 200 - waterDepth));
mizuSeg.Points.Add(new Point(0, 200 - waterDepth));

// STEP2 ジオメトリのサブセクション=2次元幾何学セグメントを作成します。
PathFigure mizuFig = new PathFigure();
mizuFig.StartPoint = new Point(0, 200);
mizuFig.Segments.Add(mizuSeg);
mizuFig.IsFilled = true;
mizuFig.IsClosed = true;

// STEP3 ジオメトリに変換します
PathGeometry mizuPgeo = new PathGeometry();
mizuPgeo.Figures.Add(mizuFig);

// STEP4 複数のジオメトリを組み合わせます。

// 変換を使って底を首を平行移動します。
sokoPgeo.Transform = new TranslateTransform(0, 100); // 底をY軸方向に100平行移動
kubiPgeo.Transform = new TranslateTransform(25, 0); // 首をX軸方向に25平行移動

// 底と首を結合して丸底フラスコを完成させます。
CombinedGeometry furaGeo = new CombinedGeometry(sokoPgeo, kubiPgeo);
furaGeo.GeometryCombineMode = GeometryCombineMode.Union;

// 丸底フラスコのうち水で満たされている領域を抽出します。
CombinedGeometry mizufuraGeo = new CombinedGeometry(furaGeo, mizuPgeo);
mizufuraGeo.GeometryCombineMode = GeometryCombineMode.Intersect; // 重なっているる領域

// ここまでの操作で、必要なジオメトリが準備できましたので描画に移ります。

// STEP5 GeometryDrawingを作成します。

// 丸底フラスコ全体の描画
GeometryDrawing furaGdwg = new GeometryDrawing();
furaGdwg.Geometry = furaGeo;
furaGdwg.Brush = Brushes.Transparent; // 透明で塗りつぶす。
furaGdwg.Pen = new Pen(Brushes.Black, 0.5); // 黒色でふちどる

// 丸底フラスコのうち水で満たされている領域の描画
GeometryDrawing mizufuraGdwg = new GeometryDrawing();
mizufuraGdwg.Geometry = mizufuraGeo;
mizufuraGdwg.Brush = Brushes.LightBlue; // 水色で塗りつぶす
mizufuraGdwg.Pen = new Pen(Brushes.Blue, 1); // 青色でふちどる

// STEP6 丸底フラスコ全体と水で満たされている領域をグループ化します。

DrawingGroup furaDwgg = new DrawingGroup();
furaDwgg.Children.Add(furaGdwg);
furaDwgg.Children.Add(mizufuraGdwg);

// STEP7 DrawingImageに変換します。

DrawingImage dwgImg = new DrawingImage();
dwgImg.Drawing = furaDwgg;

return dwgImg;
}

/// <summary>
/// ImageSourceをBitmapファイルに変換します。
/// </summary>
/// <param name="path">ファイルの作成先のPath</param>
/// <param name="imgSource">イメージソース</param>
public static void SaveJpeg(string path, ImageSource imgSource)
{
Image img = new Image();
img.Width = 100;
img.Height = 200;
img.Source = imgSource;

DrawingVisual dv = new DrawingVisual();
dv.Children.Add(img);

RenderTargetBitmap render = new RenderTargetBitmap(100, 200, 96, 96, PixelFormats.Pbgra32);
render.Render(dv);

BitmapEncoder enc = new JpegBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(render));

using (System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
enc.Save(stream);
}
}
}
}
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2008-05-11 18:23
リンク先が反映されなかったようなので、掲載します。

前回の質問(参考)
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=44486&forum=7
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2008-05-11 19:16
引用:

リンク先が反映されなかったようなので、掲載します。


右上の「参照元記事」になっているのがそうじゃないですか?

で、本題ですが、このスレッドの記述で何が分かりませんか?
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=42480&forum=7&2


[追記]
どうせ JpegBitmapEncoder がエンコードする際に 24bpp に変更しますが、それじゃ不都合なのでしょうか?
[/追記]

[ メッセージ編集済み 編集者: Hongliang 編集日時 2008-05-11 19:33 ]
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2008-05-14 00:06
ご回答ありがとうございます。
Hongliangさんにはとても感謝しています。

やっと、JPEGファイルを作成することができました。
ソースコードを下記のように修正することで、
水色のフラスコが描かれたJPEGファイルが生成しました。(背景が黒色のままですが)

未だDrowVisual,DrawContext,RenderTargetBtimap,BitmapEncorderの役割が
きっちりふにおちているわけではありませんが、私にとっては前進です。
MSDNを見ながら、頭を整理しようと思います。


/// <summary>
/// ImageSourceをBitmapファイルに変換します。
/// </summary>
/// <param name="path">ファイルの作成先のPath</param>
/// <param name="imgSource">イメージソース</param>
public static void SaveJpeg(string path, ImageSource imgSource)
{
Image img = new Image();
img.Width = 100;
img.Height = 200;
img.Source = imgSource;

DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawImage(imgSource, new Rect(0, 0, 100, 200));
dc.Close();

RenderTargetBitmap render = new RenderTargetBitmap(100, 200, 96, 96, PixelFormats.Pbgra32);
render.Render(dv);

BitmapEncoder enc = new JpegBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(render));

using (System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
enc.Save(stream);
}
}


1

スキルアップ/キャリアアップ(JOB@IT)