wxleasyland@sina.com
2020.5
一、pdf文件权限的简单原理
PDF的Owner密码=权限口令 , User密码=打开口令
对pdf文件设置权限,原理是采用权限口令(owner)对文件进行加密!并不是简单地在文件中设置一个权限标志!
所以去除权限,必须要经过解密这个过程。
权限口令 会加密成条目O,放在PDF文件中。
权限状态(可否打印,可否复制等) 就是条目P,放在PDF文件中。
打开口令 会加密成条目U,放在PDF文件中。
条目O+条目P+打开口令 → 可生成全局密钥,采用全局密钥对文件内容进行加密。
加密必须要设置权限口令,不一定要设置打开口令。
如果没有设置打开口令,则打开口令采用默认值,通过口令默认值、条目O和条目P,可以得到全局密钥。这样文件内容可以解密!查看器需要进行权限限制。
如果有设置打开口令,则需要打开口令才能解密,即需要输入打开密码才能打开PDF文件。
如果打开口令=权限口令(可通过重新计算条目O和条目U来判断),则查看器放开所有权限。
如果打开口令≠权限口令(可通过重新计算条目O和条目U来判断),则查看器进行权限限制。
二、podofo初步使用
podofo是PDF的开发库。可以在VS下编库使用。初步摸索了一下。
helloworld是用PdfStreamedDocument生成文件,再PdfPainter。
podofomerge是用PdfMemDocument读入或生成文件,InsertPages或Append方法。
podofoencrypt是用PdfVecObjects和PdfParser读入一个文件, 再PdfWriter 和 PdfEncrypt。
podofopdfinfo是它自己重写了PdfInfo类,不是采用标准的PdfInfo类。 实际是采用PdfMemDocument。
如果参考podofomerge,建一个空文件,再把旧文件(有owner密码)Append进来,写新文件,则出现提示是:删除了很多reference,新文件没有权限限制了!但所有的跳转都没有了,书签还在但跳转没有了,目录也在但跳转也没有了!(因为APPEND后位置不一样了,原有的reference就不准了,只能删掉)。 另外文件变成内部没有压缩的,很大! 这个方法有缺陷,不好。
如果参考podofoencrypt,PdfVecObjects和PdfParser读入旧文件(有owner密码), 再PdfWriter写新文件,则成功,新文件没有权限限制了!书签还在,跳转都还在。只是文件变成内部没有压缩的,很大! 用winrar可以压缩这个pdf文件到很小。
内部未压缩的pdf文件,可以用acrobat reader打开,再另存,OK,就变成内部压缩的pdf文件了,文件很小。也可以用acrobat打开和另存,这时不仅压缩了,而且还带快速WEB查看功能。
这个方法可以,成功!
总结来说,就是podofo在打开PDF文件时,会自动解密及解压缩,保存成新文件后,就没权限限制了,再用acrobat reader另存下,使文件变小。
上干货:
#include "src\podofo.h"
#include <stdlib.h>
#include <cstdio>
using namespace PoDoFo;
#ifdef _HAVE_CONFIG
#include <config.h>
#endif // _HAVE_CONFIG
void myconvert( const char* pszInput1, const char* pszOutput )
{
PdfVecObjects objects;
PdfParser parser( &objects );
printf("Reading file: %s\n", pszInput1 );
objects.SetAutoDelete( true );
parser.ParseFile( pszInput1 );
printf("PdfVecObjects.GetMaxObjectCount(): %ld\n", (long)objects.GetObjectCount() );
printf("PdfParser.GetEncrypted(): %d\n", parser.GetEncrypted() );
printf("************\nPdfWriter: \n" );
PdfWriter writer( &parser );
printf("GetEncrypted(): %d\n", writer.GetEncrypted() );
printf("GetLinearized(): %d\n", writer.GetLinearized() );
printf("GetPdfVersionString(): %s\n", writer.GetPdfVersionString() );
printf("GetWriteMode(): %d\n", writer.GetWriteMode() ); //ePdfWriteMode_Compact=1
printf("Writing file: %s\n", pszOutput );
writer.Write( pszOutput );
}
int main( int argc, char* argv[] )
{
char* pszInput1;
char* pszOutput;
if( argc != 3 )
{
exit( -1 );
}
pszInput1 = argv[1];
pszOutput = argv[2];
try
{
myconvert( pszInput1, pszOutput );
}
catch( PdfError & e )
{
fprintf( stderr, "Error %i occurred!\n", e.GetError() );
e.PrintErrorMsg();
return e.GetError();
}
return 0;
}
好吧,podofo太复杂,我也只会这么多。