簡體   English   中英

C# p/invoke 用於 GdipBitmapConvertFormat

[英]C# p/invoke for GdipBitmapConvertFormat

如何將此 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");
}

但是抖動不起作用:(

托盤一代似乎是問題所在。 有什么提示嗎?

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% 正確,但至少它有點工作(圖像仍然呈現“條帶”效果)。

查看要匹配的兩個函數:

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的處理是錯誤的。 這是一個可變大小的結構。 顏色數組具有可變長度。 你似乎並不滿足於此。 而且您已將其聲明為類而不是結構。 這意味着您在ColorPalette參數上使用outref會導致錯誤的額外間接級別。

在任何情況下,您都需要為此類型執行一些自定義編組。 這不是最簡單的任務,也不是我特別想在這個答案中涉及的任務。 它將涉及手動內存分配和結構編組。

一個不太重要的錯誤是您使用了SetLastError 這些函數不設置 Win32 上一個錯誤值。 您應該刪除屬性的那一部分。

錯誤檢查很重要。 你沒有這樣做。 您確實需要檢查這些 GDI+ 函數的返回值。 由於上面討論的原因,我很確定對GdipInitializePalette的調用將返回一個指示失敗的值。

我想指出一個文檔中沒有提到的巨大問題。

當您調用GdipInitializePalette時:

  • 你告訴它你希望它創建一個 256 色的最佳調色板
  • 並傳遞一個指向緩沖區的指針,該緩沖區足夠大以容納ColorPalette標頭和 256 個 DWORD 顏色值。
struct ColorPalette 
{
   UInt32 flags;
   UInt32 count;
   UInt32[256] entries;
}
ColorPalette palette;

GdipInitializePalette(palette, PaletteTypeOptimal, 256, False, bitmap);

這個想法是GdipInitializePalette將為您填充ColorPalette緩沖區。

但這並不完全正確。 即使您在調色板中指定了256種顏色,您也需要指定palette.count = 256

ColorPalette palette;
palette.count = 256; //must tell it twice that you want 256 colors
GdipInitializePalette(palette, PaletteTypeOptimal, 256, False, bitmap);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM