c# - 将 C# 位图转换为 Windows dib 句柄以用于 RIOT?

标签 c# c++ pinvoke dib

我正在尝试实现一个使用 RIOT(激进图像优化工具)进行批量图像优化的应用程序。我可以成功地将 riot.dll 导入到我的应用程序中。但我不知道如何将 Windows DIB(设备独立位图)句柄传递给 RIOT 函数。

这是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Riot_Test
{
    public partial class Form1 : Form
    {

        [DllImport("RIOT.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
        static extern bool RIOT_LoadFromDIB(IntPtr hDIB, IntPtr hwndParent, [MarshalAs(UnmanagedType.LPStr)] string fileName = "", [MarshalAs(UnmanagedType.LPStr)] string iniFile = "", int flags = 0, [MarshalAs(UnmanagedType.LPStr)] string buf = "");

        [DllImport("RIOT.dll")]
        static extern void RIOT_Show();

        [DllImport("RIOT.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
        static extern bool RIOT_LoadFromFile([MarshalAs(UnmanagedType.LPStr)] string filename, int flags = 0);

        [DllImport("RIOT.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool RIOT_SaveToFile(IntPtr hDIB, IntPtr hwndParent, [MarshalAs(UnmanagedType.LPStr)] string fileName, [MarshalAs(UnmanagedType.LPStr)] string origFilename = "", ulong byteSize = 0, [MarshalAs(UnmanagedType.LPStr)]  string errorText = "", int flags = 0, [MarshalAs(UnmanagedType.LPStr)] string buf = "");

        public Form1()
        {
            InitializeComponent();
            //RIOT_Show();
            IntPtr hdib = IntPtr.Zero;
            IntPtr hwnd = IntPtr.Zero;
            string errorText = "";

            Bitmap bmp = new Bitmap("dene.jpg");
            hdib = bmp.GetHbitmap();


            string fn = "optim2.jpg";
            string fno = "dene.jpg";
            bool result = RIOT_SaveToFile_U(hdib, hwnd, fn);


        }
    }
}

RIOT_Show()RIOT_Load_From_File() 按预期工作,但当我尝试调用 RIOT_SaveToFile() 时,它给出了此错误:

System.AccessViolationException was unhandled - Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

所以我的问题是:

  1. 如何将 System.Bitmap 对象转换为 Windows DIB 句柄?
  2. 如果我无法转换,是否可以使用 C++ 库(如果有)来为我完成这项工作并返回 DIB 句柄?

编辑:

我已将代码更改为此,但它给出了相同的错误。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace from_vb
{
    public partial class Form1 : Form
    {
        [DllImport("gdi32.dll", SetLastError = true)]
        static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
        static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        [DllImport("gdi32.dll")]
        static extern int GetObject(IntPtr hgdiobj, int cbBuffer, IntPtr lpvObject);

        [DllImport("gdi32.dll")]
        static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref GDI32BITMAPINFOHEADER pbmi, uint pila, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);

        [DllImport("gdi32.dll")]
        static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, uint uStartScan,
           uint cScanLines, [Out] byte[] lpvBits, ref GDI32BITMAPINFOHEADER lpbmi, uint uUsage);

        [DllImport("gdi32.dll")]
        static extern bool DeleteObject(IntPtr hObject);

        [DllImport("gdi32.dll")]
        static extern bool DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        static extern bool GdiFlush();

        [DllImport("RIOT.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool RIOT_SaveToFile(IntPtr hDIB, IntPtr hwndParent, [MarshalAs(UnmanagedType.LPStr)] string fileName, [MarshalAs(UnmanagedType.LPStr)] string origFilename = "", ulong byteSize = 0, [MarshalAs(UnmanagedType.LPStr)]  string errorText = "", int flags = 0, [MarshalAs(UnmanagedType.LPStr)] string buf = "");


        public const int BI_RGB = 0;
        public const int DIB_PAL_COLORS = 1;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct GDI32BITMAP
        {
            public int bmType;
            public int bmWidth;
            public int bmHeight;
            public int bmWidthBytes;
            public short bmPlanes;
            public short bmBitsPixel;
            public int bmBits;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct GDI32BITMAPINFOHEADER
        {
            public int biSize;
            public int biWidth;
            public int biHeight;
            public short biPlanes;
            public short biBitCount;
            public int biCompression;
            public int biSizeImage;
            public int biXPelsPerMeter;
            public int biYPelsPerMeter;
            public uint biClrUsed;
            public uint biClrImportant;

            public void Init()
            {
                biSize = (int)Marshal.SizeOf(this);
            }
        }



        public Form1()
        {
            InitializeComponent();
            IntPtr hdc = IntPtr.Zero;
            IntPtr hSrcBitmap = IntPtr.Zero;
            IntPtr pSrcBitmapInfo = IntPtr.Zero;
            IntPtr hDestDIBitmap = IntPtr.Zero;
            IntPtr hDstOldBitmap = IntPtr.Zero;
            IntPtr pDestDIBits = IntPtr.Zero;
            IntPtr hSection = IntPtr.Zero;
            IntPtr hwnd = IntPtr.Zero;
            IntPtr ccDC = IntPtr.Zero;

            Bitmap dotNetBitmap;
            int XDPI, YDPI;

            GDI32BITMAP srcBitmapInfo = new GDI32BITMAP();
            //ccDC = CreateCompatibleDC(hdc);
            IntPtr hDstMemDC = CreateCompatibleDC(hdc);
            GDI32BITMAPINFOHEADER DestDIBMIH = new GDI32BITMAPINFOHEADER();


            dotNetBitmap = new Bitmap("dene.jpg");
            hSrcBitmap = dotNetBitmap.GetHbitmap();
            pSrcBitmapInfo = Marshal.AllocCoTaskMem(Marshal.SizeOf(srcBitmapInfo));

            GetObject(hSrcBitmap, Marshal.SizeOf(srcBitmapInfo),pSrcBitmapInfo);
            srcBitmapInfo = (GDI32BITMAP)Marshal.PtrToStructure(pSrcBitmapInfo, srcBitmapInfo.GetType());




            if (pSrcBitmapInfo != IntPtr.Zero)
            {

                Marshal.FreeCoTaskMem(pSrcBitmapInfo);
            }

            DestDIBMIH.biSize = Marshal.SizeOf(DestDIBMIH);
            DestDIBMIH.biWidth = srcBitmapInfo.bmWidth;
            DestDIBMIH.biHeight = srcBitmapInfo.bmHeight;
            DestDIBMIH.biPlanes = srcBitmapInfo.bmPlanes;
            DestDIBMIH.biBitCount = 24;
            DestDIBMIH.biCompression = BI_RGB;

            hDestDIBitmap = CreateDIBSection(hDstMemDC, ref DestDIBMIH, 0, out pDestDIBits, hSection, 0);

            string fn = "optim2.jpg";
            string fno = "dene.jpg";
            bool hede = RIOT_SaveToFile(hDestDIBitmap, hwnd, fn);
        }
    }
}

最佳答案

这是该方法的“文档”:

bool RIOT_SaveToFile(HANDLE hDIB, HWND hwndParent,const char *fileName,const char *origFilename=”", unsigned long byteSize=0,char *errorText=”",int flags=0, char *buf=”")

Saves the file with the specified parameters.

Parameters:
hDIB – handle to a Windows DIB image in memory
hwndParent – Not Used. Must be NULL.
fileName – full path to the file to be saved (only JPEG is supported)
origFilename – Fill this with the original file name if the DIB is not different than the image from the file
byteSize – filesize of the compressed JPEG image in bytes
errorText – On error errorText is filled with the error message
flags – save flags. See bellow
buf – not used. Leave blank.THe function returns true on success or false on error.If you specify byteSize you can specify any of the save flags, but the quality will not be used.
If you don’t specify byteSize flags are used.
If there are no flags or byteSize is 0 an error is thrown.Flags for RIOT_SaveToFile:0×0001 – keep EXIF
0×0002 – keep IPTC
0×0004 – keep XMP
0×0008 – keep Comments
0×1000 – keep ICC profile0x0800 – save greyscale
0×2000 – save progressive
0×10000 – disable chroma subsamplingAlso you can set a quality flag from 1 to 100Ex: flags=JPEG_SUBSAMPLING_444 | JPEG_PROGRESSIVE | 90
results in a file with no subsampling, progressive with a quality of 90
If you don’t specify quality 75 is used.
You must specify JPEG_PROGRESSIVE if you want progressive.
If you don’t specify JPEG_SUBSAMPLING_444 a default chroma of 4:2:0 is used.

第一个问题与errorText有关。该文档指出,“出现错误时,errorText 会填充错误消息。”这表明您必须传递一个未指定长度的字节数组,该数组将被填充。这太可怕了。

第二个问题是“如果没有标志或 byteSize 为 0,则会引发错误。”

我的猜测是您收到错误,并且它正在尝试将字节复制到 errorText 中。尝试传递一个较大的 byte[] 而不是字符串。

关于c# - 将 C# 位图转换为 Windows dib 句柄以用于 RIOT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11211904/

相关文章:

c# - 奇怪的颜色代码?转换为十六进制?

c# - 从 C# 加载托管资源并将其作为流句柄传递给 native C++ 代码

c++ - 将 void* 转换为 const void**

c++ - 提高图像对比度

c# - 如何使用 P/Invoke 从 64 位 C# 应用程序调用 64 位 C++ DLL?

c# - WPF Combobox Itemssource 是 Visibility Enum

c# - WPF:按下鼠标左键更改边框的背景颜色

c++ - 现代 OpenGL : VBO, GLM 和矩阵堆栈

c# - __declspec(dllexport)::vector <std::string>

c# - 在 WPF 中将窗口置于最前面