我正在使用该函数在pdf文件中查找文本并将该文本替换为另一个文本 . 问题是当我进行膨胀然后更改文本和放气时,在最终的pdf中,有时会丢失一些文本或图形 . 这是我的代码中的错误或zlib库不支持此压缩或什么?
// Open the PDF source file:
FILE *pdfFile = fopen([sourceFile cStringUsingEncoding:NSUTF8StringEncoding], "rb");
if (pdfFile) {
// Get the file length:
int fseekres = fseek(pdfFile, 0, SEEK_END);
if (fseekres != 0) {
fclose(pdfFile);
return nil;
}
long filelen = ftell(pdfFile);
fseekres = fseek(pdfFile, 0, SEEK_SET);
if (fseekres != 0) {
fclose(pdfFile);
return nil;
}
char *buffer = new char[filelen];
size_t actualread = fread(buffer, filelen, 1, pdfFile);
if (actualread != 1) {
fclose(pdfFile);
return nil;
}
bool morestreams = true;
while (morestreams) {
size_t streamstart = [self findStringInBuffer:buffer search:(char *)"stream" buffersize:filelen];
size_t streamend = [self findStringInBuffer:buffer search:(char *)"endstream" buffersize:filelen];
[self saveFile:buffer len:streamstart + 7 fileName:[destFile cStringUsingEncoding:NSUTF8StringEncoding]];
if (streamstart > 0 && streamend > streamstart) {
streamstart += 6;
if (buffer[streamstart] == 0x0d && buffer[streamstart + 1] == 0x0a) {
streamstart += 2;
} else if (buffer[streamstart] == 0x0a) {
streamstart++;
}
if (buffer[streamend - 2] == 0x0d && buffer[streamend - 1] == 0x0a) {
streamend -= 2;
} else if (buffer[streamend - 1] == 0x0a) {
streamend--;
}
size_t outsize = (streamend - streamstart) * 10;
char *output = new char[outsize];
z_stream zstrm;
zstrm.zalloc = Z_NULL;
zstrm.zfree = Z_NULL;
zstrm.opaque = Z_NULL;
zstrm.avail_in = (uint)(streamend - streamstart + 1);
zstrm.avail_out = (uint)outsize;
zstrm.next_in = (Bytef *)(buffer + streamstart);
zstrm.next_out = (Bytef *)output;
int rsti = inflateInit(&zstrm);
if (rsti == Z_OK) {
int rst2 = inflate(&zstrm, Z_FINISH);
inflateEnd(&zstrm);
if (rst2 >= 0) {
size_t totout = zstrm.total_out;
//search and replace text code here
size_t coutsize = (streamend - streamstart + 1) * 10;
char *coutput = new char[coutsize];
z_stream c_stream;
c_stream.zalloc = Z_NULL;
c_stream.zfree = Z_NULL;
c_stream.opaque = Z_NULL;
c_stream.total_out = 0;
c_stream.avail_in = (uint)totout;
c_stream.avail_out = (uint)coutsize;
c_stream.next_in = (Bytef *)output;
c_stream.next_out = (Bytef *)coutput;
rsti = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
if (rsti == Z_OK) {
rsti = deflate(&c_stream, Z_FINISH);
deflateEnd(&c_stream);
if (rsti >= 0) {
[self saveFile:coutput len:c_stream.total_out fileName:[destFile cStringUsingEncoding:NSUTF8StringEncoding]];
}
}
delete [] coutput; coutput = 0;
[self saveFile:(char *)"\nendstr" len:7 fileName:[destFile cStringUsingEncoding:NSUTF8StringEncoding]];
}
}
delete[] output; output = 0;
buffer += streamend + 7;
filelen = filelen - (streamend + 7);
} else {
morestreams = false;
}
}
[self saveFile:buffer len:filelen fileName:[destFile cStringUsingEncoding:NSUTF8StringEncoding]];
}
fclose(pdfFile);
3 回答
您的代码中存在多个问题,其效果在您对Bruno答案的评论中提供的示例_1664934中可见:
添加该字符串的问题在于您假设输入缓冲区中的“endstream”前面只有一个NEWLINE(0x0A)字节 . 这个假设是错误的,因为
一个 . 在PDF中有三种类型的有效行尾标记,一个LINE FEED(0x0A),一个CARRIAGE RETURN(0x0D),或CARRIAGE RETURN和LINE FEED对(0x0D 0x0A),以及这些中的任何一个结束行标记可以在输入缓冲区中的“endstream”之前;在您计算压缩流结束的上面的代码中,您忽略了单个CARRIAGE RETURN变量,在这里忽略2字节变量;而且:
湾PDF specification甚至不需要,只是建议在流的末尾和"endstream"关键字之间添加行尾,参见 . 第7.3.8.1节:
这已经破坏了示例文件中的第一个流,在该流文件中源文件没有行尾标记,因此,您的结果将原始“endstream”替换为“\ nendstram” . 这实际上经常在您的样本中发生 .
即使您只进行解压缩和重新压缩,您的操作也可能会改变压缩流的长度 . 因此,您必须更新 Length 条目 . 这无疑使得你的任务有点困难,因为那个字典在流之前 . 此外,在类似源文件的情况下,该条目甚至可能不直接包含该值,而是在文件中的其他位置引用间接对象 .
这会破坏文件中的第二个流,声称它的长度为8150字节,但相差大约200个字节 . 任何PDF查看器都可以假设文件中该流的内容只有8150字节长,因此忽略那些尾随200字节的内容 . 这很可能是你观察到这一点的原因
即使您只进行解压缩和重新压缩,您的操作也可能会改变压缩流的长度 . 因此,您必须更新交叉引用表中所有后续对象的偏移量 .
由于结果文件中第二个流的大小已经不同,因此该文件中只有极少数交叉引用条目是正确的 .
您的代码基本上会丢弃它无法膨胀的所有流 . 这也可能是您观察到这一点的原因
您假设PDF中的序列“stream”明确指示流的开始 . 这是错误的,该序列也可以在其他环境中轻松使用 .
你假设流开始后PDF中的第一个序列"endstream"明确指示该流的结束 . 这是错误的,该序列也可能是流内容的一部分 . 您必须使用流字典中 Length 条目的值 .
此外,您似乎假设您出现的每个流仍然在生成的PDF中使用 . 这不一定是这种情况 . 特别是在增量更新的情况下(参见PDF specification中的第7.5.6节),文件中可能有许多对象不再使用 . 虽然这不一定会破坏结果文件的语法,但是您的更改(如果它们相互依赖)在语义上是不正确的 .
您可以在内容流中找到文本的假设是错误的 .
假设您有一个包含内容Hello World的PDF . 然后你可以有一个看起来像这样的流:
但它也可以是这样的:
您的代码将在前一个流中检测到“Hello”一词,但在后一个流程中会丢失它 .
PDF查看器将以完全相同的方式呈现两个流:您将在完全相同的位置看到“Hello World” .
有时字符串被分成更小的部分,你经常会找到文本数组来引入字距调整等...这是PDF中的所有标准做法 .
PDF不是适合编辑的格式 . 我不是说这是不可能的,但如果你想满足你的要求,能够在PDF流中替换另一个字符串,你就会看到几周的额外编程 .
我想你必须阅读文本如何存储在PDF文件中,
这是指向http://www.adobe.com/devnet/pdf/pdf_reference.html的链接
第9节文本是理解的关键 .