cpp
#include <podofo/podofo.h>
#include <iostream>
// All PoDoFo classes are member of the PoDoFo namespace.
//using namespace std;
using namespace PoDoFo;
PdfFont* getFont(PdfDocument& doc);
// Base14 + other non-Base14 fonts for comparison
static const char* s_base14fonts[] =
{
"Times-Roman",
"Times-Italic",
"Times-Bold",
"Times-BoldItalic",
"Helvetica",
"Helvetica-Oblique",
"Helvetica-Bold",
"Helvetica-BoldOblique",
"Courier",
"Courier-Oblique",
"Courier-Bold",
"Courier-BoldOblique",
"Symbol",
"ZapfDingbats",
"Arial",
"Verdana"
};
const char* GetBase14FontName(unsigned i)
{
if (i >= std::size(s_base14fonts))
return nullptr;
return s_base14fonts[i];
}
void DrawRedFrame(PdfPainter& painter, double x, double y, double width, double height)
{
// draw red box
painter.GraphicsState.SetFillColor(PdfColor(1.0f, 0.0f, 0.0f));
painter.GraphicsState.SetStrokeColor(PdfColor(1.0f, 0.0f, 0.0f));
painter.DrawLine(x, y, x + width, y);
if (height > 0.0f)
{
painter.DrawLine(x, y, x, y + height);
painter.DrawLine(x + width, y, x + width, y + height);
painter.DrawLine(x, y + height, x + width, y + height);
}
// restore to black
painter.GraphicsState.SetFillColor(PdfColor(0.0f, 0.0f, 0.0f));
painter.GraphicsState.SetStrokeColor(PdfColor(0.0f, 0.0f, 0.0f));
}
void DemoBase14Fonts(PdfPainter& painter, PdfPage& page, PdfDocument& document)
{
PdfFontSearchParams params;
params.AutoSelect = PdfFontAutoSelectBehavior::Standard14;
double x = 56, y = page.GetRect().Height - 56.69;
std::string_view demo_text = "abcdefgABCDEFG12345!#$%&+-@? ";
double height = 0.0f, width = 0.0f;
// draw sample of all types
for (unsigned i = 0; i < std::size(s_base14fonts); i++)
{
x = 56; y = y - 25;
std::string text;
if (i == 12)
{
// Or u8"♠♣♥♦": Symbol font doesn't support regular characters
text = u8"\\u2660\\u2663\\u2665\\u2666";
}
else if (i == 13)
{
// Or u8"❏❑▲▼": ZapfDingbats font doesn't support regular characters
text = u8"\\u274f\\u2751\\u25b2\\u25bc";
}
else
{
text = demo_text;
text.append(GetBase14FontName(i));
}
PdfFont* font = document.GetFonts().SearchFont(GetBase14FontName(i), params);
font = &document.GetFonts().GetStandard14Font(PdfStandard14FontType::Helvetica);
font = getFont(document);
if (font == nullptr)
throw std::runtime_error("Font not found");
painter.TextState.SetFont(*font, 12.0);
width = font->GetStringLength(text, painter.TextState);
height = font->GetLineSpacing(painter.TextState);
std::cout << GetBase14FontName(i) << " Width = " << width << " Height = " << height << std::endl;
// draw red box
DrawRedFrame(painter, x, y, width, height);
// draw text
painter.DrawText(text, x, y);
}
// draw some individual characters:
std::string_view demo_text2 = " @_1jiPlg .;";
auto helveticaStd14 = document.GetFonts().SearchFont("Helvetica", params);
auto arialImported = document.GetFonts().SearchFont("Arial");
helveticaStd14 = getFont(document);
arialImported = getFont(document);
auto& metrics = arialImported->GetMetrics();
std::cout << "Non base 14 font characteristics" << std::endl;
std::cout << "Font name: " << metrics.GetFontName() << std::endl;
std::cout << "Family font name: " << metrics.GetFontFamilyName() << std::endl;
std::cout << "Font file path: " << metrics.GetFilePath() << std::endl;
std::cout << "Font face index: " << metrics.GetFaceIndex() << std::endl;
// draw individuals
for (unsigned i = 0; i < demo_text2.length(); i++)
{
x = 56; y = y - 25;
std::string text;
if (i == 0)
text = "Helvetica / Arial Comparison:";
else
text = (std::string)demo_text2.substr(i, 1);
painter.TextState.SetFont(*helveticaStd14, 12);
height = helveticaStd14->GetLineSpacing(painter.TextState);
width = helveticaStd14->GetStringLength(text, painter.TextState);
// draw red box
DrawRedFrame(painter, x, y, width, height);
// draw text
painter.DrawText(text, x, y);
if (i > 0)
{
// draw again, with non-Base14 font
painter.TextState.SetFont(*arialImported, 12);
height = arialImported->GetLineSpacing(painter.TextState);
width = arialImported->GetStringLength((std::string_view)text, painter.TextState);
// draw red box
DrawRedFrame(painter, x + 100, y, width, height);
// draw text
painter.DrawText(text, x + 100, y);
}
}
}
void drawSquareWithCross(PdfPainter& painter, double x, double y)
{
painter.Save();
const double SquareSize = 6;
painter.GraphicsState.SetLineWidth(0.6);
painter.DrawRectangle(x - SquareSize / 2, y - SquareSize / 2, SquareSize, SquareSize);
painter.GraphicsState.SetLineWidth(0);
painter.DrawLine(x, y - SquareSize / 2, x, y + SquareSize / 2);
painter.DrawLine(x - SquareSize / 2, y, x + SquareSize / 2, y);
painter.Restore();
}
void createDocument2(const char* filename)
{
PdfMemDocument doc;
auto& page = doc.GetPages().CreatePage(PdfPage::CreateStandardPageSize(PdfPageSize::A4));
PdfFontCreateParams params;
params.Encoding = PdfEncodingMapFactory::WinAnsiEncodingInstance();
auto& font = doc.GetFonts().GetStandard14Font(PdfStandard14FontType::Helvetica, params);
PdfPainter painter;
auto& operators = static_cast<PdfContentStreamOperators&>(painter);
painter.SetCanvas(page);
painter.TextState.SetFont(font, 15);
painter.TextObject.Begin();
painter.TextObject.MoveTo(100, 500);
painter.TextObject.AddText("Test1");
// Some low level operations
operators.TJ_Operator_Begin();
operators.TJ_Operator_Glyphs("_W", false);
operators.TJ_Operator_Delta(-500);
operators.TJ_Operator_Glyphs("orld", false);
operators.TJ_Operator_End();
painter.TextObject.End();
painter.DrawText("Test2", 100, 600, PdfDrawTextStyle::StrikeThrough);
PdfPainterPath path;
path.MoveTo(20, 20);
path.AddArcTo(150, 20, 150, 70, 50);
path.AddLineTo(150, 120);
path.AddArc(200, 120, 50, 3.14159, 3.14159 / 8, true);
auto currPoint1 = path.GetCurrentPoint();
PdfPainterPath path2;
path2.MoveTo(250, 120);
path2.AddLineTo(250, 80);
path.AddPath(path2, true);
auto currPoint2 = path.GetCurrentPoint();
painter.DrawPath(path, PdfPathDrawMode::Stroke);
path.Reset();
path.MoveTo(40, 40);
path.AddLineTo(100, 40);
path.AddLineTo(70, 80);
path.AddLineTo(40, 40);
path.AddCircle(200, 300, 60);
painter.DrawPath(path, PdfPathDrawMode::Fill);
drawSquareWithCross(painter, 100, 20);
drawSquareWithCross(painter, 100, 70);
drawSquareWithCross(painter, 150, 70);
drawSquareWithCross(painter, currPoint1.X, currPoint1.Y);
drawSquareWithCross(painter, currPoint2.X, currPoint2.Y);
painter.FinishDrawing();
doc.Save(filename);
}
// 创建一个PDF文件
void testCreatePDF(const char* filename) {
PdfMemDocument document;
PdfPainter painter;
PdfFont* font;
try
{
auto& page = document.GetPages().CreatePage(PdfPage::CreateStandardPageSize(PdfPageSize::A4));
painter.SetCanvas(page);
font = document.GetFonts().SearchFont("Microsoft YaHei");
//font = &document.GetFonts().GetStandard14Font(PdfStandard14FontType::Helvetica);
font = getFont(document);
if (font == nullptr)
throw std::runtime_error("Invalid handle");
auto& metrics = font->GetMetrics();
std::cout << "The font name is " << metrics.GetFontName() << std::endl;
std::cout << "The family font name is " << metrics.GetFontFamilyName() << std::endl;
std::cout << "The font file path is " << metrics.GetFilePath() << std::endl;
std::cout << "The font face index is " << metrics.GetFaceIndex() << std::endl;
painter.TextState.SetFont(*font, 18);
// painter.SetColor(1.0, 0.0, 0.0);
painter.DrawText("ABCDEFGHIKLMNOPQRSTVXYZ", 56.69, page.GetRect().Height - 56.69);
try
{
// Add also some non-ASCII characters (Cyrillic alphabet)
painter.DrawText("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЫЭЮЯ", 56.69, page.GetRect().Height - 80);
}
catch (PdfError& err)
{
if (err.GetCode() == PdfErrorCode::InvalidFontData)
std::cout << "WARNING: The matched font " << metrics.GetFontName() << " doesn't support cyrillic" << std::endl;
}
//DemoBase14Fonts(painter, page, document);
painter.FinishDrawing();
// Set some additional information on the PDF file.
document.GetMetadata().SetCreator(PdfString("examplahelloworld - A PoDoFo test application"));
document.GetMetadata().SetAuthor(PdfString("Dominik Seichter"));
document.GetMetadata().SetTitle(PdfString("Hello World"));
document.GetMetadata().SetSubject(PdfString("Testing the PoDoFo PDF Library"));
document.GetMetadata().SetKeywords(std::vector<std::string>({ "Test", "PDF", "Hello World" }));
// The last step is to close the document.
document.Save(filename);
}
catch (PdfError& e)
{
// All PoDoFo methods may throw exceptions
// make sure that painter.FinishPage() is called
// or who will get an assert in its destructor
try
{
painter.FinishDrawing();
}
catch (...)
{
// Ignore errors this time
}
throw e;
}
}
#include <windows.h>
HFONT createWinFont() {
return CreateFont(
-15/*高度*/, -7.5/*宽度*/, 0/*不用管*/, 0/*不用管*/, 400 /*一般这个值设为400*/,
FALSE/*不带斜体*/, FALSE/*不带下划线*/, FALSE/*不带删除线*/,
DEFAULT_CHARSET, //这里我们使用默认字符集,还有其他以 _CHARSET 结尾的常量可用
OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, //这行参数不用管
DEFAULT_QUALITY, //默认输出质量
FF_DONTCARE, //不指定字体族*/
"微软雅黑" //字体名
);
}
PdfFont* getFont(PdfDocument& doc) {
return &doc.GetFonts().GetOrCreateFont(createWinFont());
}
void testFonts() {
}
void test() {
//auto& fc = GetFontConfigWrapper();
//fc.AddFontDirectory("C://fonts");
//PdfCommon::AddFontDirectory("C:\\Users\\ws\Downloads\\podofo\\extern\\resources\\Fonts\\");
PdfCommon::SetMaxLoggingSeverity(PdfLogSeverity::Warning);
testCreatePDF("./test.pdf");
createDocument2("./test2.pdf");
}
输出
/*
The font name is MicrosoftYaHei
The family font name is Microsoft YaHei
The font file path is
The font face index is 0
*/
参考
GitHub - podofo/podofo: A C++17 PDF manipulation library