C#p /调用GdipBitmapConvertFormat

时间:2014-01-10 20:17:30

标签: c# c++ pinvoke

如何将此Gdi + 1.1签名转换为C#p / invoke?:

GpStatus WINGDIPAPI GdipBitmapConvertFormat(IN GpBitmap *pInputBitmap, 
PixelFormat format, DitherType dithertype, PaletteType palettetype, 
ColorPalette *palette, REAL alphaThresholdPercent);

http://msdn.microsoft.com/en-us/library/windows/desktop/ms536306(v=vs.85).aspx

我现在所拥有的是:

internal static class GdiPlusWrapper
{
    [DllImport("gdiplus.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
    public static extern Status GdipBitmapConvertFormat(HandleRef bitmap,
        PixelFormat format, DitherType dithertype, PaletteType palettetype,
        ColorPalette palette, float alpha);

    [DllImport("gdiplus.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
    public static extern Status GdipInitializePalette(out ColorPalette pallete,
        PaletteType palettetype, int optimalColors, bool useTransparentColor,
        HandleRef bitmap);

    internal enum DitherType
    {
        DitherTypeNone = 0,
        DitherTypeSolid = 1,
        DitherTypeOrdered4x4 = 2,
        DitherTypeOrdered8x8 = 3,
        DitherTypeOrdered16x16 = 4,
        DitherTypeOrdered91x91 = 5,
        DitherTypeSpiral4x4 = 6,
        DitherTypeSpiral8x8 = 7,
        DitherTypeDualSpiral4x4 = 8,
        DitherTypeDualSpiral8x8 = 9,
        DitherTypeErrorDiffusion = 10,
    }

    internal enum PaletteType
    {
        PaletteTypeCustom = 0,
        PaletteTypeOptimal = 1,
        PaletteTypeFixedBW = 2,
        PaletteTypeFixedHalftone8 = 3,
        PaletteTypeFixedHalftone27 = 4,
        PaletteTypeFixedHalftone64 = 5,
        PaletteTypeFixedHalftone125 = 6,
        PaletteTypeFixedHalftone216 = 7,
        PaletteTypeFixedHalftone252 = 8,
        PaletteTypeFixedHalftone256 = 9
    }

    internal enum Status
    {
        Ok = 0,
        GenericError = 1,
        InvalidParameter = 2,
        OutOfMemory = 3,
        ObjectBusy = 4,
        InsufficientBuffer = 5,
        NotImplemented = 6,
        Win32Error = 7,
        WrongState = 8,
        Aborted = 9,
        FileNotFound = 10,
        ValueOverflow = 11,
        AccessDenied = 12,
        UnknownImageFormat = 13,
        FontFamilyNotFound = 14,
        FontStyleNotFound = 15,
        NotTrueTypeFont = 16,
        UnsupportedGdiplusVersion = 17,
        GdiplusNotInitialized = 18,
        PropertyNotFound = 19,
        PropertyNotSupported = 20,
        ProfileNotFound = 21
    }

    internal static T GetPrivateField<T>(this object obj, string fieldName)
    {
        if (obj == null) return default(T);

        var ltType = obj.GetType();
        var lfiFieldInfo = ltType.GetField(fieldName,
            BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);

        if (lfiFieldInfo != null)
            return (T) lfiFieldInfo.GetValue(obj);
        throw new InvalidOperationException(
            String.Format("Instance field '{0}' could not be located in object of type '{1}'.", fieldName,
                obj.GetType().FullName));
    }
}

这就是你如何使用它:

var bitmap = new Bitmap(@"testing\image.png");
var bmpHandle = new HandleRef(bitmap, bitmap.GetPrivateField<IntPtr>("nativeImage"));
ColorPalette palette = null;

GdiPlusWrapper.GdipInitializePalette(out palette, GdiPlusWrapper.PaletteType.PaletteTypeOptimal, 0,
    true, bmpHandle);

foreach (GdiPlusWrapper.DitherType dither in Enum.GetValues(typeof(GdiPlusWrapper.DitherType)))
{

    GdiPlusWrapper.GdipBitmapConvertFormat(bmpHandle, PixelFormat.Format16bppRgb555,
       dither, GdiPlusWrapper.PaletteType.PaletteTypeFixedBW, ref palette, 0.0f);
    bitmap.Save(@"testing\image_" + dither + ".png");
}

但是抖动不起作用:(

pallete一代似乎是个问题。任何提示?

2 个答案:

答案 0 :(得分:1)

查看两个要匹配的函数:

<强> C ++

GpStatus WINGDIPAPI GdipBitmapConvertFormat(IN GpBitmap *pInputBitmap, 
    PixelFormat format, DitherType dithertype, PaletteType palettetype, 
    ColorPalette *palette, REAL alphaThresholdPercent);

<强> C#

[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, 
    CharSet = CharSet.Unicode)]
public static extern int GdipBitmapConvertFormat(HandleRef bitmap, 
    PixelFormat format, DitherType dithertype, ref ColorPalette palette, 
    float alpha);

很明显,您的函数具有不同的参数列表。参数计数不匹配。 C +有6个参数,C ++有5个参数。您错过了PaletteType参数。

最重要的是,您对ColorPalette的处理是错误的。这是一个可变大小的结构。颜色数组具有可变长度。你似乎不满足于此。并且您已将其声明为类而不是结构。这意味着您在out参数上使用refColorPalette会导致错误的额外间接级别。

在任何情况下,您都需要为此类型执行一些自定义编组。这不是最简单的任务,也不是我在这个答案中特别想要的。它将涉及手动内存分配和结构编组。

一个不太重要的错误是您使用SetLastError。这些函数不设置Win32上一个错误值。您应该删除属性的那一部分。

错误检查很重要。你没有这样做。您需要检查这些GDI +函​​数的返回值。由于上面讨论的原因,我很确定对GdipInitializePalette的调用将返回一个表示失败的值。

答案 1 :(得分:-1)

http://download.csdn.net/download/laviewpbt/4900954

中找到解决方案
// Source: http://download.csdn.net/download/laviewpbt/4900954
// Author: http://download.csdn.net/user/laviewpbt

namespace PrimeLib
{
    public enum DitherType
    {
        DitherTypeNone = 0,
        DitherTypeSolid = 1,
        DitherTypeOrdered4x4 = 2,
        DitherTypeOrdered8x8 = 3,
        DitherTypeOrdered16x16 = 4,
        DitherTypeSpiral4x4 = 5,
        DitherTypeSpiral8x8 = 6,
        DitherTypeDualSpiral4x4 = 7,
        DitherTypeDualSpiral8x8 = 8,
        DitherTypeErrorDiffusion = 9,
        DitherTypeMax = 10
    }
    public enum PaletteType
    {
        PaletteTypeCustom = 0,
        PaletteTypeOptimal = 1,
        PaletteTypeFixedBW = 2,
        PaletteTypeFixedHalftone8 = 3,
        PaletteTypeFixedHalftone27 = 4,
        PaletteTypeFixedHalftone64 = 5,
        PaletteTypeFixedHalftone125 = 6,
        PaletteTypeFixedHalftone216 = 7,
        PaletteTypeFixedHalftone252 = 8,
        PaletteTypeFixedHalftone256 = 9
    }

    public static class GdipEffect
    {
        [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern int GdipInitializePalette(ref GdiPalette Pal, int palettetype, int optimalColors,
            int useTransparentColor, IntPtr bitmap);

        [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern int GdipInitializePalette(int[] Pal, PaletteType palettetype, int optimalColors,
            int useTransparentColor, IntPtr bitmap);

        [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern int GdipBitmapConvertFormat(IntPtr bitmap, int pixelFormat, DitherType dithertype,
            PaletteType palettetype, ref GdiPalette Pal, float alphaThresholdPercent);

        [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern int GdipBitmapConvertFormat(IntPtr bitmap, int pixelFormat, DitherType dithertype,
            PaletteType palettetype, int[] Pal, float alphaThresholdPercent);

        [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern int GdipBitmapConvertFormat(IntPtr bitmap, int pixelFormat, DitherType dithertype,
            PaletteType palettetype, IntPtr Pal, float alphaThresholdPercent);

        public static void ChangeTo8bppIndexed(this Bitmap Bmp, PaletteType palettetype = PaletteType.PaletteTypeOptimal,
            DitherType ditherType = DitherType.DitherTypeErrorDiffusion, int optimalColors = 256)
        {
            int Entries;
            // http://msdn.microsoft.com/en-us/library/ms534159(v=vs.85).aspx
            switch (palettetype)
            {
                case PaletteType.PaletteTypeFixedBW:
                    Entries = 2;
                    break;
                case PaletteType.PaletteTypeFixedHalftone8:
                    Entries = 16;
                    break;
                case PaletteType.PaletteTypeFixedHalftone27:
                    Entries = 36;
                    break;
                case PaletteType.PaletteTypeFixedHalftone64:
                    Entries = 73;
                    break;
                case PaletteType.PaletteTypeFixedHalftone125:
                    Entries = 134;
                    break;
                case PaletteType.PaletteTypeFixedHalftone216:
                    Entries = 225;
                    break;
                case PaletteType.PaletteTypeFixedHalftone252:
                    Entries = 253;
                    break;
                case PaletteType.PaletteTypeFixedHalftone256:
                    Entries = 256;
                    break;
                case PaletteType.PaletteTypeOptimal:
                    if (optimalColors <= 0 || optimalColors > 256)
                        throw new ArgumentOutOfRangeException(
                            "Colors should be between 0 (inclusive) and 256 (exclusive)");
                    Entries = optimalColors;
                    break;
                default:
                    throw new ArgumentException("Error");
            }
            var Pal = new int[2 + Entries];
            Pal[0] = (int) PaletteFlags.GrayScale; // Flag
            Pal[1] = Entries; // Count
            if (palettetype == PaletteType.PaletteTypeOptimal)
                GdipInitializePalette(Pal, palettetype, Entries, 0, Bmp.NativeHandle());
            else
                GdipInitializePalette(Pal, palettetype, Entries, 0, IntPtr.Zero);
            if (palettetype == PaletteType.PaletteTypeOptimal)
                if (ditherType != DitherType.DitherTypeNone && ditherType != DitherType.DitherTypeSolid &&
                    ditherType != DitherType.DitherTypeErrorDiffusion)
                    throw new ArgumentException("Arguments error");
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format8bppIndexed), ditherType,
                palettetype, Pal, 50f);
        }

        public static void ChangeToSpecialIndexed(this Bitmap Bmp, PaletteType palettetype = PaletteType.PaletteTypeOptimal,
           DitherType ditherType = DitherType.DitherTypeErrorDiffusion, int optimalColors = 256)
        {
            int Entries;
            // http://msdn.microsoft.com/en-us/library/ms534159(v=vs.85).aspx
            switch (palettetype)
            {
                case PaletteType.PaletteTypeFixedBW:
                    Entries = 2;
                    break;
                case PaletteType.PaletteTypeFixedHalftone8:
                    Entries = 16;
                    break;
                case PaletteType.PaletteTypeFixedHalftone27:
                    Entries = 36;
                    break;
                case PaletteType.PaletteTypeFixedHalftone64:
                    Entries = 73;
                    break;
                case PaletteType.PaletteTypeFixedHalftone125:
                    Entries = 134;
                    break;
                case PaletteType.PaletteTypeFixedHalftone216:
                    Entries = 225;
                    break;
                case PaletteType.PaletteTypeFixedHalftone252:
                    Entries = 253;
                    break;
                case PaletteType.PaletteTypeFixedHalftone256:
                    Entries = 256;
                    break;
                case PaletteType.PaletteTypeOptimal:
                    if (optimalColors <= 0 || optimalColors > 256)
                        throw new ArgumentOutOfRangeException(
                            "Colors should be between 0 (inclusive) and 256 (exclusive)");
                    Entries = optimalColors;
                    break;
                default:
                    throw new ArgumentException("Error");
            }
            var Pal = new int[2 + Entries];
            Pal[0] = (int)PaletteFlags.GrayScale; // Flag
            Pal[1] = Entries; // Count
            if (palettetype == PaletteType.PaletteTypeOptimal)
                GdipInitializePalette(Pal, palettetype, Entries, 0, Bmp.NativeHandle());
            else
                GdipInitializePalette(Pal, palettetype, Entries, 0, IntPtr.Zero);
            if (palettetype == PaletteType.PaletteTypeOptimal)
                if (ditherType != DitherType.DitherTypeNone && ditherType != DitherType.DitherTypeSolid &&
                    ditherType != DitherType.DitherTypeErrorDiffusion)
                    throw new ArgumentException("Arguments error");
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format16bppArgb1555), ditherType,
                palettetype, Pal, 50f);
        }

        public static void ChangeTo4bppIndexed(this Bitmap Bmp, PaletteType palettetype = PaletteType.PaletteTypeOptimal,
            DitherType ditherType = DitherType.DitherTypeErrorDiffusion, int optimalColors = 16)
        {
            int Entries;
            // http://msdn.microsoft.com/en-us/library/ms534159(v=vs.85).aspx
            switch (palettetype)
            {
                case PaletteType.PaletteTypeFixedBW:
                    Entries = 2;
                    break;
                case PaletteType.PaletteTypeFixedHalftone8:
                    Entries = 16;
                    break;
                case PaletteType.PaletteTypeOptimal:
                    if (optimalColors <= 0 || optimalColors > 16)
                        throw new ArgumentOutOfRangeException("Colors should be between 0 (inclusive) and 16 (exclusive)");
                    Entries = optimalColors;
                    break;
                default:
                    throw new ArgumentException("Error");
            }
            var Pal = new int[2 + Entries];
            Pal[0] = (int) PaletteFlags.GrayScale; // Flag
            Pal[1] = Entries; // Count
            if (palettetype == PaletteType.PaletteTypeOptimal)
                GdipInitializePalette(Pal, palettetype, Entries, 0, Bmp.NativeHandle());
            else
                GdipInitializePalette(Pal, palettetype, Entries, 0, IntPtr.Zero);
            if (palettetype == PaletteType.PaletteTypeOptimal)
                if (ditherType != DitherType.DitherTypeNone && ditherType != DitherType.DitherTypeSolid &&
                    ditherType != DitherType.DitherTypeErrorDiffusion)
                    throw new ArgumentException("Arguments error");
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format4bppIndexed), ditherType,
                palettetype, Pal, 50f);
        }

        public static void ChangeTo1bppIndexed(this Bitmap Bmp,
            DitherType ditherType = DitherType.DitherTypeErrorDiffusion)
        {
            if (ditherType != DitherType.DitherTypeSolid && ditherType != DitherType.DitherTypeErrorDiffusion)
                throw new ArgumentException("Arguments error.");
            var Pal = new int[4];
            Pal[0] = (int) PaletteFlags.GrayScale; // Flag
            Pal[1] = 2; // Count
            GdipInitializePalette(Pal, PaletteType.PaletteTypeFixedBW, 2, 0, IntPtr.Zero);
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format1bppIndexed), ditherType,
                PaletteType.PaletteTypeFixedBW, Pal, 50f);
        }

        public static void ChangeTo16bppRgb555(this Bitmap Bmp,
            DitherType ditherType = DitherType.DitherTypeErrorDiffusion)
        {
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format16bppRgb555), ditherType,
                PaletteType.PaletteTypeCustom, IntPtr.Zero, 50f);
        }

        public static void ChangeTo24bppRgb(this Bitmap Bmp)
        {
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format24bppRgb),
                DitherType.DitherTypeNone, PaletteType.PaletteTypeCustom, IntPtr.Zero, 50f);
        }

        public static void ChangeTo32bppARGB(this Bitmap Bmp)
        {
            GdipBitmapConvertFormat(Bmp.NativeHandle(), Convert.ToInt32(PixelFormat.Format32bppArgb),
                DitherType.DitherTypeNone, PaletteType.PaletteTypeCustom, IntPtr.Zero, 50f);
        }

        internal static TResult GetPrivateField<TResult>(this object obj, string fieldName)
        {
            if (obj == null) return default(TResult);
            Type ltType = obj.GetType();
            FieldInfo lfiFieldInfo = ltType.GetField(fieldName,
                BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
            if (lfiFieldInfo != null)
                return (TResult) lfiFieldInfo.GetValue(obj);
            throw new InvalidOperationException(
                string.Format("Instance field '{0}' could not be located in object of type '{1}'.", fieldName,
                    obj.GetType().FullName));
        }

        public static IntPtr NativeHandle(this Bitmap Bmp)
        {
            return Bmp.GetPrivateField<IntPtr>("nativeImage");
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct GdiPalette
        {
            internal readonly PaletteFlags Flag;
            internal readonly int Count;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] internal readonly byte[] Entries;
        }
    }
}

这是已清理的文件(基本上只是删除中文字符): https://github.com/eried/PrimeComm/blob/7cbce9f16a0f647c43a6b69e7a77a820a0f80df4/PrimeLib/GdipEffect.cs

我非常接近,但似乎没有为非索引像素格式定义调色板。我不确定这是否100%正确,但至少它有点工作(图像仍然呈现'条带'效果)。