Hi everyone,
I have a problem with embedded fonts on PDFs (reports). We send via email invoices and other kind of reports with embedded fonts. When the PDF file size is less than 3MB all works fine, but if the PDF file size is >= 3MB the fonts doesn`t display correctly.
The documents below are a packingSlip and an invoice, one works fine, the other not.
1MB file example (fonts OK):
3MB file example (fonts NOT OK):
If I see the properties of the documents, both has embedded fonts but for some reason, if the document is bigger than 3MB, fonts doesn't show.
Anyone know how can I solve it?
The version of AX is 2009.
Thanks.
UPDATE: I just realized that the bad working is when the file has more than 2MB (not 3MB)
*This post is locked for comments
Hi Nikolaos Mäenpää,
There is a lot of code, I will show you where the loop is and where the report is generated.
CODE WHERE IS THE LOOP ( Classes\SalesFormLetter\Method\run() )
void run()
{
#OCCRetryCount
QueryRun query;
Counter infoLogCounter;
LogText logText;
boolean updateError;
dataAreaId curExtPreProgress = curext();
SalesFormLetterEndMultiThread salesFormLetterEndMultiThread;
FormLetterMultiThread formLetterMultiThread;
;
startDateTimeUpdate = DateTimeUtil::newDateTime(systemdateget(),timenow(),DateTimeUtil::getUserPreferredTimeZone());
this.progressInit("@SYS25781", progressTotal, #AviFormLetter);
progress.setText("@SYS26577");
if (salesParmUpdate.LateSelection)
{
if (!SalesParmUpdate::exist(this.parmId()))
{
this.parmId(NumberSeq::newGetNum(CompanyInfo::numRefParmId()).num());
this.createParmUpdateFromParmUpdateRecord(this.salesParmUpdate());
}
else
{
SalesParmTable::deleteWithoutUpdate(this.parmId(), true);
}
if (this.isInBatch())
{
this.resetParmListCommonCS();
this.transDate(systemdateget());
}
chooseLines = new QueryRun(salesParmUpdate.LateSelectionQuery);
this.chooseLines();
if (salesParmUpdate.numberOfLines() < 1)
checkFailed("@SYS26185");
}
else
{
if (this.isInBatch())
{
this.transDate(salesParmTable.Transdate);
}
}
if ( reArrangeNow && !this.reArrange(false) &&
!salesTable.QuotationId)
{
throw error("@SYS18447");
}
if (this.canMultiThread())
{
batchHeader = BatchHeader::construct(this.parmCurrentBatch().BatchJobId);
salesFormLetterEndMultiThread = SalesFormLetterEndMultiThread::newFormLetter(this,
salesParmUpdate.ParmId,
salesParmUpdate.Proforma,
startDateTimeUpdate);
batchHeader.addRuntimeTask(salesFormLetterEndMultiThread,this.parmCurrentBatch().RecId);
}
query = this.queryBuild();
if (printout == Printout::After && ! this.proforma())
{
journalList = this.newJournalList();
}
setprefix("@SYS25781");
while (query.next()) //LOOP
{
infoLogCounter = infolog.num();
infolog.updateViewSet(this);
if (printout == Printout::Current || this.proforma())
{
journalList = this.newJournalList();
}
salesParmTable = query.get(tablenum(SalesParmTable));
if (salesParmTable.SalesId != salesTable.SalesId)
{
salesTable = salesParmTable.salesTable();
}
if (this.checkIfSalesOrderExist(salesTable))
{
try
{
if (batchHeader)
{
formLetterMultiThread = FormLetterMultiThread::newFormLetter(this);
batchHeader.addRuntimeTask(formLetterMultiThread,this.parmCurrentBatch().RecId);
if(printout == Printout::Current && !this.proforma())
{
ttsbegin;
batchHeader.save();
ttscommit;
}
if(printout == Printout::After || this.proforma())
{
batchHeader.addDependency(salesFormLetterEndMultiThread,formLetterMultiThread,BatchDependencyStatus::FinishedOrError);
}
}
else
{
this.createJournal(); //HERE IT GO TO THE NEXT STEP OF THE LOGIC
}
}
catch (Exception::Deadlock)
{
#if.never //#Speedtest
if (speedExecute_Sales)
speedExecute_Sales.timing(SpeedSalesTiming::DeadLockInvoice, salesParmLine.itemId);
#endif
this.removeRecIdSuspension();
this.removeJournalFromList();
retry;
}
catch (Exception::UpdateConflict)
{
this.removeRecIdSuspension();
if (appl.ttsLevel() == 0)
{
if (xSession::currentRetryCount() >= #RetryNum)
{
throw Exception::UpdateConflictNotRecovered;
}
else
{
this.removeJournalFromList();
retry;
}
}
else
{
throw Exception::UpdateConflict;
}
}
catch (Exception::Error)
{
this.removeRecIdSuspension();
this.removeJournalFromList();
updateError = true;
ttsbegin;
logText = Info::infoCon2Str(infolog.copy(infoLogCounter 1,infolog.num()));
infolog.updateViewSet(this, false);
this.setForUpdateSalesParmTable();
salesParmTable.Log = logText;
salesParmTable.updateParmJobStatusContainErrors();
ttscommit;
}
//
catch(Exception::CLRError)
{
new InteropPermission(InteropKind::ClrInterop).assert();
//BP Deviation Documented
error(CLRInterop::getLastException().ToString());
CodeAccessPermission::revertAssert();
}
//
}
else
{
if (salesParmUpdate.SumBy == AccountOrder::None)
info(strfmt("@SYS15067", salesParmTable.SalesId));
}
infolog.updateViewSet(this, false);
//TRY TO CLEAN CACHE DOESN'T WORK
SysFlushDictionary::doFlush();
SysEvent::fireEvent(SysEventType::FlushDictionary);
//AOD
SysFlushAOD::doFlush();
SysEvent::fireEvent(SysEventType::FlushAOD);
//Data
SysFlushData::doFlush();
SysEvent::fireEvent(SysEventType::FlushData);
}
if (batchHeader)
{
if(printout == Printout::After || this.proforma())
batchHeader.save();
}
else
{
if (printout == Printout::After && ! salesParmUpdate.Proforma)
this.printJournal();
this.endUpdate();
}
progress = null;
if (updateError)
throw error("@SYS78886");
}
After this method there are a lot of clases/methods
The call to generate the report
void processReport()
{
SysEmailId emailId;
DirECommunicationAddress communicationAddress;
DirPartyTable partyTable;
DirPartyECommunicationRelationShip communicationRelationShip;
//-MDV 12/09/2019 GLPI 48230
SysGlobalCache cache = classfactory.globalCache();
ParmId parmId;
// MDV 12/09/2019 GLPI 48230
;
emailId = custPackingSlipJour.DlvMode == #AGNDlvMode ? #AGNPackingSlipEmailId : #NoAGNPackingSlipEmailId;
communicationTypeIdEmialId = AXZCustVendCommunicationTypeIdEmialId::findByEmailId(custTable.RecId, demandType, emailId);
select firstonly partyTable
where partyTable.PartyId == custTable.PartyId
join communicationRelationShip
where communicationRelationShip.PartyId == custTable.PartyId
join communicationAddress
where communicationAddress.RecId == communicationRelationShip.ValuesRecId &&
communicationAddress.ECommunicationTypeId == communicationTypeIdEmialId.ECommunicationTypeId;
if (!communicationTypeIdEmialId.SysEmailId)
warning(strfmt("@CSR877", custTable.AccountNum, demandType));
else
{
table = SysEmailTable::find(communicationTypeIdEmialId.SysEmailId);
pdfReportFile = this.generatePDF(custPackingSlipJour);
this.sendEmail(communicationTypeIdEmialId.SysEmailId,
custTable.LanguageId,
communicationAddress.Email,
this.attachments(),
AXZCustVendType::Cust);
//-MDV 12/09/2019 GLPI 48230
//TRY TO CLEAN CACHE
SysFlushDictionary::doFlush();
SysEvent::fireEvent(SysEventType::FlushDictionary);
//AOD
SysFlushAOD::doFlush();
SysEvent::fireEvent(SysEventType::FlushAOD);
//Data
SysFlushData::doFlush();
SysEvent::fireEvent(SysEventType::FlushData);
#AOT
TreeNode::findNode(#TablesPath).AOTrefresh();
TreeNode::findNode(#TableMapsPath).AOTrefresh();
TreeNode::findNode(#ViewsPath).AOTrefresh();
TreeNode::findNode(#ExtendedDataTypesPath).AOTrefresh();
TreeNode::findNode(#BaseEnumsPath).AOTrefresh();
TreeNode::findNode(#LicenseCodesPath).AOTrefresh();
TreeNode::findNode(#ConfigurationKeysPath).AOTrefresh();
TreeNode::findNode(#SecurityKeysPath).AOTrefresh();
TreeNode::findNode(#TableCollectionsPath).AOTrefresh();
TreeNode::findNode(#PerspectivesPath).AOTrefresh();
TreeNode::findNode(#MacrosPath).AOTrefresh();
TreeNode::findNode(#ClassesPath).AOTrefresh();
TreeNode::findNode(#ReportsPath).AOTrefresh();
TreeNode::findNode(#ReportTemplatesPath).AOTrefresh();
TreeNode::findNode(#SectionTemplatesPath).AOTrefresh();
TreeNode::findNode(#QueriesPath).AOTrefresh();
TreeNode::findNode(#JobsPath).AOTrefresh();
Dictionary::aodFlush();
Dictionary::dataFlush();
flush UtilElements, UtilIdElements;
// MDV 12/09/2019 GLPI 48230
info(strfmt("@CSR878", custTable.AccountNum, demandType));
}
}
And then the generation of the report: (Reports\ SalesPackingSlip\ fetch())
boolean fetch()
{
QueryRun tradeLoopTrans;
boolean hasReportBeenPrinted = false;
QueryRun markupLoopTrans;
int i; // FASF - 28/12/2010
QueryBuildDataSource qbds; // FASF - 09/02/2011
;
setprefix(this.design().caption());
if (custFormletterParameters.TransportationDocumentOnPackingSlip)
{
Shipment.height(0, Units::char);
}
while (custPackingSlipJour)
{
// VSS 07/11/2017 X09 Restos de pedido de albarán
VSSCustPackingSlipTransTmp::initFromSalesPackingSlipReport(custPackingSlipJour);
//-VSS 07/11/2017 X09 Restos de pedido de albarán
setprefix(strfmt("@SYS70896", custPackingSlipJour.PackingSlipId));
isSummaryUpdated = custPackingSlipJour.isSummaryUpdated();
element.design().languageID(custPackingSlipJour.LanguageId);
element.design().caption(strfmt("@SYS70896", custPackingSlipJour.PackingSlipId));
// Load print settings for this journal
salesFormLetterReport.loadPrintSettings(
custPackingslipJour,
custPackingSlipJour.salesTable(),
custPackingslipJour.LanguageId);
// acumulados de los distintos tipos de gasto
amountMarkupTax = 0;
amountMarkupTransport = 0;
amountMarkupOthers = 0;
while (salesFormLetterReport.moveNextPrintSetting())
{
// Set report print settings
element.unpackPrintJobSettings(salesFormLetterReport.getCurrentPrintSetting().parmPrintJobSettings().packPrintJobSettings());
element.printJobSettings().copies(salesFormLetterReport.getCurrentPrintSetting().parmNumberOfCopies());
printFooter = true; // FASF - 27/12/2010 - = this.totalsPage(FirstLast::First, true);
// FASF - BEGIN - 28/12/2010
printFooterDisc = true; // FASF - 16/02/2011 - Ahora se pinta siempre. this.totalsPage(FirstLast::First, true);
this.footerEnable(FooterDiscObserv, printFooterDisc);
printFooterTxt = false; // FASF - 16/02/2011 - Ahora no se pinta. this.totalsPage(FirstLast::Last, true);
this.footerEnable(FooterText, printFooterTxt);
// FASF - END - 28/12/2010
printDocuHeader = false;
printShipmentFooter = false;
// FASF - 14/01/2011 - Comprobamos si el albarán es NO valorado y quitamos los campos.
this.setNoValuedPackingSlip();
this.send(custPackingSlipJour);
lineHeaderPrintedCount = 0;
// FASF - 17/01/2011 - Borro los impuestos del anterior albarán.
while select taxWorkTrans
{
taxWorkTrans.delete();
}
// FASF - 16/02/2011 - Calculamos los gastos por tipo antes de pintar las lÃneas para que salgan en los
// totales de all las páginas, también calculamos los impuestos.
element.calcMarkupPerTypeAndTax();
// FASF - BEGIN - 16/02/2011 - Este bloque iba después de pintar el total por capÃtulos
// se ha movido porque ahora quieren los totales en todas las páginas.
i = 1; // FASF - 28/12/2010
firstBodyTaxTrans = true;
if (custFormletterParameters.TaxSpecPrintLevel != TaxSpecPrintLevel::None)
{
preTaxBaseAmount = 0;
while select taxWorkTrans
order by taxWorkTrans.TaxBaseAmount, taxWorkTrans.TaxCode
{
// FASF - 28/12/2010 - Añado en un contenedor el registro de taxSpec.
if ((taxWorkTrans.TaxBaseAmount == preTaxBaseAmount) ||
//-RSZ 06/05/2015 No acumular la base si no está asà indicado en la configuración del impuesto
(!TaxTable::find(taxWorkTrans.TaxCode).AQBaseCumulate))
// RSZ 06/05/2015
{
taxRecords[i] = [0,
TaxTable::printCode(taxWorkTrans.TaxCode),
TaxData::percent(taxWorkTrans.TaxCode, CustPackingSlipJour.DeliveryDate, 0),
taxWorkTrans.TaxAmount,
taxWorkTrans.TaxAmount];
}
else
{
taxRecords[i] = [taxWorkTrans.TaxBaseAmount,
TaxTable::printCode(taxWorkTrans.TaxCode),
TaxData::percent(taxWorkTrans.TaxCode, CustPackingSlipJour.DeliveryDate, 0),
taxWorkTrans.TaxAmount,
taxWorkTrans.TaxBaseAmount taxWorkTrans.TaxAmount];
}
i ;
// element.send(taxWorkTrans); // FASF - 28/12/2010 - Ya no se imprime TaxWorkTrans sino desde el pie.
preTaxBaseAmount = taxWorkTrans.TaxBaseAmount;
}
}
// FASF - END - 16/02/2011
tradeLoopTrans = new TradeLoopTrans(custPackingSlipJour,tablenum(VSSCustPackingSlipTransTmp)).buildQueryRun();
// FASF - BEGIN - 09/02/2011 - Añadir que ordene por CapÃtulo para la agrupación
qbds = tradeLoopTrans.query().dataSourceTable(tablenum(VSSCustPackingSlipTransTmp));
qbds.addSortField(fieldnum(VSSCustPackingSlipTransTmp, CustChapter), SortOrder::Ascending);
qbds.addSortField(fieldnum(VSSCustPackingSlipTransTmp, LineNum), SortOrder::Ascending);
// FASF - END - 09/02/2011
while (tradeLoopTrans.next())
{
custPackingSlipTrans = tradeLoopTrans.get(tablenum(VSSCustPackingSlipTransTmp));
printBodySeparator = false; // FASF - 27/12/2010
// compruebo si es la primera lÃnea
if (custChapter == 'first')
{
custChapter = CustPackingSlipTrans.CustChapter;
printHeaderCustChapter = true;
}
if (custChapter != custPackingSlipTrans.CustChapter)
{
printFootCustChapter = true;
element.executeSection(Section_FootCustChapter);
if (custChapter)
{
totalAmountCustChapter = amountCustChapter;
}
amountCustChapter = 0;
custChapter = custPackingSlipTrans.CustChapter;
printHeaderCustChapter = true;
}
this.send(custPackingSlipTrans);
if ((custFormletterDocument.DocuOnPackingSlip == DocuOnFormular::Line) ||
(custFormletterDocument.DocuOnPackingSlip == DocuOnFormular::All))
Docu::send(this, DocuRefSearch::newTypeIdAndRestriction(custPackingSlipTrans,
custFormletterDocument.DocuTypePackingSlip,
DocuRestriction::External));
markupLoopTrans = new TradeLoopTrans(custPackingSlipTrans.salesLine(), tablenum(MarkupTrans)).buildQueryRun();
while (markupLoopTrans.next())
{
markupTrans = markupLoopTrans.get(tablenum(MarkupTrans));
if (MarkupTable::find(ModuleInventCustVend::Cust, markupTrans.MarkupCode).ShowInInvoice &&
(markupTrans.PackingSlipId == custPackingSlipTrans.PackingSlipId ||
!markupTrans.PackingSlipId))
{
printMarkupTrans = true;
this.executeSection(BodyMarkupTrans);
}
// FASF - 16/02/2011 - Quitado, ahora este cálculo se hace antes para que salga en totales.
/* switch (MarkupTable::find(ModuleInventCustVend::Cust, markupTrans.MarkupCode).SundriesType)
{
case AQTSundriesType::Tax :
amountMarkupTax = markupTrans.CalculatedAmount;
break;
case AQTSundriesType::Freight :
amountMarkupTransport = markupTrans.CalculatedAmount;
break;
case AQTSundriesType::Others :
amountMarkupOthers = markupTrans.CalculatedAmount;
break;
}*/
}
// Fin imprimir gastos varios.
// FASF - 27/12/2010 - Imprimir la lÃnea de separación
printBodySeparator = true;
element.executeSection(BodySeparator);
}
// FASF - BEGIN
// imprimo el pie de capÃtulo
printFootCustChapter = true;
element.executeSection(Section_FootCustChapter);
if (custChapter)
{
totalAmountCustChapter = amountCustChapter;
}
amountCustChapter = 0;
// imprimo el total de los capÃtulos
if (custChapter)
{
printTotalCustChapter = true;
}
element.executeSection(Section_TotalCustChapter);
// iniciliazo valores de los capÃtulos
custChapter = 'first';
totalAmountCustChapter = 0;
// FASF - END
if (custFormletterParameters.ShippingDetailsOnPackingSlip && ! custFormletterParameters.ShowOnlyOneShippingLineOnPackingSlip)
{
while select salesShippingStat
where salesShippingStat.SalesId == custPackingSlipJour.SalesId &&
salesShippingStat.PackingSlipId == custPackingSlipJour.PackingSlipId &&
salesShippingStat.DeliveryDate == custPackingSlipJour.DeliveryDate
{
this.send(salesShippingStat);
}
}
// El pie de entrega se imprime junto con el de ejemplar para el cliente
printShipmentFooter = false; // true;
// Imprimir el pie de Observación y el ejemplar para el cliente/empresa de entrega
if (element.page() != 1)
{
// FASF - BEGIN - 28/12/2010
printFooterDisc = true; // FASF - 16/02/2011 - Ahora se pinta siempre. this.totalsPage(FirstLast::Last, true);
this.footerEnable(FooterDiscObserv, printFooterDisc);
printFooterTxt = false; // FASF - 16/02/2011 - Ahora no se pinta. this.totalsPage(FirstLast::First, true);
this.footerEnable(FooterText, printFooterTxt);
// FASF - END
printFooter = true;
}
else
{
// FASF - BEGIN - 28/12/2010
printFooterDisc = true;
this.footerEnable(FooterDiscObserv, printFooterDisc);
printFooterTxt = false;
this.footerEnable(FooterText, printFooterTxt);
// FASF - END
// printFooter = true;
}
if (custFormletterParameters.TransportationDocumentOnPackingSlip &&
this.transportationDocumentNotEmpty())
{
element.newPage();
element.execute(1);
}
element.printBackorders();
this.printDocumentHeader();
salesFormLetterReport.printFormLetterRemarks(custPackingSlipJour);
if (salesFormLetterReport.checkNextPrintSetting())
{
element.reset(true);
}
}
// All printing must be done in the context of the fetch() method and not
// in the print() method. This ensures printing errors are associated with the
// appropriate documents.
element.reset(true);
hasReportBeenPrinted = true;
// VSS 07/11/2017 X09 Restos de pedido de albarán
VSSCustPackingSlipTransTmp::clearTable(custPackingSlipJour);
//-VSS 07/11/2017 X09 Restos de pedido de albarán
// The journalList is used when printing is delayed until after all posting is complete.
if (!journalList.next(custPackingSlipJour))
{
break;
}
}
// If the report has been printed, return false to indicate the print method should not be run
return (!hasReportBeenPrinted);
}
I don't know where the data is accumulating.
Could you share your code that does the looping and printing?
Hi Sourav Dam,
I found out the problem (I think). When you generate more than one report at the same time (in a loop for example), the first one shows correctly, but the rest have about 1,26 MB extra. I try clean caches (by code) each time the report is generated, but doesn't work.
I used -->
SysFlushDictionary::doFlush();
SysEvent::fireEvent(SysEventType::FlushDictionary);
SysFlushAOD::doFlush();
SysEvent::fireEvent(SysEventType::FlushAOD);
SysFlushData::doFlush();
SysEvent::fireEvent(SysEventType::FlushData);
Any idea about how can I avoid junk data?
Hi Marta DÃaz Vila,
I was thinking about whether the technical team has set any option there so that you can change the format of this pdf.
However, it seems you need to re-check with your developer team and fix the alignment of the characters in this report. May be they set the character length based on certain % of area covered as per the size of the file which I feel, need to be set something like 'Auto fit' type in this report so that it should not overlapped.
How the report looks like on the screen? Have you tried by increasing the zoom? If yes; is it overlapping on the screen too?
Best regards,
Sourav Dam
Please take time to click 'Yes' against the answers that help you guide in right direction to help other community members.
Hi Sourav Dam,
Thanks for you replie.
The problem is that the generation of the PDF is a development made by some programmer, so the option of generate a excel it isn't available.
On the other hand I cannot find where is the change of the format (or if it is possible), I will keep looking. So I'm at the same point as at the beginning right now.
What I don't understand is why the fonts appear as embedded but are not shown. If the fonts did not fit in the file they would not be embedded right? Do you know something about this?
Thanks.
Hi Marta DÃaz Vila,
Have you checked if you generate the print copy directly in excel format (if possible to do in AX 2009), whether you are getting the same challenge like pdf or not?
Have you tried generating pdf in both portrait and landscape (if changing this option available) format and what is the output in both cases?
Best regards,
Sourav Dam
André Arnaud de Cal...
291,969
Super User 2025 Season 1
Martin Dráb
230,846
Most Valuable Professional
nmaenpaa
101,156