Хотя я не гуру в формате JPEG, я провел некоторое исследование по этому вопросу, и вот что я нашел, что могло бы помочь вам в решении вашей проблемы/вопросов.
Обратите внимание, что этот ответ предполагает, а не конкретно указывает источник вашей проблемы из-за отсутствия файла примера для проверки и указания того, что его отличает от того, что ожидает декодер .Net/GDI + JPEG/JFIF.
Формат JPEG/JFIF
Начинание, вы можете иметь некоторое представление о самом формате JPEG/JFIF. В конце концов, вы только что столкнулись с файлом, который .Net/GDI + не может загрузить/разбор. Поскольку у меня нет файла, с которым возникают проблемы, я бы предложил загрузить его в шестнадцатеричном редакторе, который имеет возможность выделить файл на основе шаблона/кода/парсера.
Я использовал 010 Editor и JPEG Template из репозитория шаблонов Sweetscape. Редактор 010 поставляется с 30-дневной бесплатной пробной версией.
Что вы конкретно ищете, SOF п идентификатор и данные в вашем плохой JPEG.
В SOF данных в п я могу видеть, что мое изображение Y (154) пикселей в высоту и Х (640) пикселей в ширину с точностью до 8 бит на компонент с использованием 3 компонентов, делая его 24 бит на пиксель.
Формат JPEG/JFIF - это огромное сочетание множества различных реализаций/форматов. Очевидно, что вы не найдете каждый вариант формата в любой библиотеке, которая существует с тех пор, как появились нечетные Форматы JPEG. Которая имеет библиотеку GDI +.
В вашем случае, я подозреваю, что вы запустили цветной профиль CMYK в ваших файлах JPEG.
Реализация .Net
Вы сказали, что вы использовали System.Drawing.Graphics.FromImage так что я буду считать, что ваш код выглядит как один из следующих способов:
Graphics.FromImage(Image.FromFile("nope.jpg"));
Graphics.FromImage(Image.FromFile("nope.jpg", true));
Graphics.FromImage(Image.FromStream(nopeJpegStream));
Из этих звонков, вы может получить OutOfMemoryException, когда родной gdiplus.dll называет ...
- GdipGetImageGraphicsContext
- GdipLoadImageFromFile
- GdipLoadImageFromFileICM (или их соответствующие * Стрит варианту) или
- GdipImageForceValidation
... возвращает код 3 или 5 (из памяти или Недостаточных буферов соответственно)
Что я собрал с sourcesource.microsoft.com, просматривая источники .Net.
В любом случае это скорее всего не проблема с .Net, а проблема с GDI + (gdiplus.dll), для которой Microsoft не предоставляет исходный код. Это также означает, что нет способа контролировать загрузку изображения с использованием оберток .Net, и нет способа проверить, ПОЧЕМУ он терпит неудачу. (хотя я все еще подозреваю, что ваш JPEG сохранен с помощью CMYK)
К сожалению, вы найдете много других из этих странных исключений/ошибок, которые вы двигаетесь в GDI +. Поскольку библиотека почти устарела в пользу Windows Presentation Framework (WPF) и компонента Windows Imaging. (WIC)
Мое собственное тестирование
Поскольку вы не предоставили изображение или какие-либо дополнительные сведения по этому вопросу я попытался воспроизвести проблему. Это само по себе само по себе, Image.FromFile (GdipLoadImageFromFile) провалится во многих разных форматах файлов.По крайней мере, не важно, что такое расширение файла, что, к счастью, делает Photoshop.
Итак, я, наконец, сумел воспроизвести файл .jpg, который загружается отлично в Photoshop, показывает DPI как 96 и глубину бит как 32. Конечно, если бы я знал больше о формате JPEG, возможно, к решению сразу.
Показаны этот файл (который я должен был установить в CMYK цветового пространства в Photoshop) в 010 Редактор дал мне следующий SOF п данные: Y (154) пикселей в высоту и X (640) пикселей в ширину с точность 8 бит на компонент с использованием компонентов, составляющих 32 бита на пиксель.
Я подозреваю, что вы увидите то же самое в своем «плохом» файле.
И да, Image.FromFile теперь выбрасывает OutOfMemoryException!
Возможные решения
- Используйте внешнюю библиотеку для загрузки файлов изображений. (Упражнение, которое я оставляю вам, но ImageMagick A.K.A Magick.NET кажется хорошей ставкой)
- Используйте инструмент командной строки (вызывается при получении этого исключения), который может преобразовывать изображение из одного формата в другой. Или из JPEG в JPEG, как это может быть в этом случае. (Еще раз, ImageMagick в "преобразовать" инструмент командной строки, кажется, хорошая ставка)
Используйте Windows Presentation Framework сборки ...
public static Image ImageFromFileWpf(string filename) {
/* Load the image into an encoder using the Presentation Framework.
* This is done by adding a frame (which in laymans terms is a layer) to a class derived BitmapEncoder.
* Only TIFF, Gif and JPEG XR supports multiple frames.
* Since we are going to convert our image to a GDI+ resource we won't support this as GDI+ doesn't (really) support it either.
* If you want/need support for layers/animated Gif files, create a similar method to this one that takes a BitmapFrame as an argument and then...
* 1. Instanciate the appropriate BitmapDecoder.
* 2. Iterate over the BitmapDecoders frames, feeding them to the new method.
* 3. Store the returned images in a collection of images.
*
* Finally, i opted to use a PngBitmapEncoder here which supports image transparency.
*/
var bitmapEncoder = new PngBitmapEncoder();
bitmapEncoder.Frames.Add(BitmapFrame.Create(new Uri(filename)));
// Use a memorystream as a handover from one file format to another.
using (var memoryStream = new MemoryStream()) {
bitmapEncoder.Save(memoryStream);
/* We MUST create a copy of our image from stream, MSDN specifically states that the stream must remain
* open throughout the lifetime of the image.
* We cannot instanciate the Image class, so we instanciate a Bitmap from our temporary image instead.
* Bitmaps are derived from Image anyways, so this is perfectly fine.
*/
var tempImage = Image.FromStream(memoryStream);
return new Bitmap(tempImage);
}
}
на основе this answer ...
... Я бы сказал, что это хороший вариант, поскольку он держит вас в рамках .Net.
Пожалуйста, имейте в виду, что при возврате метода вы получаете изображение PNG. Если вы назовете Image.Save(string)
на нем вы WILL Сохраните файл PNG, независимо от того, какое расширение вы его сохраните.
Существует перегрузка Image.Save(string, ImageFormat)
, которая сохранит файл, используя формат файла. Однако использование этой перегрузки с ImageFormat.Jpeg
приведет к потере качества в результирующем файле на более чем одном уровне.
Это может быть несколько исправлено с помощью третьей перегрузки:
foreach (var encoder in ImageCodecInfo.GetImageEncoders()) {
if (encoder.MimeType == "image/jpeg")
image.Save(filename, encoder, new EncoderParameters { Param = new [] { new EncoderParameter(Encoder.Quality, 100L) }});
}
Который, по крайней мере, сохранит JPEG с «почти» без сжатия. GDI + по-прежнему не очень хорошо справляется с этим.
Однако, независимо от того, сколько вы крутите и поворачиваете. GDI + не будет столь же хорош, как и соответствующая библиотека изображений, которая, скорее всего, будет ImageMagick. Чем дальше вы можете получить от GDI +, тем лучше будет.
Заключение/TL: DR и другие примечания.
Вопрос: Могу ли я загрузить эти файлы в .Net?
A: Да, с немного возиться и не использовать GDI + для начальной загрузки файла, так как GDI + не поддерживает цветовое пространство CMYK в файлах JPEG.
И даже при том, что GDI + не поддерживает поддержку многих вещей, поэтому я бы порекомендовал внешнюю библиотеку изображений над GDI +.
Q: Несовпадение в ДПИ и битовая глубина для файлов между Windows, и < вставкой приложением фото здесь >
A: Это просто доказательство того, что Windows, JPEG загрузка отличается от других приложений JPEG погрузочных процедур. Только приложения, которые используют GDI или GDI +, будут видеть ту же информацию, что и Windows при отображении деталей изображения.
Если вы используете Windows 7+, то он не использует GDI + для отображения информации или изображения. Для этого используется WPF или WIC, которые несколько более актуальны.
Q: Если открыть файл в формате JPG с помощью графической программы и просто повторно сохранить, ничего не меняя, свойства файла в проводнике Windows теперь соответствуют/прочитать правильно (72 точек на дюйм и 24-битовую)
A : Если вы используете Adobe Photoshop и используете «Сохранить для Интернета», изображение JPEG не будет сохранено в формате CMYK. Вместо этого используйте «Сохранить как ...», и вы обнаружите, что цветовое пространство (и глубина бит) остается неизменным.
Однако, я не смог воспроизвести ваше несоответствие в DPI и глубине бита при загрузке моего файла в Photoshop. Они сообщаются как в Windows, так и в Photoshop.
Как эти файлы JPEG были созданы? похоже, что их форматирование некорректно ... – Tigran
С какого типа приложения вы получаете эту ошибку? Поместите некоторый код. Вы вызываете dispose на объекты, такие как system.drawing.Image, которые реализуют IDispose? – Mick
Перейти к началу проблемы, которая является источником этих плохих файлов. Я видел, что jpeg плохо перепутался, например. миниатюра, показывающая что-то все неправильно, без какого-либо способа ее исправить, кроме сохранения в tif и обратно в jpeg .. – TaW