Как идентифицировать изображения CMYK в ASP.NET с помощью С#
Кто-нибудь знает, как правильно идентифицировать изображения CMYK в ASP.NET с помощью С#? Когда я проверяю атрибут Flags
экземпляра Bitmap
, я получаю неправильные результаты.
Я создал три изображения, чтобы проверить это: cmyk.jpg, rgb.jpg и gray.jpg. Это соответственно изображения CMYK, RGB и Grayscale.
Это мой тестовый код:
static void Main(string[] args)
{
Bitmap bmpCMYK = new Bitmap("cmyk.jpg");
Bitmap bmpRGB = new Bitmap("rgb.jpg");
Bitmap bmpGray = new Bitmap("gray.jpg");
Console.WriteLine("\t\tRgb\tCmyk\tGray\tYcbcr\tYcck\tPixelFormat");
Console.WriteLine("cmyk.jpg\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpCMYK, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpCMYK.PixelFormat);
Console.WriteLine("rgb.jpg\t\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpRGB, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpRGB.PixelFormat);
Console.WriteLine("gray.jpg\t{0}\t{1}\t{2}\t{3}\t{4}\t{5}",
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceRgb),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceCmyk),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceGray),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceYcbcr),
IsSet(bmpGray, System.Drawing.Imaging.ImageFlags.ColorSpaceYcck),
bmpGray.PixelFormat);
bmpCMYK.Dispose();
bmpRGB.Dispose();
bmpGray.Dispose();
Console.ReadLine();
}
private static bool IsSet(Bitmap bitmap, System.Drawing.Imaging.ImageFlags flag)
{
return (bitmap.Flags & (int)flag) == (int)flag;
}
Это производит следующий вывод:
![Test results]()
Я проверил фактические изображения, а cmyk.jpg - действительно изображение CMYK.
По-видимому, это "известная проблема". У Alex Gil была такая же проблема в WPF (см. Этот вопрос: Как идентифицировать изображения CMYK с помощью С#), и ему удалось решить его, используя класс BitmapDecoder
для загрузки изображения. Мне немного неудобно использовать это решение в ASP.NET, потому что он требует, чтобы я добавлял ссылки на WindowsBase.dll и PresentationCore.dll, и я не уверен, что хочу это в веб-проекте.
Кто-нибудь знает какие-либо другие чистые .NET-решения, чтобы проверить, находится ли образ в формате CMYK, который я могу безопасно использовать в ASP.NET?
Ответы
Ответ 1
Я использую комбинацию значений ImageFlags и PixelFormat. Обратите внимание, что PixelFormat.Forma32bppCMYK отсутствует в .NET. Я выхватил его из GdiPlusPixelFormats.h в SDK Windows.
Фокус в том, что Windows 7 и Server 2008 R2 вернут правильный формат пикселей, но отсутствуют флаги изображений. Vista и Server 2008 возвращают неверный формат пикселей, но правильные флаги изображений. Insanity.
public ImageColorFormat GetColorFormat(this Bitmap bitmap)
{
const int pixelFormatIndexed = 0x00010000;
const int pixelFormat32bppCMYK = 0x200F;
const int pixelFormat16bppGrayScale = (4 | (16 << 8);
// Check image flags
var flags = (ImageFlags)bitmap.Flags;
if (flags.HasFlag(ImageFlags.ColorSpaceCmyk) || flags.HasFlag(ImageFlags.ColorSpaceYcck))
{
return ImageColorFormat.Cmyk;
}
else if (flags.HasFlag(ImageFlags.ColorSpaceGray))
{
return ImageColorFormat.Grayscale;
}
// Check pixel format
var pixelFormat = (int)bitmap.PixelFormat;
if (pixelFormat == pixelFormat32bppCMYK)
{
return ImageColorFormat.Cmyk;
}
else if ((pixelFormat & pixelFormatIndexed) != 0)
{
return ImageColorFormat.Indexed;
}
else if (pixelFormat == pixelFormat16bppGrayScale)
{
return ImageColorFormat.Grayscale;
}
// Default to RGB
return ImageColorFormat.Rgb;
}
public enum ImageColorFormat
{
Rgb,
Cmyk,
Indexed,
Grayscale
}
Ответ 2
Идея: если вы не хотите ссылаться на эти dll в своем веб-проекте, вы можете сделать обработку вне веб-проекта в службе, которая может быть в любом случае лучше?
Ответ 3
Вы можете проверить FreeImage, который является win32 DLL, но имеет оболочку .NET, я использую его в производственной среде и это здорово.
Я был бы удивлен, если бы не смог предоставить эту информацию.
(изменить) Я не заметил, прежде чем вы попросили чистые .NET-решения - возможно, это не сработает, но я нашел это полезным дополнением к ограничениям платформы .NET для манипуляций с изображениями.
Другая идея, если вам нужно всего лишь определить формат, - извлечь ее непосредственно из файла. Я понятия не имею, насколько сложна спецификация формата JPEG, но эй, это только 29 страниц!
Ответ 4
Как ранее ответили, самым надежным способом будет синтаксический анализ заголовка файла для извлечения этих данных.
Ответ 5
Итак, вот как я решил проблему, с которой вы столкнулись, что было тем же, что и у меня. Все в csharp выглядит, чтобы вернуть rgb-информацию, когда вы знаете, что это 100% изображение cymk. Итак, что делать, хорошо зайдите в корневой каталог и прочитайте файл. Вот что я сделал и протестировал, чтобы хорошо работать и должен охватывать все ОС, и 50 для 50 imgs проверены правильно. Это тоже 2.0 на всякий случай.
public bool isByteACMYK(Stream image)
{
using (StreamReader sr = new StreamReader(image))
{
string contents = sr.ReadToEnd();
if (contents.ToLower().Contains("cmyk"))
{
return true;
}
}
return false;
}
public bool isFileACMYKJpeg(System.Drawing.Image image)
{
System.Drawing.Imaging.ImageFlags flagValues = (System.Drawing.Imaging.ImageFlags)Enum.Parse(typeof(System.Drawing.Imaging.ImageFlags), image.Flags.ToString());
if (flagValues.ToString().ToLower().IndexOf("ycck") == -1)
{
// based on http://www.maxostudio.com/Tut_CS_CMYK.cfm
bool ret = false;
try{
int cmyk = (image.Flags & (int)ImageFlags.ColorSpaceCmyk);
int ycck = (image.Flags & (int)ImageFlags.ColorSpaceYcck);
ret = ((cmyk > 0) || (ycck > 0));
} catch (Exception ex){
}
return ret;
}
return true;
}
// my upload test .. but you could turn a file to stream and do the same
public void UpdatePool(HttpPostedFile newimage)
{
if (newimage.ContentLength != 0)
{
Stream stream = newimage.InputStream;
MemoryStream memoryStream = new MemoryStream();
CopyStream(stream,memoryStream);
memoryStream.Position = 0;
stream = memoryStream;
System.Drawing.Image processed_image = null;
processed_image = System.Drawing.Image.FromStream(newimage.InputStream);
if (imageService.isFileACMYKJpeg(processed_image) || imageService.isByteACMYK(stream))
{
Flash["error"] = "You have uploaded a CMYK image. Please conver to RGB first.";
RedirectToReferrer();
return;
}
}
}
cheers - Джереми
Ответ 6
Я был в предположении, что все в .NET было основано на RGB
, aRGB
и оттенках серого (в оттенках серого есть RGB (128, 128, 128)).
Если мое предположение верно, вам нужно будет пройти сторонний маршрут.