FX_BOOL CPDF_PageOrganizer::PDFDocInit(CPDF_Document* pDestPDFDoc, CPDF_Document* pSrcPDFDoc) { if (!pDestPDFDoc || !pSrcPDFDoc) return FALSE; CPDF_Dictionary* pNewRoot = pDestPDFDoc->GetRoot(); if (!pNewRoot) return FALSE; CPDF_Dictionary* DInfoDict = pDestPDFDoc->GetInfo(); if (!DInfoDict) return FALSE; CFX_ByteString producerstr; producerstr.Format("PDFium"); DInfoDict->SetFor("Producer", new CPDF_String(producerstr, FALSE)); CFX_ByteString cbRootType = pNewRoot->GetStringFor("Type", ""); if (cbRootType.IsEmpty()) pNewRoot->SetFor("Type", new CPDF_Name("Catalog")); CPDF_Object* pElement = pNewRoot->GetObjectFor("Pages"); CPDF_Dictionary* pNewPages = pElement ? ToDictionary(pElement->GetDirect()) : nullptr; if (!pNewPages) { pNewPages = new CPDF_Dictionary(pDestPDFDoc->GetByteStringPool()); pNewRoot->SetReferenceFor("Pages", pDestPDFDoc, pDestPDFDoc->AddIndirectObject(pNewPages)); } CFX_ByteString cbPageType = pNewPages->GetStringFor("Type", ""); if (cbPageType == "") { pNewPages->SetFor("Type", new CPDF_Name("Pages")); } if (!pNewPages->GetArrayFor("Kids")) { pNewPages->SetIntegerFor("Count", 0); pNewPages->SetReferenceFor("Kids", pDestPDFDoc, pDestPDFDoc->AddIndirectObject(new CPDF_Array)); } return TRUE; }
CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName) { pLogFont->lfHeight = -1000; pLogFont->lfWidth = 0; HGDIOBJ hFont = CreateFontIndirectA(pLogFont); HDC hDC = CreateCompatibleDC(nullptr); hFont = SelectObject(hDC, hFont); int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr); if (tm_size == 0) { hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return nullptr; } LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf); GetOutlineTextMetrics(hDC, tm_size, ptm); int flags = CalculateFlags(false, pLogFont->lfItalic != 0, (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET); bool bCJK = pLogFont->lfCharSet == FXFONT_CHINESEBIG5_CHARSET || pLogFont->lfCharSet == FXFONT_GB2312_CHARSET || pLogFont->lfCharSet == FXFONT_HANGUL_CHARSET || pLogFont->lfCharSet == FXFONT_SHIFTJIS_CHARSET; CFX_ByteString basefont; if (bTranslateName && bCJK) basefont = FPDF_GetPSNameFromTT(hDC); if (basefont.IsEmpty()) basefont = pLogFont->lfFaceName; int italicangle = ptm->otmItalicAngle / 10; int ascend = ptm->otmrcFontBox.top; int descend = ptm->otmrcFontBox.bottom; int capheight = ptm->otmsCapEmHeight; int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; FX_Free(tm_buf); basefont.Replace(" ", ""); CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); pBaseDict->SetNameFor("Type", "Font"); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { if (pLogFont->lfCharSet == FXFONT_ANSI_CHARSET || pLogFont->lfCharSet == FXFONT_DEFAULT_CHARSET || pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET) { pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); } else { CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); } int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); CPDF_Array* pWidths = new CPDF_Array; for (size_t i = 0; i < 224; i++) pWidths->AddInteger(char_widths[i]); ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, pWidths); } else { pFontDict = ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont, [&hDC](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } AddIndirectObject(pBaseDict); CPDF_Array* pBBox = new CPDF_Array; for (int i = 0; i < 4; i++) pBBox->AddInteger(bbox[i]); CPDF_Dictionary* pFontDesc = CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend, pBBox, pLogFont->lfWeight / 5); pFontDesc->SetIntegerFor("CapHeight", capheight); pFontDict->SetReferenceFor("FontDescriptor", this, AddIndirectObject(pFontDesc)); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return LoadFont(pBaseDict); }
CPDF_Dictionary* CPDF_Document::ProcessbCJK( CPDF_Dictionary* pBaseDict, int charset, FX_BOOL bVert, CFX_ByteString basefont, std::function<void(FX_WCHAR, FX_WCHAR, CPDF_Array*)> Insert) { CPDF_Dictionary* pFontDict = new CPDF_Dictionary(m_pByteStringPool); CFX_ByteString cmap; CFX_ByteString ordering; int supplement = 0; CPDF_Array* pWidthArray = new CPDF_Array; switch (charset) { case FXFONT_CHINESEBIG5_CHARSET: cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; pWidthArray->AddInteger(1); Insert(0x20, 0x7e, pWidthArray); break; case FXFONT_GB2312_CHARSET: cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H"; ordering = "GB1"; supplement = 2; pWidthArray->AddInteger(7716); Insert(0x20, 0x20, pWidthArray); pWidthArray->AddInteger(814); Insert(0x21, 0x7e, pWidthArray); break; case FXFONT_HANGUL_CHARSET: cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; pWidthArray->AddInteger(1); Insert(0x20, 0x7e, pWidthArray); break; case FXFONT_SHIFTJIS_CHARSET: cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; pWidthArray->AddInteger(231); Insert(0x20, 0x7d, pWidthArray); pWidthArray->AddInteger(326); Insert(0xa0, 0xa0, pWidthArray); pWidthArray->AddInteger(327); Insert(0xa1, 0xdf, pWidthArray); pWidthArray->AddInteger(631); Insert(0x7e, 0x7e, pWidthArray); break; } pBaseDict->SetNameFor("Subtype", "Type0"); pBaseDict->SetNameFor("BaseFont", basefont); pBaseDict->SetNameFor("Encoding", cmap); pFontDict->SetFor("W", pWidthArray); pFontDict->SetNameFor("Type", "Font"); pFontDict->SetNameFor("Subtype", "CIDFontType2"); pFontDict->SetNameFor("BaseFont", basefont); CPDF_Dictionary* pCIDSysInfo = new CPDF_Dictionary(m_pByteStringPool); pCIDSysInfo->SetStringFor("Registry", "Adobe"); pCIDSysInfo->SetStringFor("Ordering", ordering); pCIDSysInfo->SetIntegerFor("Supplement", supplement); pFontDict->SetFor("CIDSystemInfo", pCIDSysInfo); CPDF_Array* pArray = new CPDF_Array; pBaseDict->SetFor("DescendantFonts", pArray); pArray->AddReference(this, AddIndirectObject(pFontDict)); return pFontDict; }
DLLEXPORT int STDCALL FPDFPage_Flatten(FPDF_PAGE page, int nFlag) { CPDF_Page* pPage = CPDFPageFromFPDFPage(page); if (!page) { return FLATTEN_FAIL; } CPDF_Document* pDocument = pPage->m_pDocument; CPDF_Dictionary* pPageDict = pPage->m_pFormDict; if (!pDocument || !pPageDict) { return FLATTEN_FAIL; } CPDF_ObjectArray ObjectArray; CPDF_RectArray RectArray; int iRet = FLATTEN_FAIL; iRet = ParserAnnots(pDocument, pPageDict, &RectArray, &ObjectArray, nFlag); if (iRet == FLATTEN_NOTHINGTODO || iRet == FLATTEN_FAIL) return iRet; CFX_FloatRect rcOriginalCB; CFX_FloatRect rcMerger = CalculateRect(&RectArray); CFX_FloatRect rcOriginalMB = pPageDict->GetRectFor("MediaBox"); if (pPageDict->KeyExist("CropBox")) rcOriginalMB = pPageDict->GetRectFor("CropBox"); if (rcOriginalMB.IsEmpty()) { rcOriginalMB = CFX_FloatRect(0.0f, 0.0f, 612.0f, 792.0f); } rcMerger.left = rcMerger.left < rcOriginalMB.left ? rcOriginalMB.left : rcMerger.left; rcMerger.right = rcMerger.right > rcOriginalMB.right ? rcOriginalMB.right : rcMerger.right; rcMerger.top = rcMerger.top > rcOriginalMB.top ? rcOriginalMB.top : rcMerger.top; rcMerger.bottom = rcMerger.bottom < rcOriginalMB.bottom ? rcOriginalMB.bottom : rcMerger.bottom; if (pPageDict->KeyExist("ArtBox")) rcOriginalCB = pPageDict->GetRectFor("ArtBox"); else rcOriginalCB = rcOriginalMB; if (!rcOriginalMB.IsEmpty()) { CPDF_Array* pMediaBox = new CPDF_Array(); pMediaBox->Add(new CPDF_Number(rcOriginalMB.left)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.bottom)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.right)); pMediaBox->Add(new CPDF_Number(rcOriginalMB.top)); pPageDict->SetFor("MediaBox", pMediaBox); } if (!rcOriginalCB.IsEmpty()) { CPDF_Array* pCropBox = new CPDF_Array(); pCropBox->Add(new CPDF_Number(rcOriginalCB.left)); pCropBox->Add(new CPDF_Number(rcOriginalCB.bottom)); pCropBox->Add(new CPDF_Number(rcOriginalCB.right)); pCropBox->Add(new CPDF_Number(rcOriginalCB.top)); pPageDict->SetFor("ArtBox", pCropBox); } CPDF_Dictionary* pRes = pPageDict->GetDictFor("Resources"); if (!pRes) { pRes = new CPDF_Dictionary(pDocument->GetByteStringPool()); pPageDict->SetFor("Resources", pRes); } CPDF_Stream* pNewXObject = new CPDF_Stream( nullptr, 0, new CPDF_Dictionary(pDocument->GetByteStringPool())); uint32_t dwObjNum = pDocument->AddIndirectObject(pNewXObject); CPDF_Dictionary* pPageXObject = pRes->GetDictFor("XObject"); if (!pPageXObject) { pPageXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); pRes->SetFor("XObject", pPageXObject); } CFX_ByteString key = ""; int nStreams = ObjectArray.GetSize(); if (nStreams > 0) { for (int iKey = 0; /*iKey < 100*/; iKey++) { char sExtend[5] = {}; FXSYS_itoa(iKey, sExtend, 10); key = CFX_ByteString("FFT") + CFX_ByteString(sExtend); if (!pPageXObject->KeyExist(key)) break; } } SetPageContents(key, pPageDict, pDocument); CPDF_Dictionary* pNewXORes = nullptr; if (!key.IsEmpty()) { pPageXObject->SetReferenceFor(key, pDocument, dwObjNum); CPDF_Dictionary* pNewOXbjectDic = pNewXObject->GetDict(); pNewXORes = new CPDF_Dictionary(pDocument->GetByteStringPool()); pNewOXbjectDic->SetFor("Resources", pNewXORes); pNewOXbjectDic->SetNameFor("Type", "XObject"); pNewOXbjectDic->SetNameFor("Subtype", "Form"); pNewOXbjectDic->SetIntegerFor("FormType", 1); pNewOXbjectDic->SetNameFor("Name", "FRM"); CFX_FloatRect rcBBox = pPageDict->GetRectFor("ArtBox"); pNewOXbjectDic->SetRectFor("BBox", rcBBox); } for (int i = 0; i < nStreams; i++) { CPDF_Dictionary* pAnnotDic = ObjectArray.GetAt(i); if (!pAnnotDic) continue; CFX_FloatRect rcAnnot = pAnnotDic->GetRectFor("Rect"); rcAnnot.Normalize(); CFX_ByteString sAnnotState = pAnnotDic->GetStringFor("AS"); CPDF_Dictionary* pAnnotAP = pAnnotDic->GetDictFor("AP"); if (!pAnnotAP) continue; CPDF_Stream* pAPStream = pAnnotAP->GetStreamFor("N"); if (!pAPStream) { CPDF_Dictionary* pAPDic = pAnnotAP->GetDictFor("N"); if (!pAPDic) continue; if (!sAnnotState.IsEmpty()) { pAPStream = pAPDic->GetStreamFor(sAnnotState); } else { auto it = pAPDic->begin(); if (it != pAPDic->end()) { CPDF_Object* pFirstObj = it->second; if (pFirstObj) { if (pFirstObj->IsReference()) pFirstObj = pFirstObj->GetDirect(); if (!pFirstObj->IsStream()) continue; pAPStream = pFirstObj->AsStream(); } } } } if (!pAPStream) continue; CPDF_Dictionary* pAPDic = pAPStream->GetDict(); CFX_Matrix matrix = pAPDic->GetMatrixFor("Matrix"); CFX_FloatRect rcStream; if (pAPDic->KeyExist("Rect")) rcStream = pAPDic->GetRectFor("Rect"); else if (pAPDic->KeyExist("BBox")) rcStream = pAPDic->GetRectFor("BBox"); if (rcStream.IsEmpty()) continue; CPDF_Object* pObj = pAPStream; if (pObj) { CPDF_Dictionary* pObjDic = pObj->GetDict(); if (pObjDic) { pObjDic->SetNameFor("Type", "XObject"); pObjDic->SetNameFor("Subtype", "Form"); } } CPDF_Dictionary* pXObject = pNewXORes->GetDictFor("XObject"); if (!pXObject) { pXObject = new CPDF_Dictionary(pDocument->GetByteStringPool()); pNewXORes->SetFor("XObject", pXObject); } CFX_ByteString sFormName; sFormName.Format("F%d", i); pXObject->SetReferenceFor(sFormName, pDocument, pDocument->AddIndirectObject(pObj)); CPDF_StreamAcc acc; acc.LoadAllData(pNewXObject); const uint8_t* pData = acc.GetData(); CFX_ByteString sStream(pData, acc.GetSize()); if (matrix.IsIdentity()) { matrix.a = 1.0f; matrix.b = 0.0f; matrix.c = 0.0f; matrix.d = 1.0f; matrix.e = 0.0f; matrix.f = 0.0f; } CFX_ByteString sTemp; CFX_Matrix m = GetMatrix(rcAnnot, rcStream, matrix); sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f, sFormName.c_str()); sStream += sTemp; pNewXObject->SetData(sStream.raw_str(), sStream.GetLength()); } pPageDict->RemoveFor("Annots"); ObjectArray.RemoveAll(); RectArray.RemoveAll(); return FLATTEN_SUCCESS; }