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

16

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

这将产生以下输出: 测试结果 我检查了实际的图像,cmyk.jpg确实是一张CMYK图像。
显然,这是一个“已知问题”。Alex Gil在WPF中遇到了同样的问题(见此问题:如何使用C#识别CMYK图像),他通过使用BitmapDecoder类来加载图像并解决了这个问题。在ASP.NET中使用这个解决方案让我感到有些不安,因为它要求我添加对WindowsBase.dll和PresentationCore.dll的引用,我不确定我是否想要在Web项目中添加这些引用。
有没有人知道任何其他纯.NET解决方案,可以安全地在ASP.NET中使用来检查图片是否为CMYK格式?
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
}

2
一个想法:如果你不想在你的Web项目中引用那些dll文件,你可以在Web项目外部的一个服务中进行处理,这可能更好?

这确实可能是一个解决方案,但我正在尝试创建一个小型且可重复使用的库,用于在Web应用程序中保存和调整图像大小。在这种情况下,我认为让它依赖于服务并不是一个好主意。 - Kristof Claes
+1 我本来也想给出差不多的答案:将图像处理与Web应用程序解耦。我过去做过这个,坦率地说,一旦你开始调整真正大的图像(在磁盘上不需要很大就可以在内存中很大),它很快变得混乱,无论是内存、CPU还是磁盘方面。现在所有的图像处理都由一个简单的服务处理,该服务使用Graphics Magick:我将作业文件(源图像、调整大小选项、目标图像)放在一个文件夹中,服务会接收并调整图像。这样Web服务就不会被占用了。 - Sébastien Nussbaumer

1

你可以尝试使用FreeImage,它是一个Win32 DLL但有一个.NET包装器,我正在生产环境中使用它,效果非常好。

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

(编辑) 我之前没有注意到你要求.NET解决方案 - 所以也许这个方法行不通 - 但我发现它是一个有用的补充,可以弥补.NET框架在图像处理方面的局限性。

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


1

0

所以这就是我解决你遇到的问题的方法,这个问题和我之前遇到的一样。在csharp中,所有东西看起来都返回rgb信息,但你知道它是100%的cymk图像。那么该怎么办呢?好吧,回到根目录并读取文件。这就是我所做的,并经过测试可以很好地工作,并且应该涵盖所有操作系统,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;
            }
        }
    }

干杯 - Jeremy


-1
我以为.NET中的所有内容都基于RGBaRGB和灰度(因为灰度是RGB(128, 128, 128))。
如果我的假设是正确的,那么你将不得不选择第三方路线。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接