如何将此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一代似乎是个问题。任何提示?
答案 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
参数上使用ref
和ColorPalette
会导致错误的额外间接级别。
在任何情况下,您都需要为此类型执行一些自定义编组。这不是最简单的任务,也不是我在这个答案中特别想要的。它将涉及手动内存分配和结构编组。
一个不太重要的错误是您使用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%正确,但至少它有点工作(图像仍然呈现'条带'效果)。