无法加载 JPG 图像 Pdfium

问题描述 投票:0回答:2

我尝试用 PDF 为项目做一些事情。我正在尝试与 Pdfium 进行一些互操作:https://pdfium.googlesource.com/pdfium/.

我想将 JPG 图像转换为 PDF(仅作为开始)。所以我在网上找到了一些资源,然后我找到了这个:

///// My main file
// Create the stream
using FileStream image = new FileStream(@"test.jpg", FileMode.Open, FileAccess.Read);
using FileStream pdf = new FileStream(@"test.pdf", FileMode.OpenOrCreate, FileAccess.Write);

// Init the library to use it
FPDF.InitLibrary();

// Create the PDF
IntPtr document = FPDF.CreateNewDocument();
IntPtr page = FPDFPage.New(document, 0, 3000, 4000);
IntPtr pageObject = FPDFPageObj.NewImageObj(document);


// Create a copy of the delegate
FPDF.m_GetBlockDelegate del = Delegates.m_GetBlockDelegate;
FPDF.FILEACCESS fileAccess = new FPDF.FILEACCESS
{
    m_FileLen = (ulong)image.Length,
    m_Param = image.SafeFileHandle.DangerousGetHandle(),
    m_GetBlock = del,
};

// Create the FILEWRITE struct
byte[] buffer = null;
FPDF.FILEWRITE fileWrite = new FPDF.FILEWRITE
{
    WriteBlock = delegate (ref FPDF.FILEWRITE pThis, byte[] pData, ulong size)
    {
        if (buffer == null || (ulong)buffer.Length < size)
            buffer = new byte[size];

        pData.CopyTo(buffer, 0);
        pdf.Write(buffer, 0, (int)size);

        return true;
    }
};

// Load the image
FPDPImageObj.LoadJpegFile(IntPtr.Zero, 0, pageObject, ref fileAccess);
FPDFPage.InsertObject(page, pageObject);

// Save the PDF
FPDF.SaveAsCopy(document, ref fileWrite, 0);

// Destroy the library
FPDF.DestroyLibrary();

问题出在这个方法上:

FPDPImageObj.LoadJpegFile(IntPtr.Zero, 0, pageObject, ref fileAccess);
。 该结构有一个委托作为回调函数来执行一些操作(它在 C 中执行某种流实现)。

这是我的委托、结构体和委托的实现的代码:

public struct FILEACCESS
{
    public ulong m_FileLen { get; set; }
    public m_GetBlockDelegate m_GetBlock { get; set; }
    public IntPtr m_Param { get; set; }
}
public struct FILEWRITE
{
    // Must be 1
    public int version = 1;
    public WriteBlockDelegate WriteBlock { get; set; }
}

public delegate int m_GetBlockDelegate(IntPtr param, ulong position, [In] byte[] pBuf, ulong size);
public delegate bool WriteBlockDelegate(ref FILEWRITE pThis, [In] byte[] pData, ulong size);

// The implementation of my delegate in another class
public static int m_GetBlockDelegate(IntPtr param, ulong position, [In] byte[] pBuf, ulong size)
{
    // Original source code for the delegate
    //FILE* fileHandle = (FILE*)param;
    //fseek(imageFile, position, SEEK_SET);
    //fread(pBuf, size, 1, fileHandle);

    using FileStream fs = new FileStream(new SafeFileHandle(param, false), FileAccess.Read);
    fs.Seek((long)position, SeekOrigin.Begin);
    fs.Read(pBuf, 0, (int)size);

    return (int)size;
}

当前的问题是pBuf应该是一个缓冲区来保存所有要读取的数据。所以它的大小必须与

size
相同。在我的例子中,pBuf 的大小为 1。我已经测试了我的代码的 C 变体,它运行良好(它读取所有数据)。这是代码:

#include <stdio.h>
#include <fpdfview.h>
#include <fpdf_edit.h>
#include <fpdf_save.h>

FILE* pdfFile = nullptr;

int m_GetBlockImpl(void* param, unsigned long position, unsigned char* pBuf, unsigned long size)
{
    FILE* fileHandle = (FILE*)param;
    fseek(fileHandle, position, SEEK_SET);
    fread(pBuf, size, 1, fileHandle);

    return size;
}

int WriteBlockImpl(FPDF_FILEWRITE* pThis, const void* pData, unsigned long size)
{
    fwrite(pData, size, 1, pdfFile);

    return TRUE;
}

int main()
{
    FILE* jpgFile = fopen("C:\\Users\\tcroi\\Desktop\\test.jpg", "rb");
    pdfFile = fopen("C:\\Users\\tcroi\\Desktop\\test.pdf", "wb");

    if (jpgFile == nullptr || pdfFile == nullptr)
        return 1;


    FPDF_InitLibrary();


    // Create the PDF
    FPDF_DOCUMENT pdf_doc = FPDF_CreateNewDocument();
    FPDF_PAGE pdf_page = FPDFPage_New(pdf_doc, 0, 3000, 4000);


    // Seek the stream and get the size
    fseek(jpgFile, 0, SEEK_END);
    long fileSize = ftell(jpgFile);
    fseek(jpgFile, 0, SEEK_SET);

    // Create the FILEACCESS
    FPDF_FILEACCESS fileReadObj;
    fileReadObj.m_FileLen = fileSize;
    fileReadObj.m_Param = jpgFile;
    fileReadObj.m_GetBlock = m_GetBlockImpl;


    // Load the image to the PDF
    FPDF_PAGEOBJECT page_obj_image = FPDFPageObj_NewImageObj(pdf_doc);
    FPDFImageObj_LoadJpegFile(nullptr, 0, page_obj_image, &fileReadObj);
    FPDFPage_InsertObject(pdf_page, page_obj_image);


    // Create the FILEWRITE
    FPDF_FILEWRITE fileWriteObj;
    fileWriteObj.version = 1;
    fileWriteObj.WriteBlock = WriteBlockImpl;

    FPDF_SaveAsCopy(pdf_doc, &fileWriteObj, 0);

    FPDF_DestroyLibrary();

    fclose(jpgFile);
    fclose(pdfFile);

    return 0;
}

这段代码运行良好,直到我想保存PDF,我只得到一个空白页,也许我错过了一些东西,但根据示例没有。这是示例:https://groups.google.com/g/pdfium/c/P73DgvJtgTs

c# c++ pdf interop pdfium
2个回答
1
投票

插入对象后,您可能必须

FPDFPage_GenerateContent
页面,也许还必须
FPDF_ClosePage
页面。


1
投票

插入图像时,初始大小将是 1x1 PDF 画布单位的小矩形,因为对象矩阵默认为

(1 0 0 1 0 0)
。您需要在页面对象上使用
FPDFPageObj_SetMatrix()
来调用
FS_MATRIX(width, 0, 0, height, pos_x, pos_y)

@jerbob92 是对的,

FPDFPage_GenerateContent()
也应该被调用。

pdfium 文档对此肯定会更加明显。 我也花了一段时间才弄清楚这一点;)

© www.soinside.com 2019 - 2024. All rights reserved.