这个CGPDFDictionaryGetString如何转换成Monotouch?

时间:2011-09-21 20:19:06

标签: c# pdf xamarin.ios pinvoke cgpdfdictionaryref

我有一张来自GIT上伟大的VFR PDF Viewer的ObjC代码。 它使用CGPDFDictionaryGetString从PDF注释中获取指向字符串的指针。然后它使用一些字节指针转换来获取最终的字符串。 在Monotouch中没有CGPDFDictionary.GetString()但只有.GetName() - 这是唯一返回字符串的方法,所以我认为必须是正确的方法,但它不起作用。 我可以很好地检索数组,字典,浮点数和整数 - 只有字符串似乎不起作用。

请参阅下面的小代码示例。

CGPDFStringRef uriString = NULL;
// This returns TRUE in the ObjC version and uriString is a valid pointer to a string.
if (CGPDFDictionaryGetString(actionDictionary, "URI", &uriString) == true)
{
  // Do some pointer magic - how to do this in MT? Do I have to at all?
  const char *uri = (const char *)CGPDFStringGetBytePtr(uriString);
  // *uri now contains a URL, I can see it in the debugger.
}

我翻译得那样:

string sUri = null;
// This returns FALSE. Hence my sUri is NULL. Seems like GetName() is not the analogy to CGPDFDictionaryGetString.
if(oActionDic.GetName("URI", out sUri))
{
  // I never get here.
}

修改 看一下Mono来源,我可以在Master分支中看到这个: // TODO:GetString - >返回CGPDFString

切换到分支4.2显示它似乎在那里。所以我从那里复制了代码但有两个问题:

  • 我收到有关“unsafe”关键字的错误消息。它告诉我添加“unsafe”命令行选项。那是什么,添加它是个好主意?在哪里?
  • 无论如何它似乎都在运行,但是在获取CGPDFString时应用程序会挂起。

[DllImport(Constants.CoreGraphicsLibrary)]         public extern static IntPtr CGPDFStringGetLength(IntPtr pdfStr);

    [DllImport (Constants.CoreGraphicsLibrary)]
    public extern static IntPtr CGPDFStringGetBytePtr (IntPtr pdfStr);

    public static string PdfStringToString (IntPtr pdfString)
    {
        if (pdfString == IntPtr.Zero)
            return null;

        int n = (int)CGPDFStringGetLength (pdfString);
        unsafe
        {
            return new String ((char *)CGPDFStringGetBytePtr (pdfString), 0, n);
        }
    }

    [DllImport (Constants.CoreGraphicsLibrary)]
    extern static bool CGPDFDictionaryGetString (IntPtr handle, string key, out IntPtr result);

    public static bool GetStringFromPdfDictionary (CGPDFDictionary oPdfDic, string key, out string result)
    {
        if (key == null)
            throw new ArgumentNullException ("key");
        IntPtr res;
        if (CGPDFDictionaryGetString (oPdfDic.Handle, key, out res))
        {
            result = PdfStringToString (res);
            return true;
        }
        result = null;
        return false;
    }

2 个答案:

答案 0 :(得分:1)

如果您在源代码中使用不安全关键字,则需要在构建程序集时启用不安全。在MonoDevelop中,您可以通过以下方式执行此操作:

  • 右键单击项目;
  • 选择选项菜单;
  • 选择常规图标;
  • 点击允许'不安全'代码复选框
  • 点击确定按钮
  • 然后重建。

注意:如果没有此功能,您之前的版本就无法运行。

master monotouch-4.2 之间的源代码在这种情况下应该是相同的。我会检查但是你可能正在查看GIT中的特定修订(在代码更新之前被推送)。我会检查以确定并编辑帖子。

更新:这是指向master的链接(即最新的可用代码),它显示:

public bool GetString (string key, out string result)

可用。但它确实依赖于不安全代码(在PdfStringToString中),如果不允许在复制/粘贴此代码的程序集中使用不安全的代码,则无法编译。

UPDATE2 :返回的值是UTF8编码的,因此从中创建的字符串需要正确解码(另一个System.String构造函数允许这样做)。以上指向master的链接应该已经指向固定版本。

答案 1 :(得分:0)

我不是使用不安全块的忠实粉丝,并设法实现此方法而不使用它。最初我尝试了不安全的样式,但是由于字符串存储在UTF8中,因此需要进行转换。

private bool PDFDictionaryGetString (IntPtr handle, string key, out string result)
{
    IntPtr stringPtr;
    result = null;

    if (CGPDFDictionaryGetString(handle, "URI", out stringPtr)) {

        if (stringPtr == IntPtr.Zero)
                return false;

        // Get length of PDF String
        uint n = (uint) CGPDFStringGetLength (stringPtr);

        // Get the pointer of the string
        var ptr = CGPDFStringGetBytePtr (stringPtr);
        // Get the bytes
        var data = NSData.FromBytes(ptr, n);
        // Convert to UTF8
        var value = NSString.FromData(data, NSStringEncoding.UTF8);

        result = value.ToString();
        return true;
    }
    return false;
} 

有一篇完整的博文here和工作样本,其中包含完整的来源here,其中包含多页滑动导航和可点击链接。