0

Memory Stream を使用して Base64 文字列を画像に変換する非常に古いコードのバグを修正する必要があります。基本的に、base64 文字列として保存された画像のリストをループし、それらを画像に変換してから、ActiveReports を使用して描画します。

バグは、1 つの画像をロードすると、後続のすべての画像が最初の画像のコピーになることです。

文字列から画像への変換を行っているコードを見つけたところ、メモリ ストリームを破棄していないことがすぐにわかりました。using ブロックでメモリ ストリームをラップすると、GDI 例外が発生します。これは、画像がまだ実際にメモリから読み取られていないためだと思いますが、誰かが推測できるかどうかを知りたいです。前もって感謝します!

        byte[] oGraphic = null;
        try
        {
            oGraphic = Convert.FromBase64String(psGraphic);

            DataDynamics.ActiveReports.Picture oImg = new Picture();
            oImg.Top = this.Legend.Top + this.fTopFirst;
            oImg.Visible = true;
            oImg.Name = sLabelName;
            oImg.PictureAlignment = PictureAlignment.Center;

            oImg.Image = null;

            if (oGraphic != null)
            {
                var oStream = new MemoryStream(oGraphic);
                oImg.Image = System.Drawing.Image.FromStream(oStream);
                oImg.Height = Convert.ToSingle(oImg.Image.Height)/(oImg.Image.VerticalResolution);
                oImg.Width = Convert.ToSingle(oImg.Image.Width)/(oImg.Image.HorizontalResolution);
                oImg.SizeMode = SizeModes.Zoom;
                this.fGraphicHeight = oImg.Height;
                this.fGraphicWidth = oImg.Width;
                if (this.fConstantGraphic > this.fGraphicWidth)
                    oImg.Left = this.Legend.Left + this.fLeftFirst +
                                ((this.fConstantGraphic - this.fGraphicWidth)/2);
                else
                    oImg.Left = this.Legend.Left + this.fLeftFirst;

            }
            else
            {
                this.fGraphicHeight = 0f;
                this.fGraphicWidth = 0f;
            }

            this.GHMap.Controls.Add(oImg);
        }
        catch (Exception oE)
        {
            .....
        }

ここに画像の説明を入力

4

5 に答える 5

1

推測 #3 (これらの 1 つにチェックマークが付きます。私はそれを知っています!)

提供されたコードではすべて問題ないように見えますが、問題は別の場所にあります (ただし、問題がないことについて私が間違っている可能性は十分にあります)。

このコードが実行されるたびに psGraphic が異なることは確かですか?

于 2012-05-23T23:06:16.173 に答える
1

この問題の原因は、Picture コントロールが 1 つのセクション上の 1 つのコントロール インスタンスであることです。したがって、この単一のコントロールの画像を何度も上書きしているだけです。

このレポートで見たいのが画像だけの場合は、ActiveReports の Unbound モードを使用して、各画像を別の「レコード」として扱うのが最善の方法です。アンバウンド モードの使用例については、このウォークスルーを参照してください(問題の内容については、DataInitialize および FetchData イベントを参照してください)。

非バインド モードを使用すると、ActiveReports は、各画像を新しいレコードのように扱うセクションで画像を次々にレンダリングします。コードは次のようになります (申し訳ありませんが、現時点では ActiveReports が手元にないため、このコードを確認することはできませんが、これはかなり近いはずです。問題が発生した場合はお知らせください。問題を解決します朝起きて):

ActiveReports の ReportStart イベント:

DataDynamics.ActiveReports.Picture oImg = new Picture();
oImg.Top = 0;
oImg.Visible = true;
oImg.Name = sLabelName;
oImg.PictureAlignment = PictureAlignment.Center;
// setting DataField "binds" the Picture control to get it's data from the MyImageField field which we'll initialize and bind in the events below
oImg.DataField = "MyImageField";
this.Sections["Detail"].Controls.Add(oImg);

ActiveReports の DataInitialize イベント:

this.Fields.Add("MyImageField");

ActiveReports FetchData イベント:

var imageBytes = Convert.FromBase64String(_imageStrings.Current); // I'm not sure where the base64 image strings come from, some I'm assuming you can put them in an enumerator field in the report like "_imageStrings" 
var imageStream = new MemoryStream(imageBytes);
var image = Image.FromStream(imageStream);
Fields["MyImageField"].Value = image;

// This tells ActiveReports if there are more records, and if it should raise the FetchData event again (allowing you to add another image).
eArgs.EOF = !_imageStrings.MoveNext();

各画像の画像コントロールのサイズを変更する必要がある場合は、セクションの Format イベントを使用してください。次のようなものを使用できます。

Detail_Format イベント:

var pictureControl = this.Sections["Detail"].Controls["MyImageControl"] as DataDynamics.ActiveReports.Picture;
pictureControl.Width = Convert.ToSingle(pictureControl.Image.Width)/(pictureControl.Image.VerticalResolution);
pictureControl.Width = Convert.ToSingle(pictureControl.Image.Width)/(pictureControl.Image.HorizontalResolution);

最後に、ActiveReports は IEnumerable (または IList、忘れました) 内の一連の POCO オブジェクトに自動的にバインドします。そのため、「MyImage」などのプロパティを持つ「MyImage」クラスを作成するだけで、ActiveReports がそれを読み取ってバインドします (DataInitialize と FetchData にコードを記述する必要はありません)。バインディングも ActiveReports がそれを読み取るので、そこに MemoryStream を配置することもできると思いますが、私はそれについて肯定的ではありません。

ところで: MemoryStream を破棄するときに GDI 例外が発生する理由は、GDI がそのコピーを作成するのではなく、その単一の MemoryStream 内で画像データをシークしようとするためです。そのため、各 System.Drawing.Image インスタンスに新しいストリームを提供する必要があります (すべてが解放されたときに MemoryStream が自動的にクリーンアップされることを心配しないでください)。

于 2012-05-24T05:30:56.373 に答える
1

これが別の推測です(後世のために最初の推測はそのままにしておきます):

私は Active Reports に詳しくありませんが、Picture オブジェクトの Top プロパティと PictureAlignment プロパティを同じ値に設定し、複数の Picture を追加しているようです。それらはすべてそこにある可能性がありますが、互いに重なっていますか? 結果は一枚の絵?

于 2012-05-23T22:44:00.537 に答える
1

私が想像できる唯一のことは、ここにあるものから欠落しているコード行があるかどうかです。

if (oGraphic == null) // missing line
    oGraphic = Convert.FromBase64String(psGraphic);

この byte[] を try { } ブロックの外で宣言する理由はありません。その配列は、Image にラップされる MemoryStream にラップされます。その画像は、画像コレクションに追加された真新しい画像に添付されます。

私たちが見えないのは何ですか?

于 2012-05-23T22:20:29.043 に答える
0

画像の作成方法に問題があることが判明しました。以下のコードを追加すると、問題が修正されました。

   oImg.Image = System.Drawing.Image.FromStream(oStream);

   TO THIS

   oImg.Image = ImageFromBase64String(psGraphic);

   private Image ImageFromBase64String(string sBase64String)
        {
            using (var sStream = new MemoryStream(Convert.FromBase64String(sBase64String)))
            using (var iSourceImage = Image.FromStream(sStream))
            {
                return new Bitmap(iSourceImage);
            }
        }
于 2012-05-25T16:13:36.303 に答える