imageinfo icon indicating copy to clipboard operation
imageinfo copied to clipboard

Is it possible that a C# wrapper will be provided in the future?

Open Charltsing opened this issue 1 year ago • 20 comments

Is it possible that a C# wrapper will be provided in the future?

Thank you for your excellent work

Charltsing avatar Jul 14 '24 13:07 Charltsing

Hi @Charltsing , a C# wrapper is possible. You can wrap a dll and then use something like [DllImport("MyLibrary.dll", EntryPoint = "NativeMethod")].

Since this project is a c++ header only library, wrapping dlls need to be done by yourself, I believe this can be done within 10 lines of code.

Or completely rewriting imageinfo using C# would also be a good idea, just like the rust version imageinfo-rs.

: )

xiaozhuai avatar Jul 15 '24 03:07 xiaozhuai

I'm looking forward to an official version

Charltsing avatar Jul 18 '24 23:07 Charltsing

I'm looking forward to an official version

Unfortunately, there is currently no official port for C#. And currently I have no plans to port to C# for the time being. If you are willing to get this done, I would be happy to help. Any question is welcome.

xiaozhuai avatar Jul 25 '24 10:07 xiaozhuai

@Charltsing I'm closing this as complete. Feel free to reopen it if you want to continue discussion.

xiaozhuai avatar Jul 29 '24 11:07 xiaozhuai

我只懂C#,可以编译你的项目,但是生成的却是exe文件。这就麻烦了。 以我的C水平,能编译已经是能力极限。把你这个工程改成符合c#要求的dll,有点费劲。

没找到 extern "C" __declspec(dllexport) 导出函数,是不是得我自己写啊。

————

另外,ImageInfo的输出对C# 也不太友好。 C#获取c++的输出,通常是数值、字节数组、字符串。后两者还需要知道分配的内存大小。 或者直接返回一个定长的结构,以便C#分配内存。

所以,是不是考虑将输出改成C#友好的版本: 输出的结构包括:图像格式枚举,图像宽高数值,以及输出的其它字符串和字符串长度。 或者直接输出定长的结构,字符串改成定长,例如图像格式用8个字符,错误信息64个字符之类的。

如果实在麻烦的话,也许直接只写一个导出函数,能提供图像格式枚举和宽高数值就足够了,不需要字符串输出。因为我没在代码里面发现其它什么有用的图像信息。

这就是为啥我希望等官方出一个C#包装,毕竟需要修改你的源代码才方便包装成C#版本。

Charltsing avatar Jul 29 '24 16:07 Charltsing

没找到 extern "C" __declspec(dllexport) 导出函数,是不是得我自己写啊。

是的

这就是为啥我希望等官方出一个C#包装,毕竟需要修改你的源代码才方便包装成C#版本。

实际上并不需要修改现有的代码,正如我前面说过的,这是一个仅头文件库。但确实需要编写少量的c++代码来集成到c#工程中。晚点我会提供一个简单的C#封装示例。

xiaozhuai avatar Jul 30 '24 03:07 xiaozhuai

@Charltsing 下载下面的zip包,解压后将imageinfo-sharp目录放入imageinfo工程的根目录,然后用Visual Studio打开imageinfo-sharp目录下面的imageinfo-sharp.sln工程文件即可。 注意修改一下Program.cs中的测试文件的路径。

imageinfo-sharp.zip

QQ_1722319137807

xiaozhuai avatar Jul 30 '24 05:07 xiaozhuai

我把imageinfo.hpp放到imageinfo-sharp\imageinfo-native目录下,编译成功。

谢谢您的帮助。

Charltsing avatar Jul 30 '24 07:07 Charltsing

我把imageinfo.hpp放到imageinfo-sharp\imageinfo-native目录下,编译成功。

这一步不是必须的,可以修改一下imageinfo-nativeinclude_directories即包含目录,增加一个../../include即可,注意如果有多个Configuration,则都需要修改。 可能我发你的时候忘了改了,你可以自己改一下。 或者就按照你的做法,复制一下imageinfo.hpp也是可以的。

最后需要注意的是: 格式枚举的值有可能会改变,你需要在C#中小心的处理映射关系,当前导出的是int类型,你可能会需要增加一个enum类型用于表示图片格式。 如果后续你更新了imageinfo.hpp,那么你需要检查一下你的枚举量映射关系是否正确。(因为未来可能会发生改变,此库只保证源码兼容,不保证二进制兼容。)

xiaozhuai avatar Jul 30 '24 07:07 xiaozhuai

@Charltsing 没什么问题的话,我就关闭这个issue了。有问题的话你可以再重新打开。

xiaozhuai avatar Jul 30 '24 08:07 xiaozhuai

@Charltsing 没什么问题的话,我就关闭这个issue了。有问题的话你可以再重新打开。

那个啥,你这个版本不支持中文吗?英文没啥问题了

我测试中文路径和中文文件名都提示: - Error : Unrecognized format

没找到在哪reopen

顺便问一下,字符串能不能以Unicode方式传进native dll,这样就不需要utf8转换了。

Charltsing avatar Jul 30 '24 10:07 Charltsing

那个啥,你这个版本不支持中文吗?

是的,不支持中文,支持中文需要做一些小小的更改。

QQ_1722335624090

找到entrypoint.cpp,修改如下

#define WIN32_LEAN_AND_MEAN

#include "imageinfo.hpp"
#include <iostream>
#include <Windows.h>

std::wstring utf8_to_wstring(const char *str, size_t len) {
    if (len == 0) {
        return std::wstring();
    }

    int size = MultiByteToWideChar(CP_UTF8, 0, str, (int)len, nullptr, 0);
    if (size == 0) {
        return std::wstring();
    }

    std::wstring wstr(size, 0);
    MultiByteToWideChar(CP_UTF8, 0, str, (int)len, &wstr[0], size);
    return wstr;
}

class WFilePathReader {
public:
    explicit WFilePathReader(const std::wstring &path) : file_(path, std::ios::in | std::ios::binary) {
    }

    ~WFilePathReader() {
        if (file_.is_open()) {
            file_.close();
        }
    }

    inline size_t size() {
        if (file_.is_open()) {
            file_.seekg(0, std::ios::end);
            return (size_t)file_.tellg();
        } else {
            return 0;
        }
    }

    inline void read(void *buf, off_t offset, size_t size) {
        file_.seekg(offset, std::ios::beg);
        file_.read((char *)buf, (std::streamsize)size);
    }

private:
    std::ifstream file_;
};

#define IMAGE_INFO_API		extern "C" __declspec(dllexport)

IMAGE_INFO_API imageinfo::ImageInfo *imageinfo_parse_file(const char *path, size_t len) {
    imageinfo::ImageInfo *info = new imageinfo::ImageInfo();
    *info = imageinfo::parse<WFilePathReader>(utf8_to_wstring(path, len));
    return info;
}

IMAGE_INFO_API imageinfo::ImageInfo *imageinfo_parse_memory(const void *data, size_t size) {
    imageinfo::ImageInfo *info = new imageinfo::ImageInfo();
    *info = imageinfo::parse<imageinfo::RawDataReader>(imageinfo::RawData(data, size));
    return info;
}

IMAGE_INFO_API void imageinfo_free(imageinfo::ImageInfo *info) {
    delete info;
}

IMAGE_INFO_API int imageinfo_get_error(const imageinfo::ImageInfo *info) {
    return info->error();
}

IMAGE_INFO_API const char *imageinfo_get_error_message(const imageinfo::ImageInfo *info) {
    return info->error_msg();
}

IMAGE_INFO_API int imageinfo_get_format(const imageinfo::ImageInfo *info) {
    return info->format();
}

IMAGE_INFO_API const char *imageinfo_get_ext(const imageinfo::ImageInfo *info) {
    return info->ext();
}

IMAGE_INFO_API const char *imageinfo_get_full_ext(const imageinfo::ImageInfo *info) {
    return info->full_ext();
}

IMAGE_INFO_API const char *imageinfo_get_mimetype(const imageinfo::ImageInfo *info) {
    return info->mimetype();
}

IMAGE_INFO_API int64_t imageinfo_get_width(const imageinfo::ImageInfo *info) {
    return info->size().width;
}

IMAGE_INFO_API int64_t imageinfo_get_height(const imageinfo::ImageInfo *info) {
    return info->size().height;
}

IMAGE_INFO_API int imageinfo_get_entries_count(const imageinfo::ImageInfo *info) {
    return static_cast<int>(info->entry_sizes().size());
}

IMAGE_INFO_API int64_t imageinfo_get_entry_width(const imageinfo::ImageInfo *info, int index) {
    return info->entry_sizes()[index].width;
}

IMAGE_INFO_API int64_t imageinfo_get_entry_height(const imageinfo::ImageInfo *info, int index) {
    return info->entry_sizes()[index].height;
}

然后找到ImageInfo.cs中的ParseFile修改如下

    public static ImageInfo ParseFile(string path)
    {
        unsafe
        {
            var utf8 = System.Text.Encoding.UTF8.GetBytes(path);
            fixed (byte* p = utf8)
            {
                return new ImageInfo(NativeMethods.parse_file(p, utf8.Length));
            }
        }
    }

xiaozhuai avatar Jul 30 '24 10:07 xiaozhuai

反正你也是把Utf8转成Unicode,不如直接用Unicode

我把代码改成这样了:

entrypoint.cpp IMAGE_INFO_API imageinfo::ImageInfo* imageinfo_parse_file_unicode(const wchar_t* path) { imageinfo::ImageInfo* info = new imageinfo::ImageInfo(); *info = imageinfo::parse<WFilePathReader>(path); return info;

ImageInfo.cs [DllImport(DllPath, EntryPoint = "imageinfo_parse_file_unicode", CharSet = CharSet.Unicode)] public static extern unsafe IntPtr parse_file_unicode(string path);

public static ImageInfo ParseFileUnicode(string path) { return new ImageInfo(NativeMethods.parse_file_unicode(path));
}

Charltsing avatar Jul 30 '24 10:07 Charltsing

不如直接用Unicode

也可以,我对c#不是很熟悉,如果你上面的代码能work的话那就没问题

xiaozhuai avatar Jul 30 '24 11:07 xiaozhuai

我试了一下你的代码没有问题,注意WFilePathReader还是需要的。

xiaozhuai avatar Jul 30 '24 11:07 xiaozhuai

@Charltsing 我提供的C#示例实际上并非最优的实现,例如要考虑到ImageInfo要对序列化/反序列化友好,需要将EntrySizes作为一个List属性,当前是提供了两个get方法。然后就是windows下的宽字符文件路径的支持,这个刚刚已经解决了。可能还会有别的一些问题或需要优化的地方。 如果你愿意维护C#的封装,我会考虑将其合并到此工程作为官方C#支持。因为我本人确实不是很想再多维护C#的部分,主要也不熟。所以如果你愿意之后维护C#部分的话,欢迎提交PR。

xiaozhuai avatar Jul 30 '24 11:07 xiaozhuai

另外作为官方C#支持,至少还需要添加以下内容:

  1. C# tests,参考tests.cpp对所有示例文件进行测试,并确保所有的测试通过。
  2. 添加对应的CI工作流,自动编译和测试C#部分。可以参考现有的 ci.yml

xiaozhuai avatar Jul 30 '24 11:07 xiaozhuai

目前在辽宁联通和移动上github都很麻烦。每次只能几分钟,然后就被断网。 间隔十几分钟或者更长时间才能再上,然后再被断网。

所以我目前不具备维护项目的条件。

不过,我过些日子发一个内存加载native dll的C#版给你,你可以用它修改一下,放到你的存储库里面做官方示例,以后我找起来也方便。

C#版的例子有一个就行,也不需要天天维护。

Charltsing avatar Jul 30 '24 12:07 Charltsing

ImageInfo-sharp包括imageinfo-native,ImageInfo-sharp,imageinfo-demo三个项目

ImageInfo-sharp采用内存加载的方式调用原生dll。使用的MemoryModule来自https://github.com/wwh1004/MemoryModule 这个项目也是国内大神搞的。测试了三年,在上万台电脑跑过,很可靠。

其它具体项目说明看readme.txt

ImageInfo-sharp.zip

使用MemoryModule的目的是避免多出两个原生dll文件。可以单文件部署或者调用。

如果你觉得可用的话,以你的名义放在存储库里面吧。方便我以后升级查找。因为entrypoint.cpp还需要你来维护。

Charltsing avatar Aug 05 '24 15:08 Charltsing

@Charltsing 感谢贡献。 我暂时会将此issue置顶,以便有需要的人方便获取。

xiaozhuai avatar Aug 06 '24 03:08 xiaozhuai

暂时没有C#的官方移植计划,将关闭此issue。 但此issue将继续保持置顶。

xiaozhuai avatar Nov 27 '24 09:11 xiaozhuai