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

发布于 2024-10-18 04:01:00 字数 2600 浏览 8 评论 0原文

有谁知道如何使用 C# 正确识别 ASP.NET 中的 CMYK 图像?当我检查 Bitmap 实例的 Flags 属性时,我得到了不正确的结果。

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

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

Does anybody know how to properly identify CMYK images in ASP.NET using C#? When I check the Flags attribute of a Bitmap instance, I get incorrect results.

I have created three images to test this: cmyk.jpg, rgb.jpg and gray.jpg. These are respectively CMYK, RGB and Grayscale images.

This is my test code:

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;
}

This produces the following output:
Test results

I have checked the actual images and cmyk.jpg really is a CMYK image.

Apparently, this is a "known issue". Alex Gil had the same problem in WPF (see this question: How to identify CMYK images using C#) and he managed to solve it by using a BitmapDecoder class to load the images. I'm a bit uncomfortable using that solution in ASP.NET because it requires me to add references to WindowsBase.dll and PresentationCore.dll and I'm not sure I want those in a web project.

Does anyone know of any other pure .NET solutions to check if an image is in the CMYK format that I can safely use in ASP.NET?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

韬韬不绝 2024-10-25 04:01:00

我使用 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
}

I use a combination of the ImageFlags and PixelFormat values. Note that PixelFormat.Forma32bppCMYK is missing from .NET - I grabbed it out of GdiPlusPixelFormats.h in the Windows SDK.

The trick is that Windows 7 and Server 2008 R2 returns the correct pixel format but is missing the image flags. Vista and Server 2008 return an invalid pixel format but the correct image flags. 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
}
四叶草在未来唯美盛开 2024-10-25 04:01:00

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

An idea: If you dont want to reference those dll's in your web project, you could do the processing outside the web project, in a service, which may be better anyway?

独自唱情﹋歌 2024-10-25 04:01:00

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

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

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

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

You might check out FreeImage which is a win32 DLL but has a .NET wrapper, I am using it in a production enviroment and it's great.

I would be surprised if it couldn't provide this information.

(edit) I didn't notice before you asked for pure .NET solutions - so maybe this won't work - but I have found it a useful supplement to the limitations of the .NET framework for image manipulation.

Another idea, if you only need to identify the format, is to extract that directly from the file. I have no idea how complex the specification for the JPEG format might be, but hey, it's only 29 pages!

一抹苦笑 2024-10-25 04:01:00

正如之前回答的那样,最可靠的方法是解析文件头以检索此数据。

As previously answered, the most reliable way will be to parse the file's header to retrieve this data.

缘字诀 2024-10-25 04:01:00

因此,这就是我解决您遇到的问题的方法,该问题与我遇到的问题相同。当您知道它是 100% cymk 图像时,csharp 中的所有内容都会返回 rgb 信息。那么该怎么办呢,我们去根目录读取文件。这是我所做的,并经过测试,效果良好,应该涵盖所有操作系统,并且 50 个图像中的 50 个图像经过正确测试。这也是 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;
            }
        }
    }

干杯-杰里米

So here is how I solved the issue you were having which was the same as what I was having. Everything in csharp looks to return rgb info when you know it's a 100% a cymk image. So what to do, well go to the root and read the file. Here is what I had done and tested to work well and should cover all OS's, and 50 for 50 imgs tested right. This is 2.0 too just in case.

     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 - Jeremy

为你拒绝所有暧昧 2024-10-25 04:01:00

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

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

I was under the assumption that everything in .NET was based on RGB, aRGB and grayscale (as grayscale is RGB(128, 128, 128)).

If my assumption is correct then you will have to go the third party route.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文