有人知道如何使用C#在ASP.NET中正确识别CMYK图像吗?当我检查Flags
实例的Bitmap
属性时,我得到的结果不正确。
我创建了三个图像来测试它:cmyk.jpg,rgb.jpg和gray.jpg。这些分别是CMYK,RGB和灰度图像。
这是我的测试代码:
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;
}
这会产生以下输出:
我已经检查了实际图像,cmyk.jpg确实是 CMYK图像。
显然,这是一个“已知问题”。 Alex Gil在WPF中遇到了同样的问题(请参阅此问题:How to identify CMYK images using C#)并且他设法通过使用BitmapDecoder
类来加载图像来解决它。我在ASP.NET中使用该解决方案有点不舒服,因为它要求我添加对WindowsBase.dll和PresentationCore.dll的引用,我不确定我是否想在Web项目中使用它们。
有没有人知道任何其他纯.NET解决方案来检查图像是否是我可以在ASP.NET中安全使用的CMYK格式?
答案 0 :(得分:10)
我使用ImageFlags和PixelFormat值的组合。请注意,.NET中缺少PixelFormat.Forma32bppCMYK - 我在Windows SDK中将其从GdiPlusPixelFormats.h中删除。
诀窍是Windows 7和Server 2008 R2返回正确的像素格式但缺少图像标记。 Vista和Server 2008返回无效的像素格式,但正确的图像标记。精神错乱。
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
}
答案 1 :(得分:2)
一个想法:如果您不想在您的Web项目中引用这些dll,您可以在Web服务之外的服务中进行处理,这可能会更好吗?
答案 2 :(得分:1)
你可以查看FreeImage这是一个win32 DLL,但有一个.NET包装器,我在生产环境中使用它,它很棒。
如果无法提供此信息,我会感到惊讶。
(编辑)在您要求纯 .NET解决方案之前我没有注意到 - 所以这可能不起作用 - 但我发现它是对.NET限制的有用补充图像处理框架。
如果您只需要识别格式,另一个想法是直接从文件中提取它。我不知道JPEG格式的规范有多复杂,但是嘿,它只是29 pages!
答案 3 :(得分:1)
作为previously answered,最可靠的方法是解析文件的标头以检索此数据。
答案 4 :(得分:0)
所以这就是我如何解决你遇到的问题,这和我的问题一样。当你知道它是100%的cymk图像时,csharp中的所有内容都会返回rgb信息。那么该做什么,去root并读取文件。以下是我所做的测试,并且测试得很好,应该覆盖所有操作系统,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;
}
}
}
欢呼 - 杰里米
答案 5 :(得分:-1)
我假设.NET中的所有内容都基于RGB
,aRGB
和灰度(灰度为RGB(128,128,128))。
如果我的假设是正确的,那么你将不得不走第三方路线。