bool GenerateFreeTextAP(CPDF_Document* pDoc,
|
CPDF_Dictionary* pAnnotDict) {
|
|
// DA is required
|
ByteString DA;
|
if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA"))
|
DA = pDAObj->GetString();
|
if (DA.IsEmpty())
|
return false;
|
|
CPDF_DefaultAppearance appearance(DA);
|
|
float fFontSize = 0;
|
Optional<ByteString> font = appearance.GetFont(&fFontSize);
|
if (!font)
|
return false;
|
|
ByteString font_name = *font;
|
CFX_Color crText = CFX_Color::ParseColor(DA);
|
|
|
CPDF_Dictionary* pDRFontDict = pAnnotDict->GetDictFor("Font");
|
if (!pDRFontDict)
|
return false;
|
|
CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(font_name);
|
if (!pFontDict) {
|
pFontDict = pDoc->NewIndirect<CPDF_Dictionary>();
|
pFontDict->SetNewFor<CPDF_Name>("Type", "Font");
|
pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
|
pFontDict->SetNewFor<CPDF_Name>("BaseFont", CFX_Font::kDefaultAnsiFontName);
|
pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding");
|
pDRFontDict->SetFor(font_name, pFontDict->MakeReference(pDoc));
|
}
|
CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict);
|
if (!pDefFont)
|
return false;
|
|
CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect");
|
int32_t nRotate = 0;
|
//if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK"))
|
// nRotate = pMKDict->GetIntegerFor("R");
|
|
CFX_FloatRect rcBBox;
|
CFX_Matrix matrix;
|
switch (nRotate % 360) {
|
case 0:
|
rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
|
rcAnnot.top - rcAnnot.bottom);
|
break;
|
case 90:
|
matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0);
|
rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
|
rcAnnot.right - rcAnnot.left);
|
break;
|
case 180:
|
matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left,
|
rcAnnot.top - rcAnnot.bottom);
|
rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left,
|
rcAnnot.top - rcAnnot.bottom);
|
break;
|
case 270:
|
matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom);
|
rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom,
|
rcAnnot.right - rcAnnot.left);
|
break;
|
}
|
|
BorderStyle nBorderStyle = BorderStyle::SOLID;
|
float fBorderWidth = 1;
|
CPVT_Dash dsBorder(3, 0, 0);
|
CFX_Color crLeftTop;
|
CFX_Color crRightBottom;
|
/*
|
if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) {
|
if (pBSDict->KeyExist("W"))
|
fBorderWidth = pBSDict->GetNumberFor("W");
|
|
if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) {
|
dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1),
|
pArray->GetIntegerAt(2));
|
}
|
if (pBSDict->GetStringFor("S").GetLength()) {
|
switch (pBSDict->GetStringFor("S")[0]) {
|
case 'S':
|
nBorderStyle = BorderStyle::SOLID;
|
break;
|
case 'D':
|
nBorderStyle = BorderStyle::DASH;
|
break;
|
case 'B':
|
nBorderStyle = BorderStyle::BEVELED;
|
fBorderWidth *= 2;
|
crLeftTop = CFX_Color(CFX_Color::kGray, 1);
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.5);
|
break;
|
case 'I':
|
nBorderStyle = BorderStyle::INSET;
|
fBorderWidth *= 2;
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
|
break;
|
case 'U':
|
nBorderStyle = BorderStyle::UNDERLINE;
|
break;
|
}
|
}
|
}
|
*/
|
CFX_Color crBorder;
|
CFX_Color crBG;
|
/*
|
if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) {
|
if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC"))
|
crBorder = CFX_Color::ParseColor(*pArray);
|
if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG"))
|
crBG = CFX_Color::ParseColor(*pArray);
|
}
|
*/
|
std::ostringstream sAppStream;
|
ByteString sBG = GenerateColorAP(crBG, PaintOperation::FILL);
|
if (sBG.GetLength() > 0) {
|
sAppStream << "q\n"
|
<< sBG << rcBBox.left << " " << rcBBox.bottom << " "
|
<< rcBBox.Width() << " " << rcBBox.Height() << " re f\n"
|
<< "Q\n";
|
}
|
ByteString sBorderStream =
|
GenerateBorderAP(rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom,
|
nBorderStyle, dsBorder);
|
if (sBorderStream.GetLength() > 0)
|
sAppStream << "q\n" << sBorderStream << "Q\n";
|
|
CFX_FloatRect rcBody =
|
CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth,
|
rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth);
|
rcBody.Normalize();
|
|
CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP");
|
if (!pAPDict)
|
pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP");
|
|
CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N");
|
if (!pNormalStream) {
|
pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
|
pAPDict->SetFor("N", pNormalStream->MakeReference(pDoc));
|
}
|
CPDF_Dictionary* pStreamDict = pNormalStream->GetDict();
|
if (pStreamDict) {
|
pStreamDict->SetMatrixFor("Matrix", matrix);
|
pStreamDict->SetRectFor("BBox", rcBBox);
|
CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
|
if (pStreamResList) {
|
CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font");
|
if (!pStreamResFontList)
|
pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
|
if (!pStreamResFontList->KeyExist(font_name)) {
|
pStreamResFontList->SetFor(font_name, pFontDict->MakeReference(pDoc));
|
}
|
} else {
|
//pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
|
pStreamResList = pStreamDict->GetDictFor("Resources");
|
}
|
}
|
|
|
WideString swValue =
|
FPDF_GetFieldAttr(pAnnotDict, "Contents")
|
? FPDF_GetFieldAttr(pAnnotDict, "Contents")->GetUnicodeText()
|
: WideString();
|
int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q")
|
? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger()
|
: 0;
|
uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff")
|
? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger()
|
: 0;
|
uint32_t dwMaxLen = 0;
|
CPVT_FontMap map(
|
pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr,
|
pDefFont, font_name);
|
CPDF_VariableText::Provider prd(&map);
|
CPDF_VariableText vt;
|
vt.SetProvider(&prd);
|
vt.SetPlateRect(rcBody);
|
vt.SetAlignment(nAlign);
|
if (IsFloatZero(fFontSize))
|
vt.SetAutoFontSize(true);
|
else
|
vt.SetFontSize(fFontSize);
|
|
bool bMultiLine = true; //(dwFlags >> 12) & 1;
|
if (bMultiLine) {
|
vt.SetMultiLine(true);
|
vt.SetAutoReturn(true);
|
}
|
uint16_t subWord = 0;
|
if ((dwFlags >> 13) & 1) {
|
subWord = '*';
|
vt.SetPasswordChar(subWord);
|
}
|
bool bCharArray = (dwFlags >> 24) & 1;
|
if (bCharArray)
|
vt.SetCharArray(dwMaxLen);
|
else
|
vt.SetLimitChar(dwMaxLen);
|
|
vt.Initialize();
|
vt.SetText(swValue);
|
vt.RearrangeAll();
|
CFX_FloatRect rcContent = vt.GetContentRect();
|
CFX_PointF ptOffset;
|
if (!bMultiLine) {
|
ptOffset =
|
CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f);
|
}
|
ByteString sBody = GenerateEditAP(&map, vt.GetIterator(), ptOffset,
|
!bCharArray, subWord);
|
if (sBody.GetLength() > 0) {
|
sAppStream << "/Tx BMC\n"
|
<< "q\n";
|
if (rcContent.Width() > rcBody.Width() ||
|
rcContent.Height() > rcBody.Height()) {
|
sAppStream << rcBody.left << " " << rcBody.bottom << " "
|
<< rcBody.Width() << " " << rcBody.Height()
|
<< " re\nW\nn\n";
|
}
|
sAppStream << "BT\n"
|
<< GenerateColorAP(crText, PaintOperation::FILL) << sBody
|
<< "ET\n"
|
<< "Q\nEMC\n";
|
}
|
|
|
|
|
if (pNormalStream) {
|
pNormalStream->SetDataFromStringstreamAndRemoveFilter(&sAppStream);
|
pStreamDict = pNormalStream->GetDict();
|
if (pStreamDict) {
|
pStreamDict->SetMatrixFor("Matrix", matrix);
|
pStreamDict->SetRectFor("BBox", rcBBox);
|
CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
|
if (pStreamResList) {
|
CPDF_Dictionary* pStreamResFontList =
|
pStreamResList->GetDictFor("Font");
|
if (!pStreamResFontList) {
|
pStreamResFontList =
|
pStreamResList->SetNewFor<CPDF_Dictionary>("Font");
|
}
|
if (!pStreamResFontList->KeyExist(font_name)) {
|
pStreamResFontList->SetFor(font_name, pFontDict->MakeReference(pDoc));
|
}
|
} else {
|
//pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone());
|
pStreamResList = pStreamDict->GetDictFor("Resources");
|
}
|
}
|
}
|
return true;
|
}
|