16

有人知道如何使用 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 中遇到了同样的问题(请参阅这个问题:如何使用 C# 识别 CMYK 图像),他设法通过使用一个BitmapDecoder类来加载图像来解决它。在 ASP.NET 中使用该解决方案我有点不舒服,因为它需要我添加对 WindowsBase.dll 和 PresentationCore.dll 的引用,而且我不确定我是否希望将它们用于 Web 项目。

有谁知道任何其他纯 .NET 解决方案来检查图像是否是我可以在 ASP.NET 中安全使用的 CMYK 格式?

4

6 回答 6

13

我使用 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
}
于 2012-03-28T01:14:50.907 回答
2

一个想法:如果您不想在您的 Web 项目中引用这些 dll,您可以在 Web 项目之外的服务中进行处理,这可能会更好吗?

于 2011-02-21T15:04:33.243 回答
1

您可以查看FreeImage,它是一个 win32 DLL,但有一个 .NET 包装器,我在生产环境中使用它,它很棒。

如果它不能提供这些信息,我会感到惊讶。

(编辑)在您要求纯.NET 解决方案之前我没有注意到- 所以这可能行不通 - 但我发现它是对 .NET 框架图像处理限制的有用补充。

如果您只需要识别格式,另一个想法是直接从文件中提取它。我不知道 JPEG 格式的规范有多复杂,但是嘿,它只有29 页!

于 2011-02-24T19:42:14.053 回答
1

如前所述,最可靠的方法是解析文件的标题以检索此数据

于 2011-03-02T03:12:58.097 回答
0

所以这就是我如何解决您遇到的问题,这与我遇到的问题相同。当您知道它是 100% 的 cymk 图像时,csharp 中的所有内容都会返回 rgb 信息。那么该怎么办,那就去根目录读取文件吧。这是我所做的并经过测试可以正常工作,并且应该涵盖所有操作系统,并且 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;
            }
        }
    }

干杯 - 杰里米

于 2012-02-28T17:59:46.737 回答
-1

我假设 .NET 中的所有内容都基于RGB,aRGB和灰度(因为灰度是 RGB(128, 128, 128))。

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

于 2011-02-24T19:32:06.103 回答