【问题标题】:python 3 fdfgen unicode TypeErrorpython 3 fdfgen unicode TypeError
【发布时间】:2013-05-24 17:53:23
【问题描述】:

我正在使用 Python 3.3,并且正在尝试使用出色的 fgfgen / forge_fdf 脚本(谢谢大家,顺便说一句)。

当我尝试运行 fdfgen 的示例测试时,我返回以下错误。

        safe = utf16.replace('\x00)', '\x00\\)').replace('\x00(', '\x00\\(')
TypeError: expected bytes, bytearray or buffer compatible object

环顾四周,这似乎是 python 3 处理 unicode 编码的结果?但我不确定。这是执行的 fdfgen 代码的示例,然后是很好地提供的 fdfgen 代码。提前致谢:

>>> from fdfgen import forge_fdf
>>> fields = [('last_name', u'Spencer')]
>>> fdf = forge_fdf('SMBRPython.pdf', fields, [], [], [])

    # -*- coding: utf-8 -*-
"""
Port of the PHP forge_fdf library by Sid Steward
(http://www.pdfhacks.com/forge_fdf/)

Anders Pearson <anders@columbia.edu> at Columbia Center For New Media Teaching
and Learning <http://ccnmtl.columbia.edu/>
"""

__author__ = "Anders Pearson <anders@columbia.edu>"
__credits__ = ("Sébastien Fievet <zyegfryed@gmail.com>,"
               "Brandon Rhodes <brandon@rhodesmill.org>")

import codecs

def smart_encode_str(s):
    """Create a UTF-16 encoded PDF string literal for `s`."""
    utf16 = s.encode('utf_16_be')
    safe = utf16.replace('\x00)', '\x00\\)').replace('\x00(', '\x00\\(')
    return ('%s%s' % (codecs.BOM_UTF16_BE, safe))


def handle_hidden(key, fields_hidden):
    if key in fields_hidden:
        return "/SetF 2"
    else:
        return "/ClrF 2"


def handle_readonly(key, fields_readonly):
    if key in fields_readonly:
        return "/SetFf 1"
    else:
        return "/ClrFf 1"


def handle_data_strings(fdf_data_strings, fields_hidden, fields_readonly):
    for (key, value) in fdf_data_strings:
        if type(value) is bool:
            if value:
                yield "<<\n/V/Yes\n/T (%s)\n%s\n%s\n>>\n" % (
                    smart_encode_str(key),
                    handle_hidden(key, fields_hidden),
                    handle_readonly(key, fields_readonly),
                )
            else:
                yield "<<\n/V/Off\n/T (%s)\n%s\n%s\n>>\n" % (
                    smart_encode_str(key),
                    handle_hidden(key, fields_hidden),
                    handle_readonly(key, fields_readonly),
                )
        else:
            yield "<<\n/V (%s)\n/T (%s)\n%s\n%s\n>>\n" % (
                smart_encode_str(value),
                smart_encode_str(key),
                handle_hidden(key, fields_hidden),
                handle_readonly(key, fields_readonly),
            )


def handle_data_names(fdf_data_names, fields_hidden, fields_readonly):
    for (key, value) in fdf_data_names:
        yield "<<\n/V /%s\n/T (%s)\n%s\n%s\n>>\n" % (
            smart_encode_str(value),
            smart_encode_str(key),
            handle_hidden(key, fields_hidden),
            handle_readonly(key, fields_readonly),
        )


def forge_fdf(pdf_form_url="", fdf_data_strings=[], fdf_data_names=[], fields_hidden=[], fields_readonly=[]):

    """Generates fdf string from fields specified

    pdf_form_url is just the url for the form fdf_data_strings and
    fdf_data_names are arrays of (key,value) tuples for the form fields. FDF
    just requires that string type fields be treated seperately from boolean
    checkboxes, radio buttons etc. so strings go into fdf_data_strings, and
    all the other fields go in fdf_data_names. fields_hidden is a list of
    field names that should be hidden fields_readonly is a list of field names
    that should be readonly

    The result is a string suitable for writing to a .fdf file.

    """
    fdf = ['%FDF-1.2\n%\xe2\xe3\xcf\xd3\r\n']
    fdf.append("1 0 obj\n<<\n/FDF\n")

    fdf.append("<<\n/Fields [\n")
    fdf.append(''.join(handle_data_strings(fdf_data_strings, fields_hidden, fields_readonly)))
    fdf.append(''.join(handle_data_names(fdf_data_names, fields_hidden, fields_readonly)))
    fdf.append("]\n")

    if pdf_form_url:
        fdf.append("/F (" + smart_encode_str(pdf_form_url) + ")\n")

    fdf.append(">>\n")
    fdf.append(">>\nendobj\n")
    fdf.append("trailer\n\n<<\n/Root 1 0 R\n>>\n")
    fdf.append('%%EOF\n\x0a')

    return ''.join(fdf)

【问题讨论】:

  • 能否包含完整的堆栈跟踪信息?

标签: python pdf fdf


【解决方案1】:

编码产生字节值,但您正在使用字符串值来尝试替换事物。改用字节文字:

safe = utf16.replace(b'\x00)', b'\x00\\)').replace(b'\x00(', b'\x00\\(')
return (b'%s%s' % (codecs.BOM_UTF16_BE, safe))

【讨论】:

  • 马丁-谢谢!这似乎已经杀死了类型错误。谢谢!
  • @SpencerBates:我没有查看其余代码;我怀疑会有更多这样的陷阱,其中假定 Python 2 字符串而不是 Python 3 字节字符串。如果您需要有关在这种情况下如何移植的完整详细信息,请参阅docs.python.org/3/howto/pyporting.html
  • 哦,非常感谢!是的,我需要跑过去检查一下。当代码运行时,它不会产生结果。感谢您的指导。
【解决方案2】:

Fdfgen 现在已被移植到 Python 3,主要是通过将所有字符串显式转换为字节文字,正如 Martjin Pieters 所述。

【讨论】:

    【解决方案3】:

    在 Vista 上的 fdfgen 0.11.0 和 python 3.4.2 上,将 fdf 数据写入文件时,我最初收到此错误:

        fdf_file.write(fdf)
    TypeError: must be str, not bytes
    

    我最初也得到了这个,但现在无法重现:

    can't convert 'bytes' object to str implicitly
    

    原来我唯一需要做的改变就是将“二进制”模式添加到文件打开命令中。而不是:

    fdf_file=open("testForm.fdf","w")
    

    使用这个:

    fdf_file=open("testForm.fdf","wb")
    

    所有其他行都与他在 fdfgen 网站上的示例相同。希望这可以帮助某人。

    【讨论】:

      猜你喜欢
      • 2019-02-15
      • 2013-07-16
      • 1970-01-01
      • 2016-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-19
      • 1970-01-01
      相关资源
      最近更新 更多