我必须遵循被调用来改变图像分辨率的函数。我想这样做,所以上传的图像例如300dpi将被修改为72dpi(对于web)。这个问题与another question有关,我在哪里工作。
我正在创建一个扩展方法,以便能够在我的应用程序中的更多位置使用此功能,而不是仅在上载新文件时使用。 (见上述问题)
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
newBitmap.SetResolution(72, 72);
newBitmap.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), null);
}
return newMemoryStream.ToArray();
}
}
在类似于以下情况的函数中调用所提到的扩展方法;
if (newSize.Width > originalImage.Width && newSize.Height > originalImage.Height)
{
newSize.Width = originalImage.Width;
newSize.Height = originalImage.Height;
uploadedFileBuffer = uploadedFileBuffer.SetDpiTo72(uploadedFile.ContentType, newSize);
return CreateFile(newSize, uploadedFile, uploadedFileBuffer);
}
进入的bytearray是一个bytearray文件。它已经具有正确的大小,但我想将分辨率更改为72dpi。但是在执行完并保存图像后,分辨率仍然是原始输入的分辨率,即300dpi。我怎么能这样做?
几个答案之后的更新:
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
originalImage.SetResolution(72, 72);
var epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
var epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
Image newimg = Image.FromStream(memoryStream);
//Getting an GDI+ exception after the execution of this line.
newimg.Save("C:\\test1234.jpg", ImageFunctions.GetEncoderInfo(mimeType), epParameters);
originalImage.Save("test.jpg", ImageFormat.Jpeg);
//This line give me an Argumentexception - Parameter is not valid.
//originalImage.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), epParameters);
//newMemoryStream.Close();
}
return newMemoryStream.ToArray();
}
}
异常附带的stackstrace告诉我以下内容;
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at Extensions.ByteArrayExtensions.SetDpiTo72(Byte[] imageToFit, String mimeType, Size newSize) in C:\Website\Project\Extensions\ByteArrayExtensions.cs:line 356
at CMS.Presentation.FileFunctions.CreateFullsizeImage(HttpPostedFileBase uploadedFile, Size newSize, Byte[] uploadedFileBuffer) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 197
at CMS.Presentation.FileFunctions.CreateFile(HttpPostedFileBase uploadedFile, INodeService nodeservice, Guid userId, Node parentNode) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 53
与此同时,我还开发了另一个功能(见下文),只调整位图。而这似乎工作正常。我不能在我当前的实现中使用此函数,因为它只返回一个Bitmap。或者我应该改变一切以使用位图吗?
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
答案 0 :(得分:3)
好的,我只尝试过硬盘驱动器上的文件,但它也适用于流。
Bitmap bitmap = new Bitmap(loadFrom);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(72, 72);
newBitmap.Save(saveTo);
答案 1 :(得分:3)
花了我一会儿,但我终于找到了问题! 问题在于我使用的ResizeImage函数。在'GetThumbnailImage'中具体。我遇到了另一个模糊图像的问题,这是可以解释的,因为GetThumbnailImage会将创建的ThumbNail拉伸到所需的大小。缩略图的分辨率永远不会改变。
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
通过将上面的函数修改为下面的函数,我能够使用Graphics.DrawImage在渲染之前重绘新图像来解决问题。 GenerateImageDimensions也略有修改。这个问题一起解决了。
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
var resizedImage = new Bitmap(newDimensions.Width, newDimensions.Height);
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
//we have a normal image
using (var gfx = Graphics.FromImage(resizedImage))
{
gfx.SmoothingMode = SmoothingMode.HighQuality;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
var targRectangle = new Rectangle(0, 0, newDimensions.Width, newDimensions.Height);
var srcRectangle = new Rectangle(0, 0, image.Width, image.Height);
gfx.DrawImage(image, targRectangle, srcRectangle, GraphicsUnit.Pixel);
}
}
return resizedImage;
}
答案 2 :(得分:1)
通过“更改分辨率”,您是否真的想要将图像中的像素数减少72/300?即将4000x3000图像更改为960x720?
如果是这样,我看不到你的代码实际上在哪里。 overload of DrawImage() you're using执行此操作:
使用原始物理尺寸在坐标对指定的位置绘制指定的图像。
这正是发生的事情。
尝试one of the other overloads,例如this one:
在指定位置以指定大小绘制指定的图像。
例如:
// Create image.
Image newImage = Image.FromFile("SampImag.jpg");
// Create coordinates for upper-left corner of image and for size of image.
int x = 0;
int y = 0;
int width = 450;
int height = 150;
// Draw image to screen.
e.Graphics.DrawImage(newImage, x, y, width, height);
编辑:根据评论,我了解OP希望减少文件大小而不减少像素数。因此必须重新压缩文件。
我从here借用了一些示例代码:
ImageCodecInfo iciJpegCodec = null;
// This will specify the image quality to the encoder. Change the value of 75 from 0 to 100, where 100 is best quality, but highest file size.
EncoderParameter epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
// Get all image codecs that are available
ImageCodecInfo[] iciCodecs = ImageCodecInfo.GetImageEncoders();
// Store the quality parameter in the list of encoder parameters
EncoderParameters epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
// Loop through all the image codecs
for (int i = 0; i < iciCodecs.Length; i++)
{
// Until the one that we are interested in is found, which is image/jpeg
if (iciCodecs[i].MimeType == "image/jpeg")
{
iciJpegCodec = iciCodecs[i];
break;
}
}
// Create a new Image object from the current file
Image newImage = Image.FromFile(strFile);
// Get the file information again, this time we want to find out the extension
FileInfo fiPicture = new FileInfo(strFile);
// Save the new file at the selected path with the specified encoder parameters, and reuse the same file name
newImage.Save(outputPath + "\\" + fiPicture.Name, iciJpegCodec, epParameters);
答案 3 :(得分:0)
Rob,我相信您的代码存在的问题是保存图像 - 实际的数字图像数据是一定数量的点/像素,即(mxn)和位图的设置分辨率不会/不应该&#39; t更改数字点(以及图像的物理字节大小)。分辨率信息将存储在图像标题中(打印/编辑图像时由程序使用) - 如果将新位图存储到文件而不是存储流中会发生什么
newBitmap.Save("c:\test.png", ImageFormat.Png);
从文件检查上述文件的dpi - &gt;属性 - &gt;摘要(高级)。它应该是72 dpi。