簡體   English   中英

圖像質量損失從何而來?

[英]Where does this quality loss on Images come from?

在我的Winforms應用程序中,它通過Linq連接到數據庫到SQL我將圖像(總是* .png)保存到一個如下所示的表:

CREATE TABLE [dbo].[Images] (
    [Id]       INT   IDENTITY (1, 1) NOT NULL,
    [Bild]     IMAGE NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

在我可以存儲圖片之前,我必須將其轉換為byte[] ,這就是我的方法:

public static byte[] ImageToByteArray(System.Drawing.Image imageIn)
{
    using (MemoryStream ms = new MemoryStream())
    {
        imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        return ms.ToArray();
    }
}

之后,如果我想將這個相同的圖像加載到我的應用程序中的PictureBox,我將使用此方法將其轉換回來:

public static Image ByteArrayToImage(byte[] byteArrayIn)
{
    using (MemoryStream ms = new MemoryStream(byteArrayIn))
    {
        Image returnImage = Image.FromStream(ms);
        return returnImage;
    }
}

它確實有效,當我嘗試在Picturebox中顯示數據庫中的圖像時,會出現唯一的問題。

所以當我將這個Image加載到數據庫時:

在此輸入圖像描述

后來我嘗試顯示它。 它突然看起來像這樣:

在此輸入圖像描述

我已經嘗試了PictureBox的所有可能的SizeMode設置(Normal,Stretchimage,AutoSize,CenterImage,Zoom),它仍然看起來像這樣。

以下是我如何將圖像從數據庫加載到pictureBox:

首先,我通過id檢索屬於集合的所有圖像:

public static ImageList GetRezeptImages(int rezeptId) 
{
    using (CookBookDataContext ctx = new CookBookDataContext(ResourceFile.DBConnection))
    {
        IEnumerable<RezeptBilder> bilder = from b in ctx.RezeptBilders where b.FKRezept == rezeptId select b;
        ImageList imageList = new ImageList();

        foreach(RezeptBilder b in bilder)
        {
            imageList.Images.Add(Helper.ByteArrayToImage(b.Bild.ToArray()));
        }

        return imageList;                
    }
}

同樣在我的應用程序中,我有一個datagridview,其中Id存儲在第一列中。 因此,當我想要檢索屬於該集合的任何圖像時,我這樣做:

private void dgvRezeptListe_CellClick(object sender, DataGridViewCellEventArgs e)
{
    pbRezeptBild.Image = DBManager.GetRezeptImages(Int32.Parse(dgvRezeptListe.SelectedRows[0].Cells[0].Value.ToString())).Images[0];      
}

從本地目錄加載時,Image在pictureBox中看起來很好。 我還嘗試將初始圖片轉換為二進制並返回(不加載到數據庫),它在pictureBox中顯示時看起來仍然很好。

在調試來自數據庫的Image時,我發現了其他一些東西。 在查看ImageSize時,寬度和高度都具有值16.這很奇怪,因為原始圖像具有完全不同的尺寸。

有任何想法嗎?

看來, ImageList被轉換你的圖像MemoryBmp的,當你在將它們添加GetRezeptImages到列表中。
我不知道它為什么會那樣做,但這就是你在圖像中失去質量的原因。 正如您也意識到的那樣,圖像被轉換為​​16x16圖像,然后當您在PictureBox中將其調整為原始大小時,它看起來更加俗氣。

編輯:
從TaW的評論:ImageList集合無法處理不同大小的圖像,因此它將所有圖像轉換為通用大小。 由於沒有設置大小,它似乎默認為16x16。

我建議您更改GetRezeptImages方法以返回List<Image>而不是ImageList並相應地使用它來顯示圖像。

或者,如果您始終以與問題中顯示的方式相同的方式使用GetRezeptImages方法,則可以將其更改為始終只返回Image對象中的第一個Image並完全丟棄所有列表。

ImageList非常適合它可以做的事情:存儲大量圖像而不會丟失GDI資源。

但它不能做的就是你可能需要的東西:存儲不同大小和比例的圖像。

您可以並且應該將其設置為ImagesizeColorDepth屬性(查看默認值,明確用作StateImageList; 16x16px和8位深度對於LargeImageList來說甚至是壞的...)但是如果您的圖像需要,則無法使用它有不同的尺寸和比例..

如果他們不這樣做,那就是他們至少可以分享他們的比例,只需通過挑選一個漂亮的大小來修復ImageList就可以了! 添加到ImageList的所有圖像將自動縮放到該Size並轉換為ColorDepth

否則,用List<Image>List<Bitmap>替換它..!

如果您知道圖像的常見尺寸和ColorDepth ,則可以執行以下操作:

using (CookBookDataContext ctx = new CookBookDataContext(ResourceFile.DBConnection))
{
    IEnumerable<RezeptBilder> bilder = 
             from b in ctx.RezeptBilders where b.FKRezept == rezeptId select b;
    ImageList imageList = new ImageList();

    imageList.ColorDepth = ColorDepth.Depth24Bit;  // 
    imageList.ImageSize = yourImageSize;           //

    foreach(RezeptBilder b in bilder)
    {
        imageList.Images.Add(Helper.ByteArrayToImage(b.Bild.ToArray()));
    }

    return imageList;                
}

您可以不使用ImageList而是使用List<Image>List<Bitmap>制作它們 - 即: 它們修剪為相同的比例 ,基本上不會多於幾條額外的線..:

Bitmap expandCanvas(Bitmap bmp, Size size)
{
    float f1 = 1f * bmp.Width / bmp.Height;
    float f2 = 1f * size.Width / size.Height;
    Size newSize = size;
    if (f1 > f2) newSize = new Size(bmp.Width, (int)(bmp.Height * f1));
    else if (f1 < f2) newSize = new Size((int)(bmp.Width / f1), bmp.Height);

    Bitmap bmp2 = new Bitmap(newSize.Width, newSize.Height);
    bmp2.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);

    Rectangle RDest = new Rectangle(Point.Empty, bmp.Size);
    Rectangle RTgt = new Rectangle(Point.Empty, newSize);

    using (Graphics G = Graphics.FromImage(bmp2))
    {
        G.DrawImage(bmp, RDest, RDest, GraphicsUnit.Pixel);
    }
    return bmp2;
}

此例程使用透明像素向右或向下擴展圖像畫布大小,而不縮放像素,因此它應保持無損清晰。

您也可以考慮將其轉換為string64而不是byte []。 代碼有點干凈,一旦它是一個字符串,它就可以放在任何文件中,因為它只是文本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM