在我的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.这很奇怪,因为原始图像具有完全不同的尺寸。
有什么想法吗?
答案 0 :(得分:7)
当ImageList
将GetRezeptImages
添加到列表中时,PictureBox
似乎正在将您的图像转换为MemoryBmp。
我不知道它为什么会那样做,但这就是你在图像中失去质量的原因。正如您也意识到的那样,图像会转换为16x16图像,然后当您将GetRezeptImages
的尺寸调整为原始尺寸时,它看起来会更加俗气。
修改强>
从TaW的评论:ImageList集合无法处理不同大小的图像,因此它将所有图像转换为通用大小。由于没有设置大小,它似乎默认为16x16。
我建议您更改List<Image>
方法以返回ImageList
而不是GetRezeptImages
,并相应地使用它来显示图像。
或者,如果您始终以与问题中显示的方式相同的方式使用Image
方法,则可以将其更改为始终只返回{{1}}对象中的第一个图像并完全抛出离开所有名单。
答案 1 :(得分:4)
ImageList非常适合可以做的事情:存储大量图像而不会丢失GDI资源。
但不能做的就是你可能需要的东西:存储不同大小的图像&amp;比例即可。
您可以而且应该设置它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;
}
此例程使用透明像素向右或向下扩展图像画布大小而不缩放像素,因此它应保持无损清晰。
答案 2 :(得分:0)
另外,您可能会考虑将其转换为string64而不是byte []。代码有点干净,一旦它成为一个字符串,它就可以放在任何文件中,因为它只是文本。