-1

更新 3-4-15:11IS 正如 David 所建议的修改 PInvoke 如下,这次我收到不同的错误“未处理的类型 System.ExecutionEngineException 的异常发生在 mscorlib.dll 中”

    [DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, ref ddjvu_rect_t pagerect,
              ref ddjvu_rect_t renderrect,
              IntPtr pixelformat,
              uint rowsize,
              [Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);

感谢大卫宝贵的时间,我认为已经接近修复。

历史

我知道这个主题有很多问题,但没有一个有助于解决我目前面临的问题。

下面是C语言的API函数

DDJVUAPI int
ddjvu_page_render(ddjvu_page_t *page,
                  const ddjvu_render_mode_t mode,
                  const ddjvu_rect_t *pagerect,
                  const ddjvu_rect_t *renderrect,
                  const ddjvu_format_t *pixelformat,
                  unsigned long rowsize,
                  char *imagebuffer );

下面是在 .NET 代码中添加的 C 函数的 PInvoke 签名

[DllImport("C:\\Program Files\\DJVULIBRE\\LIBDJVULIBRE.dll", CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int ddjvu_page_render(IntPtr page, ddjvu_render_mode_t mode, IntPtr pagerect,
          IntPtr renderrect,
          IntPtr pixelformat,
          ulong rowsize,
          [Out][MarshalAs(UnmanagedType.LPArray)]byte[] imagebuffer);

下面是我如何在 c# 代码中调用此函数

            byte* buffer = (byte *)Memory.Alloc(nSize);
            try
            {
                IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
                Marshal.StructureToPtr(prect, ptr1, false);

                IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
                Marshal.StructureToPtr(rrect, ptr2, false);

                byte[] array = new byte[nSize];
                fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
                ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
            }
            finally
            {
                Memory.Free(buffer);
            }

在上面的代码中调用 ddjvu_page_render 会抛出“试图读取或写入受保护的内存。这通常表明其他内存已损坏。” 在这篇文章之前,我一定已经尝试过所有可以在各种博客中找到的选项。感谢任何帮助,几乎是我一无所知的一天,您的及时帮助可以挽救我的工作

更新 3-4-15:7:44IS 此代码使用DJVULibre

更新 3-4-15:8:35IS

这是我在表单加载中的代码

    ctx = ddjvu_context_create(System.AppDomain.CurrentDomain.FriendlyName);
    if (ctx != null)
    {
        string djFile = "C:\\Users\\rammohan.chavakula\\Documents\\eiasample.djvu";
        doc = ddjvu_document_create_by_filename(ctx, djFile, 100);
        if (doc != null)
        {
            while (ddjvu_job_status(ddjvu_document_job(doc)) >= ddjvu_status_t.DDJVU_JOB_OK)
                SpinDdjvuMessageLoop(ctx, true);

            int pageCount = ddjvu_document_get_pagenum(doc);
            mediaboxes =  new Rectangle[pageCount];
            for (int i = 0; i < pageCount; i++)
            {
                ddjvu_status_t status;
                ddjvu_pageinfo_t info = new ddjvu_pageinfo_t();

                while ((status = ddjvu_document_get_pageinfo_imp(doc, i, ref info, (uint)System.Runtime.InteropServices.Marshal.SizeOf(info))) < ddjvu_status_t.DDJVU_JOB_OK)
                    SpinDdjvuMessageLoop(ctx, true);
                if (status != ddjvu_status_t.DDJVU_JOB_OK)
                    continue;

                mediaboxes[i] = new Rectangle(0, 0, info.width / info.dpi,
                            info.height / info.dpi);

            }

        }
        ddjvu_context_release(ctx);
    }

在 OnPaint 函数中,我有以下代码

        if (doc == null)
        {
            base.OnPaint(e);
            return;
        }
        Rectangle pageRc = PageMediabox(1);
        Rectangle screen = Transform(pageRc, 1, zoom, rotation, false);
        Rectangle full = Transform(PageMediabox(1), 1, zoom, rotation, false);
        full.Intersect(screen);

        IntPtr page = ddjvu_page_create_by_pageno(doc, 1);
        if (page == null )
        {
            base.OnPaint(e);
            return;
        }
        int rotation4 = (((-rotation / 90) % 4) + 4) % 4;
        ddjvu_page_set_rotation(page, (ddjvu_page_rotation_t)rotation4);

        while (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_OK)
            SpinDdjvuMessageLoop(ctx, true);
        if (ddjvu_job_status(ddjvu_page_job(page)) >= ddjvu_status_t.DDJVU_JOB_FAILED)
        {
            base.OnPaint(e);
            return;
        }
        IntPtr fmt = ddjvu_format_create(ddjvu_format_style_t.DDJVU_FORMAT_BGR24, 0, (UIntPtr)null);
        ddjvu_format_set_row_order(fmt, /* top_to_bottom */1);
        ddjvu_rect_t prect = new ddjvu_rect_t(full.X, full.Y, (uint)full.Width, (uint)full.Height);
        ddjvu_rect_t rrect = new ddjvu_rect_t(screen.X, 2 * full.Y + screen.Y + full.Height - screen.Height, (uint)screen.Width, (uint)screen.Height);


        int stride = ((screen.Width * 3 + 3) / 4) * 4;
        //byte tmp;
        ////ScopedMem<char> bmpData(SAZA(char, stride * (screen.dy + 5)));
        //for (int y = 0; y < rrect.h; y++) {
        //    int step_y = y * SCREEN_WIDTH;
        //    for (int x=0; x < rrect.w; x++) {
        //        tmp = (byte)((imagebuf[x + step_y] >> 5) << 5);
        //    }
        //}
        int rowsize = mediaboxes[0].Width * 3;
        int nSize = rowsize * (mediaboxes[0].Height) * 10;

        unsafe
        {
            byte* buffer = (byte *)Memory.Alloc(nSize);
            try
            {
                IntPtr ptr1 = (IntPtr)Memory.Alloc(Marshal.SizeOf(prect));
                Marshal.StructureToPtr(prect, ptr1, false);

                IntPtr ptr2 = (IntPtr)Memory.Alloc(Marshal.SizeOf(rrect));
                Marshal.StructureToPtr(rrect, ptr2, false);

                byte[] array = new byte[nSize];
                fixed (byte* p = array) Memory.Copy(buffer, p, nSize);
                ddjvu_page_render(page, ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, ptr1, ptr2, fmt, (ulong)stride, array);
            }
            finally
            {
                Memory.Free(buffer);
            }

ddjvu_page_render 应该返回要在给定矩形区域中呈现的页面的任意数据。之后,我应该能够从任意数据创建图像并在屏幕上显示

4

1 回答 1

0

这是我编写 p/invoke 的方式:

[DllImport(dllname, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
private static extern int ddjvu_page_render(
    [In] IntPtr page, 
    [In] ddjvu_render_mode_t mode, 
    [In] ref ddjvu_rect_t pagerect,
    [In] ref ddjvu_rect_t renderrect,
    [In] ref ddjvu_format_t pixelformat,
    [In] uint rowsize,
    [Out] byte[] imagebuffer
);

请注意,我已经停止使用unsafe,并让编组器自动处理结构。

这里有很多假设我无法验证:

  • 调用约定。它可能不是 cdecl。C++ 标头将有明确的答案。
  • 我想第一个参数是void*句柄类型。
  • ddjvu_render_mode_t是您已正确翻译的枚举。
  • 这三个ref参数是结构体,通过引用传递。我无法检查您是否正确翻译了它们。

调用此函数将是这样的:

byte[] imagebuffer = new byte[nSize];
int retval = ddjvu_page_render(
    page, 
    ddjvu_render_mode_t.DDJVU_RENDER_MASKONLY, 
    ref prect, 
    ref rrect, 
    ref fmt, 
    (uint)stride, 
    imagebuffer
);
if (retval != ??) 
    // handle error

这是一个相当广泛的刷题答案。我希望它为您指明正确的方向。我不认为你所有的问题都会因此得到解决。

于 2015-03-04T18:24:03.060 回答