Is it possible that a C# wrapper will be provided in the future?
Is it possible that a C# wrapper will be provided in the future?
Thank you for your excellent work
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.
: )
I'm looking forward to an official version
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.
@Charltsing I'm closing this as complete. Feel free to reopen it if you want to continue discussion.
我只懂C#,可以编译你的项目,但是生成的却是exe文件。这就麻烦了。 以我的C水平,能编译已经是能力极限。把你这个工程改成符合c#要求的dll,有点费劲。
没找到 extern "C" __declspec(dllexport) 导出函数,是不是得我自己写啊。
————
另外,ImageInfo的输出对C# 也不太友好。 C#获取c++的输出,通常是数值、字节数组、字符串。后两者还需要知道分配的内存大小。 或者直接返回一个定长的结构,以便C#分配内存。
所以,是不是考虑将输出改成C#友好的版本: 输出的结构包括:图像格式枚举,图像宽高数值,以及输出的其它字符串和字符串长度。 或者直接输出定长的结构,字符串改成定长,例如图像格式用8个字符,错误信息64个字符之类的。
如果实在麻烦的话,也许直接只写一个导出函数,能提供图像格式枚举和宽高数值就足够了,不需要字符串输出。因为我没在代码里面发现其它什么有用的图像信息。
这就是为啥我希望等官方出一个C#包装,毕竟需要修改你的源代码才方便包装成C#版本。
没找到 extern "C" __declspec(dllexport) 导出函数,是不是得我自己写啊。
是的
这就是为啥我希望等官方出一个C#包装,毕竟需要修改你的源代码才方便包装成C#版本。
实际上并不需要修改现有的代码,正如我前面说过的,这是一个仅头文件库。但确实需要编写少量的c++代码来集成到c#工程中。晚点我会提供一个简单的C#封装示例。
@Charltsing
下载下面的zip包,解压后将imageinfo-sharp目录放入imageinfo工程的根目录,然后用Visual Studio打开imageinfo-sharp目录下面的imageinfo-sharp.sln工程文件即可。
注意修改一下Program.cs中的测试文件的路径。
我把imageinfo.hpp放到imageinfo-sharp\imageinfo-native目录下,编译成功。
谢谢您的帮助。
我把imageinfo.hpp放到imageinfo-sharp\imageinfo-native目录下,编译成功。
这一步不是必须的,可以修改一下imageinfo-native的include_directories即包含目录,增加一个../../include即可,注意如果有多个Configuration,则都需要修改。
可能我发你的时候忘了改了,你可以自己改一下。
或者就按照你的做法,复制一下imageinfo.hpp也是可以的。
最后需要注意的是:
格式枚举的值有可能会改变,你需要在C#中小心的处理映射关系,当前导出的是int类型,你可能会需要增加一个enum类型用于表示图片格式。
如果后续你更新了imageinfo.hpp,那么你需要检查一下你的枚举量映射关系是否正确。(因为未来可能会发生改变,此库只保证源码兼容,不保证二进制兼容。)
@Charltsing 没什么问题的话,我就关闭这个issue了。有问题的话你可以再重新打开。
@Charltsing 没什么问题的话,我就关闭这个issue了。有问题的话你可以再重新打开。
那个啥,你这个版本不支持中文吗?英文没啥问题了
我测试中文路径和中文文件名都提示: - Error : Unrecognized format
没找到在哪reopen
顺便问一下,字符串能不能以Unicode方式传进native dll,这样就不需要utf8转换了。
那个啥,你这个版本不支持中文吗?
是的,不支持中文,支持中文需要做一些小小的更改。
找到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));
}
}
}
åæ£ä½ ä¹æ¯æ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));
}
不如直接用Unicode
也可以,我对c#不是很熟悉,如果你上面的代码能work的话那就没问题
我试了一下你的代码没有问题,注意WFilePathReader还是需要的。
@Charltsing 我提供的C#示例实际上并非最优的实现,例如要考虑到ImageInfo要对序列化/反序列化友好,需要将EntrySizes作为一个List属性,当前是提供了两个get方法。然后就是windows下的宽字符文件路径的支持,这个刚刚已经解决了。可能还会有别的一些问题或需要优化的地方。
如果你愿意维护C#的封装,我会考虑将其合并到此工程作为官方C#支持。因为我本人确实不是很想再多维护C#的部分,主要也不熟。所以如果你愿意之后维护C#部分的话,欢迎提交PR。
另外作为官方C#支持,至少还需要添加以下内容:
- C# tests,参考
tests.cpp对所有示例文件进行测试,并确保所有的测试通过。 - 添加对应的CI工作流,自动编译和测试C#部分。可以参考现有的 ci.yml
目前在辽宁联通和移动上github都很麻烦。每次只能几分钟,然后就被断网。 间隔十几分钟或者更长时间才能再上,然后再被断网。
所以我目前不具备维护项目的条件。
不过,我过些日子发一个内存加载native dll的C#版给你,你可以用它修改一下,放到你的存储库里面做官方示例,以后我找起来也方便。
C#版的例子有一个就行,也不需要天天维护。
ImageInfo-sharp包括imageinfo-native,ImageInfo-sharp,imageinfo-demo三个项目
ImageInfo-sharp采用内存加载的方式调用原生dll。使用的MemoryModule来自https://github.com/wwh1004/MemoryModule 这个项目也是国内大神搞的。测试了三年,在上万台电脑跑过,很可靠。
其它具体项目说明看readme.txt
使用MemoryModule的目的是避免多出两个原生dll文件。可以单文件部署或者调用。
如果你觉得可用的话,以你的名义放在存储库里面吧。方便我以后升级查找。因为entrypoint.cpp还需要你来维护。
@Charltsing 感谢贡献。 我暂时会将此issue置顶,以便有需要的人方便获取。
暂时没有C#的官方移植计划,将关闭此issue。 但此issue将继续保持置顶。