如何使用C#在ASP.NET中识别CMYK图像

时间:2011-02-21 11:27:07

标签: asp.net image-processing bitmap cmyk

有人知道如何使用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;
}

这会产生以下输出: Test results

我已经检查了实际图像,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格式?

6 个答案:

答案 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中的所有内容都基于RGBaRGB和灰度(灰度为RGB(128,128,128))。

如果我的假设是正确的,那么你将不得不走第三方路线。