1

イメージをファイル システムにシリアライズ、デシリアライズ、保存するコードを次に示します。シリアライゼーション/デシリアライゼーションの多くの例を見てきましたが、コードを改善できると確信しているので、フィードバックを得たいだけです。どんなフィードバックでも大歓迎です。これはよくある問題であることを知っているので、この質問が将来他の人にとって良いリソースになることを願っています.

これは、推奨事項を使用して改訂されたコードです。

    private void Form1_Load(object sender, EventArgs e)
    {
        RunTest();
    }

    private void RunTest()
    {
        byte[] jpgba = ConvertFileToByteArray("D:\\Images\\Image01.jpg");
        using (Image jpgimg = ConvertByteArrayToImage(jpgba))
        {
            SaveImageToFileSystem(jpgimg, "D:\\Images\\Image01_Copy.jpg");
        }

        byte[] pngba = ConvertFileToByteArray("D:\\Images\\Image02.png");
        using (Image pngimg = ConvertByteArrayToImage(pngba))
        {
            SaveImageToFileSystem(pngimg, "D:\\Images\\Image02_Copy.png");
        }

        byte[] gifba = ConvertFileToByteArray("D:\\Images\\Image03.gif");
        using (Image gifimg = ConvertByteArrayToImage(gifba))
        {
            SaveImageToFileSystem(gifimg, "D:\\Images\\Image03_Copy.gif");
        }

        MessageBox.Show("Test Complete");
        this.Close();
    }

    private static byte[] ConvertFileToByteArray(String FilePath)
    {
        return File.ReadAllBytes(FilePath);
    }

    private static Image ConvertByteArrayToImage(byte[] ImageByteArray)
    {
        using (MemoryStream ms = new MemoryStream(ImageByteArray))
        {
            return Image.FromStream(ms);
        }
    }

    private static void SaveImageToFileSystem(Image ImageObject, string FilePath)
    {
        // ImageObject.Save(FilePath, ImageObject.RawFormat);
        // This method only works with .png files.

        // This method works with .jpg, .png and .gif
        // Need to copy image before saving.
        using (Image img = new Bitmap(ImageObject.Width, ImageObject.Height))
        {
            using (Graphics tg = Graphics.FromImage(img))
            {
                tg.DrawImage(ImageObject, 0, 0);
            }
            img.Save(FilePath, img.RawFormat);
        }
        return;
    }
4

3 に答える 3

3

クイックルックから見たもの:

ストリームはusing(...)パターンでラップする必要があります。この場合、処理中に例外が発生した場合、Dispose()は呼び出されません。

using (FileStream fs = new FileStream(FilePath, FileMode.Open))
{
    // Another small optimization, removed unnecessary variable 
    byte[] iba = new byte[(int)fs.Length];
    fs.Read(iba, 0, iba.Length);
}

予期する例外のみをキャッチする必要があります。たとえば、SerializeImageでは、これはIOExceptionになります。すべての例外をキャッチすることは非常に悪い習慣です。

}
catch (IOException ex)
{

Image.FromStreamメソッドはストリームに依存するため、基になるストリームを閉じてImageを返すと、予期しない動作が発生する可能性があります(ほとんどの場合、これは機能しますが、エラーが発生する場合があります)。したがって、画像のコピーを作成して返す必要があります。

using (MemoryStream ms = new MemoryStream(ImageByteArray))
{
    using (Image img = Image.FromStream(ms))
    {
        return new Bitmap(img);
    }
}

SaveImageメソッドでtgグラフィックスオブジェクトとimgオブジェクトを破棄しません(ただし、ImageObjectを破棄します。次の段落を参照してください)。そして、一般的に、私はそのようなロジックに必要性を感じていません。画像を保存する品質を保存したい場合は、ImageObject.Save(...、ImageFormat.Png)を呼び出すだけです。

同じメソッド(SaveImage)で、ImageObjectパラメーターが破棄されます。これもほとんどの場合悪い習慣です。using (...)パターンを使用してこの画像をworkerメソッドの外部に配置することを検討してください。

于 2009-07-21T00:18:00.877 に答える
1

ここにもう少しあります:

private void RunTest()
{
    // byte array that can be stored in DB
    byte[] iba;

    // image object to display in picturebox or used to save to file system.

    iba = ReadImage("D:\\Images\\Image01.jpg");
    using (Image img = DeserializeImage(iba))
    {
        SaveImage(img, "D:\\Images\\Image01_Copy.jpg");
    }

    iba = ReadImage("D:\\Images\\Image02.png");
    using (Image img1 = DeserializeImage(iba))
    {
        SaveImage(img1, "D:\\Images\\Image02_Copy.png");
    }

    iba = ReadImage("D:\\Images\\Image03.gif");
    using (var img2 = DeserializeImage(iba))
    {
        SaveImage(img2, "D:\\Images\\Image03_Copy.gif");
    }

    MessageBox.Show("Test Complete");
}

private static byte[] ReadImage(String filePath)
{
    // This seems to be the easiest way to serialize an image file
    // however it would be good to take a image object as an argument
    // in this method.
    using (var fs = new FileStream(filePath, FileMode.Open))
    {
        Int32 fslength = Convert.ToInt32(fs.Length);
        var iba = new byte[fslength];
        fs.Read(iba, 0, fslength);
        return iba;
    }
}

private static Image DeserializeImage(byte[] imageByteArray)
{
    using (var ms = new MemoryStream(imageByteArray))
    {
        return Image.FromStream(ms);
    }
}

private static void SaveImage(Image imageObject, string filePath)
{
    // I could only get this method to work for .png files.
    // imageObject.Save(filePath, imageObject.RawFormat);

    // This method works with .jpg, .png and .gif
    // Need to copy image before saving.
    using (Image img = new Bitmap(imageObject.Width, imageObject.Height))
    {
        using (Graphics tg = Graphics.FromImage(img))
        {
            tg.DrawImage(imageObject, 0, 0);
        }

        img.Save(filePath, img.RawFormat);
    }

    return;
}

あなたがシリアライズと呼んだのは、バイトを読み取るだけであることに注意してください。シリアライズは、保存時に行うことです。

すべての try/catch ブロックを取り除きました。彼らがあなたのために行った最善のことは、問題が読み取り、保存、または逆シリアル化で発生したかどうかを教えてくれることです. ex.Message.

また、重大な例外で null を返し、失敗を伝播していました。

それに加えて、私は仲裁人が言ったことすべてに同意します。

于 2009-07-21T00:36:13.860 に答える
0

John Saunder が言うように、シリアル化と逆シリアル化は、ファイルから生データを読み取るだけではありません。シリアル化に関する Wiki を参照してください

.net の画像の場合、提供されているフレームワーク メソッド以外を使用する必要はありません (ほとんどの場合)。

したがって、.net でのイメージのロード (デシリアライゼーション) はそうです。

using System.Drawing.Image;

Image test;

test = Image.FromFile(@"C:\myfile.jpg")
test = Image.FromStream(myStream); // or you can load from an existing stream

同様に、画像の保存 (シリアル化) は次のとおりです。

test.Save(@"C:\anotherFile.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

これらは、.net での画像の読み込みと保存の基本です。より具体的なシナリオがある場合は、別の質問をしてください。

于 2009-07-21T00:50:56.017 に答える