使用索引像素格式旋转图像?

时间:2012-08-02 23:02:14

标签: c# .net image image-processing bitmap

我试图弄清楚如何将我的位图图像旋转任意度数,类似于solution posted here。但是,当我尝试使用这个将Bitmap转换为Graphics对象的解决方案以及我用Google搜索过的其他解决方案时,我不断获得异常:

A Graphics object cannot be created from an image that has an indexed pixel format.

我需要索引像素,以便我可以访问每个像素并在程序中获取颜色信息,但我还需要能够以90度以外的度数增量旋转。

我想知道A)是否有一个对索引像素位图友好的解决方案,或B)如果有办法临时更改位图以允许它转换为Graphics对象然后将其更改回应用了旋转的索引像素位图?

提前多多谢谢!

编辑:我使用的位图的PixelFormat是" 1bppIndexed"。

2 个答案:

答案 0 :(得分:1)

我认为你在这里使用Windows窗体和GDI +?我已经做了相当多的工作,并且可以非常自信地告诉你,你想要使用24或32位图像(我不记得哪个抱歉)。性能大大提高了大约10到100倍的速度。在我的应用程序中,它在用户指定文本框中的旋转与仅使用鼠标抓取图像并在运行中平滑旋转,动态缩放等之间产生差异。

假设您遵循该建议,只留下能够访问每个像素的问题。为什么你认为你不能得到24或32位图像的每个像素?

编辑:在我的应用程序中,我只使用32位位图。如果我得到另一种格式的位图(例如从文件打开),我立即转换它。实际上,即使我得到32位格式,我也会立即克隆它,然后处理原始位图,因为我发现它在文件上保留了一些锁。内置克隆产生奇怪的结果,所以我最终编写下面的代码。请注意,这是我8年前写的东西,所以不使用任何最新功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace ImageCloneTest
{
    static class Program
    {
        [DllImport("kernel32", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(byte* Destination, byte* Source, int Length);

        [DllImport("kernel32", EntryPoint = "RtlMoveMemory")]
        public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);


        public static Bitmap Clone(Bitmap SourceBitmap, PixelFormat Format)
        {
            // copy image if pixel format is the same
            if (SourceBitmap.PixelFormat == Format) return Clone(SourceBitmap);

            int width = SourceBitmap.Width;
            int height = SourceBitmap.Height;

            // create new image with desired pixel format
            Bitmap bitmap = new Bitmap(width, height, Format);

            // draw source image on the new one using Graphics
            Graphics g = Graphics.FromImage(bitmap);
            //fill background in case orig bitmap contains transparent regions.
            g.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
            g.DrawImage(SourceBitmap, 0, 0, width, height);
            g.Dispose();

            return bitmap;
        }

        // and with unspecified PixelFormat it works strange too
        public static Bitmap Clone(Bitmap SourceBitmap)
        {
            // get source image size
            int width = SourceBitmap.Width;
            int height = SourceBitmap.Height;
            Rectangle rect = new Rectangle(0, 0, width, height);

            // lock source bitmap data
            BitmapData srcData = SourceBitmap.LockBits(rect, ImageLockMode.ReadOnly, SourceBitmap.PixelFormat);

            // create new image
            Bitmap dstBitmap = new Bitmap(width, height, SourceBitmap.PixelFormat);

            // lock destination bitmap data
            BitmapData dstData = dstBitmap.LockBits(rect, ImageLockMode.WriteOnly, dstBitmap.PixelFormat);

            CopyMemory(dstData.Scan0, srcData.Scan0, height * srcData.Stride);

            // unlock both images
            dstBitmap.UnlockBits(dstData);
            SourceBitmap.UnlockBits(srcData);

            // copy pallete
            if (BitmapHasPalette(SourceBitmap) && BitmapHasPalette(dstBitmap))
            {
                ColorPalette srcPalette = SourceBitmap.Palette;
                ColorPalette dstPalette = dstBitmap.Palette;
                int n = srcPalette.Entries.Length;
                for (int i = 0; i < n; i++)
                {
                    dstPalette.Entries[i] = srcPalette.Entries[i];
                }
                dstBitmap.Palette = dstPalette;
            }
            return dstBitmap;
        }

        public static bool BitmapHasPalette(Bitmap SourceBitmap)
        {
            if (SourceBitmap == null) return false;
            switch (SourceBitmap.PixelFormat)
            {
                case PixelFormat.Format1bppIndexed:
                case PixelFormat.Format4bppIndexed:
                case PixelFormat.Format8bppIndexed:
                case PixelFormat.Indexed:
                    return true;
            }
            return false;
        }
    }
}

答案 1 :(得分:0)

我在这里使用了汉斯的解决方案:https://stackoverflow.com/a/2016509/1464630

似乎我仍然可以使用相同的程序逻辑,但它不再是索引像素格式,因此Graphics类不会抱怨。