在C#中将双色调TIFF转换为双色调PNG [英] convert bitonal TIFF to bitonal PNG in C#

查看:76
本文介绍了在C#中将双色调TIFF转换为双色调PNG的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将黑白(黑白)TIFF文件转换为另一种格式,以供网络浏览器显示,当前我们使用的是JPG,但该格式并不重要.从.NET的阅读看来,似乎并不容易地支持编写二进制图像,因此我们最终只能获得约1MB的文件,而不是约100K的文件.我正在考虑使用ImageMagick进行此操作,但理想情况下,我希望找到一种可能的情况下不需要此方法的解决方案.

I need to convert bitonal (black and white) TIFF files into another format for display by a web browser, currently we're using JPGs, but the format isn't crucial. From reading around .NET doesn't seem to easily support writing bitonal images, so we're ending up with ~1MB files instead of ~100K ones. I'm considering using ImageMagick to do this, but ideally i'd like a solution which doesn't require this if possible.

当前代码段(还会对图片进行一些调整):

Current code snippet (which also does some resizing on the image):

using (Image img = Image.FromFile(imageName))
{
    using (Bitmap resized = new Bitmap(resizedWidth, resizedHeight)
    {
        using (Graphics g = Graphics.FromImage(resized))
        {
            g.DrawImage(img, new Rectangle(0, 0, resized.Width, resized.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
        }

        resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Jpeg);

    }
}

有什么办法可以做到这一点?

Is there any way to achieve this?

谢谢.

推荐答案

我相信可以通过检查resized位图是否为PixelFormat.Format1bppIndexed来解决该问题.如果不是,则应将其转换为1bpp位图,然后可以将其另存为黑白png.

I believe the problem can be solved by checking that resized bitmap is of PixelFormat.Format1bppIndexed. If it's not, you should convert it to 1bpp bitmap and after that you can save it as black and white png without problems.

换句话说,您应该使用以下代码代替resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Jpeg);

In other words, you should use following code instead of resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Jpeg);

if (resized.PixelFormat != PixelFormat.Format1bppIndexed)
{
    using (Bitmap bmp = convertToBitonal(resized))
        bmp.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
else
{
    resized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}

我对convertToBitonal使用以下代码:

private static Bitmap convertToBitonal(Bitmap original)
{
    int sourceStride;
    byte[] sourceBuffer = extractBytes(original, out sourceStride);

    // Create destination bitmap
    Bitmap destination = new Bitmap(original.Width, original.Height,
        PixelFormat.Format1bppIndexed);

    destination.SetResolution(original.HorizontalResolution, original.VerticalResolution);

    // Lock destination bitmap in memory
    BitmapData destinationData = destination.LockBits(
        new Rectangle(0, 0, destination.Width, destination.Height),
        ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

    // Create buffer for destination bitmap bits
    int imageSize = destinationData.Stride * destinationData.Height;
    byte[] destinationBuffer = new byte[imageSize];

    int sourceIndex = 0;
    int destinationIndex = 0;
    int pixelTotal = 0;
    byte destinationValue = 0;
    int pixelValue = 128;
    int height = destination.Height;
    int width = destination.Width;
    int threshold = 500;

    for (int y = 0; y < height; y++)
    {
        sourceIndex = y * sourceStride;
        destinationIndex = y * destinationData.Stride;
        destinationValue = 0;
        pixelValue = 128;

        for (int x = 0; x < width; x++)
        {
            // Compute pixel brightness (i.e. total of Red, Green, and Blue values)
            pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] +
                sourceBuffer[sourceIndex + 3];

            if (pixelTotal > threshold)
                destinationValue += (byte)pixelValue;

            if (pixelValue == 1)
            {
                destinationBuffer[destinationIndex] = destinationValue;
                destinationIndex++;
                destinationValue = 0;
                pixelValue = 128;
            }
            else
            {
                pixelValue >>= 1;
            }

            sourceIndex += 4;
        }

        if (pixelValue != 128)
            destinationBuffer[destinationIndex] = destinationValue;
    }

    Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
    destination.UnlockBits(destinationData);
    return destination;
}

private static byte[] extractBytes(Bitmap original, out int stride)
{
    Bitmap source = null;

    try
    {
        // If original bitmap is not already in 32 BPP, ARGB format, then convert
        if (original.PixelFormat != PixelFormat.Format32bppArgb)
        {
            source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
            source.SetResolution(original.HorizontalResolution, original.VerticalResolution);
            using (Graphics g = Graphics.FromImage(source))
            {
                g.DrawImageUnscaled(original, 0, 0);
            }
        }
        else
        {
            source = original;
        }

        // Lock source bitmap in memory
        BitmapData sourceData = source.LockBits(
            new Rectangle(0, 0, source.Width, source.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        // Copy image data to binary array
        int imageSize = sourceData.Stride * sourceData.Height;
        byte[] sourceBuffer = new byte[imageSize];
        Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);

        // Unlock source bitmap
        source.UnlockBits(sourceData);

        stride = sourceData.Stride;
        return sourceBuffer;
    }
    finally
    {
        if (source != original)
            source.Dispose();
    }        
}

这篇关于在C#中将双色调TIFF转换为双色调PNG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆