[英]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
參數上使用out
和ref
會導致錯誤的額外間接級別。
在任何情況下,您都需要為此類型執行一些自定義編組。 這不是最簡單的任務,也不是我特別想在這個答案中涉及的任務。 它將涉及手動內存分配和結構編組。
一個不太重要的錯誤是您使用了SetLastError
。 這些函數不設置 Win32 上一個錯誤值。 您應該刪除屬性的那一部分。
錯誤檢查很重要。 你沒有這樣做。 您確實需要檢查這些 GDI+ 函數的返回值。 由於上面討論的原因,我很確定對GdipInitializePalette
的調用將返回一個指示失敗的值。
我想指出一個文檔中沒有提到的巨大問題。
當您調用GdipInitializePalette時:
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.