Почему IrfanView говорит, что мой jpg-файл является png-файлом?
Моя утилита должна изменять размер файлов.jpg или.png.
Кажется, он отлично работает в одном месте (на работе, где у меня не установлен IrfanView). Но дома, когда я открываю *.jpg и затем сохраняю его (изменяю размер), я вижу:
Тем не менее, изображение все равно отображается нормально в любом случае (независимо от того, выбрал ли я "Да" или "Нет" в диалоговом окне.
Теперь я могу загружать и сохранять как jpgs, так и pngs, и они сохраняются как таковые и отображаются нормально. Но IrfanView утверждает, что они запутались.
На самом деле, я не уверен, как изображение сохраняется; Я предполагал, что он просто сохранил его в правильном формате "за кулисами" на основе расширения. В любом случае, поскольку это довольно простая утилита, я просто покажу весь код:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png", FilterIndex = 2, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
//buttonResizeImage.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
// Two different ways of getting the int val
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
// If used a different extension (jpg where the original was png, or vice versa) would the Save be intelligent enough to actually save in the other format?
resizedImg.Save(newFilename);
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
... и графический интерфейс (непосредственно перед нажатием кнопки "Изменить размер изображения":
ОБНОВИТЬ
На основании комментария Евгения Ш. я изменил свой метод Save на следующий блок:
bool success = true;
. . .
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null &&
fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else
{
success = false;
}
if (success)
{
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
}
else
{
MessageBox.Show("Something went awry. The file was not saved");
}
ОБНОВЛЕНИЕ 2
Итак, вот мой новый код, реализующий предложение и поддерживающий несколько новых типов файлов:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png| BMP files (*.bmp)|*.bmp| TIFF files (*.tiff)|*.png| ICO files (*.ico)|*.ico| EMF files (*.emf)|*.emf| WMF files (*.wmf)|*.wmf",
FilterIndex = 1, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
if (String.IsNullOrWhiteSpace(_originalFilename)) return;
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
bool success = true;
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
// Two different ways of getting the int val
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("bmp"))
{
resizedImg.Save(newFilename, ImageFormat.Bmp);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("ico"))
{
resizedImg.Save(newFilename, ImageFormat.Icon);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("tiff"))
{
resizedImg.Save(newFilename, ImageFormat.Tiff);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("emf"))
{
resizedImg.Save(newFilename, ImageFormat.Emf);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("wmf"))
{
resizedImg.Save(newFilename, ImageFormat.Wmf);
}
else
{
success = false;
}
MessageBox.Show(success
? String.Format("Done! File saved as {0}", newFilename)
: "Something went awry. The file was not saved");
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
3 ответа
От Image.Save
документация:
Если кодировщик для формата файла изображения не существует, используется кодировщик Portable Network Graphics (PNG). При использовании метода "Сохранить" для сохранения графического изображения в виде файла формата метафайла Windows (WMF) или расширенного метафайла (EMF) полученный файл сохраняется в виде файла Portable Network Graphics (PNG). Это происходит потому, что компонент GDI+.NET Framework не имеет кодировщика, который можно использовать для сохранения файлов в формате.wmf или.emf.
Если вы хотите сохранить в другом формате, используйте перегруженный Save
метод, принимающий формат в качестве второго параметра:
Save(String, ImageFormat)
Подойдите к консоли и распечатайте файл. Если это файл PNG, вы увидите PNG и он остановится.
Если это JPEG, вы получите много мусора, но вы должны увидеть EXIF или JFIF в верхней части. Самое начало - FF D8
Поскольку JPEG и PNG имеют разные подписи, приложение может отличить их от содержимого и предложить соответствующий декодер.
Приложения для изображений обычно определяют тип изображения по содержимому потока, а не по расширению.
Большинство программ просмотра изображений не используют расширение файла для определения типа файла, а используют так называемые "магические числа" ( http://en.wikipedia.org/wiki/Magic_number_(programming)). Они в основном проверяют первые X байтов файла, которые часто уникальны для определенного формата изображения.
Я предполагаю, что используемая вами библиотека сохраняет файл в формате PNG по умолчанию (правка: см. Ответ Евгения), не учитывая, какое расширение вы там поместили. IrfanView замечает, что магическое число и расширение не совпадают, но все равно показывает изображение по умолчанию с магическим числом.