[英]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資源。
但它不能做的就是你可能需要的東西:存儲不同大小和比例的圖像。
您可以並且應該將其設置為Imagesize
和ColorDepth
屬性(查看默認值,明確用作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.