C# изменение dpi загруженного изображения
Я должен следовать функции, которая вызывается для изменения разрешения изображения. Я хочу сделать это, чтобы загруженное изображение, например, 300dpi, было изменено на 72dpi (для интернета). Этот вопрос связан с еще вопрос здесь, где я работаю.
Я создание метод расширения для этого, чтобы иметь возможность использовать эту функцию на нескольких местах в моем приложении, а не только при загрузке новых файлов. (См. выше вопрос)
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();
}
}
упомянутое расширение methode вызывается в функции, аналогичной ситуации ниже;
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:WebsiteProjectExtensionsByteArrayExtensions.cs:line 356
at CMS.Presentation.FileFunctions.CreateFullsizeImage(HttpPostedFileBase uploadedFile, Size newSize, Byte[] uploadedFileBuffer) in C:WebsiteProjectCMS.PresentationFileFunctions.cs:line 197
at CMS.Presentation.FileFunctions.CreateFile(HttpPostedFileBase uploadedFile, INodeService nodeservice, Guid userId, Node parentNode) in C:WebsiteProjectCMS.PresentationFileFunctions.cs:line 53
в то же время я также разработал другую функцию (см. ниже) изменение размера только растрового изображения. И это, кажется, работает правильно. Я не могу использовать эту функцию с моей текущей реализацией, потому что она возвращает только растровое изображение. Или я должен изменить все, чтобы работать с bitmaps?
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;
}
4 ответов
потребовалось некоторое время, но я, наконец, нашел проблему! Проблема заключалась в функции ResizeImage, которую я использовал. В "GetThumbnailImage", если быть точным. Я столкнулся с другой проблемой с размытыми изображениями, что было объяснимо, потому что GetThumbnailImage растягивал созданный эскиз до нужного размера. И разрешение на миниатюре никогда не меняется.
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;
}
изменив функцию выше на функцию ниже, я смог решить проблему, используя Графика.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;
}
Ok, Я пробовал его только на файлах на жестком диске,но он также должен работать с потоками.
Bitmap bitmap = new Bitmap(loadFrom);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(72, 72);
newBitmap.Save(saveTo);
"изменяя разрешение", вы на самом деле имеете в виду, что хотите уменьшить количество пикселей в изображении на 72/300? Т. е. измените изображение 4000x3000 на 960x720?
Если это так, я не вижу, где ваш код на самом деле это делает. The перегрузка DrawImage () вы используете это:
рисует заданное изображение, используя его исходный фактический размер, в месте, заданном парой координат.
что событие.
попробовать одна из других перегрузок например этот:
рисует заданный объект Image в заданном месте, в заданный размер.
например:
// 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);
EDIT: в комментариях я понимаю, что OP хочет уменьшить размер файла без уменьшения количества пикселей. Поэтому файлы должны быть повторно сжаты.
я позаимствовал пример кода от здесь:
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);
Роб, я считаю, что проблема с вашим кодом заключается в сохранении изображения - фактические данные цифрового изображения будут определенным количеством точек/пикселей, т. е. (m x n), и установка разрешения на растровом изображении не изменит/не изменит количество точек (и, следовательно, физический размер байта изображения). Информация о разрешении будет храниться в заголовке изображения (для использования программами при печати/редактировании изображений) - что произойдет, если вы сохраните новое растровое изображение в файл вместо mem stream
newBitmap.Save("c:\test.png", ImageFormat.Png);
Регистрация dpi для вышеуказанного файла из файла - > свойства - > сводка (дополнительно). Он должен быть 72 dpi.