Trying to Generate new PDF with 25 columns not working

Hi all,
I have a requirement to generate a table in PDF for employee with 25 columns. For 14 columns is showing correctly but other columns are overlapped in the column 15.
Can anyone please suggest to fix this issue?
we are using aspose version : 21.7
Below is the code snipppet

 public Document generateEmployeeDetails() {
        

        try {

            com.aspose.pdf.Document rmmPdfDoc = new com.aspose.pdf.Document();
            rmmPdfDoc.setTitle("Employee Details");

            Page page = rmmPdfDoc.getPages().add();
            page.getPageInfo().setLandscape(true);
            MarginInfo pageMargin = new MarginInfo(30, 30, 30, 30);
            page.getPageInfo().setMargin(pageMargin);

            MarginInfo tableMargin = new MarginInfo(5f, 5f, 5f, 5f);

            Table table = new Table();
            page.getParagraphs().add(table);
            table.setColumnWidths("7%");
            table.setBorder(new BorderInfo(BorderSide.All, 0.1F, Color.getLightSalmon()));
            table.setDefaultCellBorder(new BorderInfo(BorderSide.All, 0.1F, Color.getLightSalmon()));
            table.setDefaultCellPadding(tableMargin);

            TextState headerTextStyle = new TextState();
            headerTextStyle.setFontStyle(FontStyles.Bold);
            headerTextStyle.setFontSize(11.0F);

            Row tableHeaderRow = table.getRows().add();
            tableHeaderRow.setBackgroundColor(Color.getLightGray());
            tableHeaderRow.getCells().add("Employee Id");
            tableHeaderRow.getCells().add("First name");
            tableHeaderRow.getCells().add("Last name");
            tableHeaderRow.getCells().add("Designation");
            tableHeaderRow.getCells().add("Skills");
            tableHeaderRow.getCells().add("Certificates");
            tableHeaderRow.getCells().add("Driving license");
            tableHeaderRow.getCells().add("Is Married");
            tableHeaderRow.getCells().add("Gender");
            tableHeaderRow.getCells().add("Address of the employee");
            tableHeaderRow.getCells().add("Temporary Address");
            tableHeaderRow.getCells().add("Permanent Address");
            tableHeaderRow.getCells().add("City");
            tableHeaderRow.getCells().add("State");
            tableHeaderRow.getCells().add("Country");
            tableHeaderRow.getCells().add("Mobile number");
            tableHeaderRow.getCells().add("Telephone number");
            tableHeaderRow.getCells().add("pin code");
            tableHeaderRow.getCells().add("years of experience");
            tableHeaderRow.getCells().add("previous company");
            tableHeaderRow.getCells().add("experience in previous company");
            tableHeaderRow.getCells().add("Manager name");
            tableHeaderRow.getCells().add("Technologies known");
            tableHeaderRow.getCells().add("Remarks");
            tableHeaderRow.getCells().add("Date of joining");

         
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            rmmPdfDoc.save(byteArrayOutputStream, SaveFormat.Pdf);

            System.out.print("--------------"+ Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray())+"--------------");
            return null;
        } catch (Exception e) {
            throw e;
        }

    }

@SravanDevarai,

This happened because the calculation for the width was wrong.

Check how many columns you have and how much % are you giving to each one. You are giving more than 100%.

If you fix that the issue will be solved.

@carlos.molina,
I have 30 columns giving widht of 7%.

@SravanDevarai,

That is the problem.

Check your math.

Thirty columns multiplied by 7% each = 210%.

You need to place everything within 100% of a page.

@carlos.molina,
If I try that way the pdf will look ugly when the labels are of length more than 30.
Is there any other way to solve the issue?
Can we split the table into 2 pages?

@SravanDevarai,

If you do not care about printing, change the page size, but give every column the correct width.

You cannot brake a table that way.

@carlos.molina Thanks for the information.

@carlos.molina Now I am trying to generate pdf with 31 columns in a table, its hanging at document.save(byteArrayOutputStream, SaveFormat.Pdf);.
We are using aspose version of 21.11.

@SravanDevarai,

Can you share your code, please?

@carlos.molina Please find the below code

private static final List HEADER_LABELS = List.of(“Risk ID”, “Hazard Type/Group”, “Hazard (potential source of harm)”, “FMEA ID/Other tool ID”,
“Device Category”, “Failure Mode (initial cause of hazard)”, “Causes/ mechanisms of failure/ sequence of events”, “End effect of failure”,
“Hazardous Situation”, “Probability§ of Occurrence”, “Severity(S)”, “Risk(PS)", “Inherit safety by design or manufacture”, “Requirements”,
“Protective Measures(PM)”, “PM Requirements”, “Information for safety (IFS)”, “IFS Requirements”, “SW Contribution”, “Reference”, “Harm”,
“Probability§ of Occurrence”, “Severity(S)”, "Residual Risk(P
S)”, “Benefit Risk Analysis”, “Risks Reduced as far as Possible?”,
“New risk introduced due to control measure?”, “New Risk ID”, “Risk Control Verification(Effectiveness Check)”, “Status of Risk Control Effectiveness”,
“Remarks”);

@SneakyThrows
@Override
public com.scubetech.rm.domain.Document generateRMMPDF(RmmPdfDTO rmmPdfDTO) {
    log.info("GenerateRMMPDF has started");
    File file = null;
    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
        com.scubetech.rm.domain.Document document = null;
        if (StringUtils.hasText(rmmPdfDTO.getDocumentId())) {
            document = dbPersistencePort.findById(rmmPdfDTO.getDocumentId());
        }
        String contentId = document != null ? document.getContentId() :  UUID.randomUUID().toString();

        Map<Integer, String> probabilityNameById = new HashMap<>();

        Map<Integer, String> severityNameById = new HashMap<>();

        Map<ValueRange, String> colorByRange = new HashMap<>();

        ObjectNode probabilityAndSeverityData = rmmPdfDTO.getViewProbSevOptsMatrix();

        if (probabilityAndSeverityData != null) {
            probabilityNameById = this.segregateProbabilityNameById((ArrayNode) probabilityAndSeverityData.get("probability"));
            severityNameById = this.segregateSeverityNameById((ArrayNode) probabilityAndSeverityData.get("severity"));
            colorByRange = this.segregateColorByRange((ArrayNode) probabilityAndSeverityData.get("matrix"));
        }

        com.aspose.pdf.Document rmmPdfDoc = new com.aspose.pdf.Document();
        rmmPdfDoc.setTitle("Risk Management Matrix");
        this.addFirstPage(rmmPdfDoc, "Risk Management Matrix", 1000.0, 1000.0);
        Page page = rmmPdfDoc.getPages().add();
        page.setPageSize(1000.0, 1000.0);
        page.getPageInfo().setLandscape(true);
        MarginInfo pageMargin = new MarginInfo(10, 90, 10, 70);
        page.getPageInfo().setMargin(pageMargin);

        MarginInfo tableMargin = new MarginInfo(3, 10, 3, 10);

        Table table = new Table();

        table.setColumnWidths("3.2%");
        table.setBorder(new BorderInfo(BorderSide.All, 0.1F, Color.getLightSalmon()));
        table.setDefaultCellBorder(new BorderInfo(BorderSide.All, 0.1F, Color.getLightSalmon()));
        table.setDefaultCellPadding(tableMargin);

        TextState headerTextStyle = new TextState();
        headerTextStyle.setFontStyle(FontStyles.Bold);
        headerTextStyle.setFontSize(11.0F);
        //Add labels for Heading in the table
        Row tableHeaderRow = table.getRows().add();
        tableHeaderRow.setBackgroundColor(Color.getLightGray());
        tableHeaderRow.setDefaultCellTextState(headerTextStyle);
        this.addCellsToRowOfTable(tableHeaderRow);

        int counter = 0;
       //Add data to the table
        for (RiskManagementMatrixDTO riskManagementMatrixDTO : rmmPdfDTO.getRmmList()) {
            if (counter >= 1) {
                break;
            }
            Row dataRow = table.getRows().add();
            dataRow.getCells().add(riskManagementMatrixDTO.getCustomId());
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getHazardType()) ? riskManagementMatrixDTO.getHazardType() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getHazard()) ? riskManagementMatrixDTO.getHazard() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getCustomRiskFmeaId()) ? riskManagementMatrixDTO.getCustomRiskFmeaId() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getDeviceCategory()) ? riskManagementMatrixDTO.getDeviceCategory() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getFailureMode()) ? riskManagementMatrixDTO.getFailureMode() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getCauses()) ? riskManagementMatrixDTO.getCauses() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getEndEffectOfFailure()) ? riskManagementMatrixDTO.getEndEffectOfFailure() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getHazardousSituation()) ? riskManagementMatrixDTO.getHazardousSituation() : "");
            ObjectNode beforeProbAndSevRiskData = riskManagementMatrixDTO.getViewBeforeProbSevRiskOptsMatrix();
            if (beforeProbAndSevRiskData != null) {
                int probabilityId = beforeProbAndSevRiskData.get("probability").asInt();
                int severityId = beforeProbAndSevRiskData.get("severity").asInt();
                int risk = probabilityId * severityId;
                dataRow.getCells().add(probabilityNameById.get(probabilityId) != null ? probabilityNameById.get(probabilityId) : "");
                dataRow.getCells().add(severityNameById.get(severityId) != null ? severityNameById.get(severityId) : "");
                Cell riskCell = dataRow.getCells().add(String.valueOf(risk));
                String colorName = this.getColorNameIfValueInRange(risk, colorByRange);
                if (StringUtils.hasText(colorName)) {
                    riskCell.setBackgroundColor(this.getColorByName(colorName));
                }
            } else {
                dataRow.getCells().add("-");
                dataRow.getCells().add("-");
                dataRow.getCells().add("-");
            }

            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getSafeByDesign()) ? riskManagementMatrixDTO.getSafeByDesign() : "");
            if (riskManagementMatrixDTO.getRequirementsDetails() != null && !riskManagementMatrixDTO.getRequirementsDetails().isEmpty()) {
                dataRow.getCells().add(riskManagementMatrixDTO.getRequirementsDetails().stream().map(RequirementShortDTO::getCustomId).collect(Collectors.joining(",")));
            } else {
                dataRow.getCells().add("-");
            }
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getProtectiveMeasure()) ? riskManagementMatrixDTO.getProtectiveMeasure() : "");
            if (riskManagementMatrixDTO.getPmRequirementsDetails() != null && !riskManagementMatrixDTO.getPmRequirementsDetails().isEmpty()) {
                dataRow.getCells().add(riskManagementMatrixDTO.getPmRequirementsDetails().stream().map(RequirementShortDTO::getCustomId).collect(Collectors.joining(",")));
            } else {
                dataRow.getCells().add("-");
            }
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getInformationForSafety()) ? riskManagementMatrixDTO.getInformationForSafety() : "");

            if (riskManagementMatrixDTO.getIfsRequirementsDetails() != null && !riskManagementMatrixDTO.getIfsRequirementsDetails().isEmpty()) {
                dataRow.getCells().add(riskManagementMatrixDTO.getIfsRequirementsDetails().stream().map(RequirementShortDTO::getCustomId).collect(Collectors.joining(",")));
            } else {
                dataRow.getCells().add("-");
            }
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getSwContribution()) ? riskManagementMatrixDTO.getSwContribution() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getReference()) ? riskManagementMatrixDTO.getReference() : "");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getHarm()) ? riskManagementMatrixDTO.getHarm() : "");
            ObjectNode afterProbAndSevRiskData = riskManagementMatrixDTO.getViewAfterProbSevRiskOptsMatrix();
            if (afterProbAndSevRiskData != null) {
                int probabilityId = afterProbAndSevRiskData.get("probability").asInt();
                int severityId = afterProbAndSevRiskData.get("severity").asInt();
                int risk = probabilityId * severityId;
                dataRow.getCells().add(probabilityNameById.get(probabilityId) != null ? probabilityNameById.get(probabilityId) : "");
                dataRow.getCells().add(severityNameById.get(severityId) != null ? severityNameById.get(severityId) : "");
                Cell riskCell = dataRow.getCells().add(String.valueOf(risk));
                String colorName = this.getColorNameIfValueInRange(risk, colorByRange);
                if (StringUtils.hasText(colorName)) {
                    riskCell.setBackgroundColor(this.getColorByName(colorName));
                }
            } else {
                dataRow.getCells().add("-");
                dataRow.getCells().add("-");
                dataRow.getCells().add("-");
            }

            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getLocalRiskBenefitAnalysis()) ? riskManagementMatrixDTO.getLocalRiskBenefitAnalysis() :"");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getNewRiskReduced()) ? riskManagementMatrixDTO.getNewRiskReduced() :"");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getNewRiskIntroduced()) ? riskManagementMatrixDTO.getNewRiskIntroduced() :"");
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getNewRiskId()) ? riskManagementMatrixDTO.getNewRiskId() :"");
            if (riskManagementMatrixDTO.getRiskControlEffectivenessDetails() != null &&
                    !riskManagementMatrixDTO.getRiskControlEffectivenessDetails().isEmpty()) {
                //Adds data for columns Risk Control Verification(Effectiveness Check),Status of Risk Control Effectiveness
                this.addRiskControlVerificationAndStatusToCellOfRow(dataRow, riskManagementMatrixDTO.getRiskControlEffectivenessDetails());
            } else {
                dataRow.getCells().add("-");
                dataRow.getCells().add("-");
            }
            dataRow.getCells().add(StringUtils.hasText(riskManagementMatrixDTO.getRemarks()) ? riskManagementMatrixDTO.getRemarks() : "");
            counter++;
        }

        page.getParagraphs().add(table);
        rmmPdfDoc.save(byteArrayOutputStream, SaveFormat.Pdf);
       // System.out.print("--------------"+ Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray())+"--------------");

        //Create a file using byte[] last downloaded, file name is value of contentId
        file = new File("/tmp/" + contentId);
        FileUtils.writeByteArrayToFile(file, byteArrayOutputStream.toByteArray());
        Tika tika = new Tika();
        String mimeType = tika.detect(file);
        //Store file in Azure

        if (document != null) {
            blobStoragePersistencePort.deleteFile(TenantContext.getCurrentTenant().toLowerCase(), contentId);
        }
        blobStoragePersistencePort.upload(TenantContext.getCurrentTenant().toLowerCase(), contentId, file);
        String checksum = getFileChecksum(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));

        if (document == null) {
            document = com.scubetech.rm.domain.Document.builder()
                    .documentId(UUID.randomUUID().toString())
                    .contentId(contentId)
                    .contentLength(file.length())
                    .fileName("Risk Management Matrix".concat(".pdf"))
                    .mimeType(mimeType)
                    .tenantId(TenantContext.getCurrentTenant())
                    .objectId(rmmPdfDTO.getProjectId())
                    .objectType(Constants.RMM)
                    .fileChecksum(checksum)
                    .creAt(Instant.now())
                    .creBy(TenantContext.getCurrentUser())
                    .build();

            document.getVersions().add(this.getVersion(document, document.getFileVersion()));
            document = dbPersistencePort.save(document);
        }

        return document;
    } catch (Exception e) {
        log.error(String.format("Exception in generateRMMPDF - %s", e.getMessage()),e);
        throw e;
    } finally {
        if (file != null) {
            file.delete();
        }
    }

}

private void addRiskControlVerificationAndStatusToCellOfRow(Row row, List<TestcaseExecutionPlanShortDTO> riskControlEffectivenessDetailsList) {
    List<String> riskControlVerifications = new ArrayList<>();
    List<String> riskControlStatus = new ArrayList<>();
    for (TestcaseExecutionPlanShortDTO riskControlEffectivenesDetails : riskControlEffectivenessDetailsList) {
        riskControlVerifications.add(riskControlEffectivenesDetails.getCustomTestcaseExecutionPlanId().concat("-").concat(riskControlEffectivenesDetails.getTitle()));
        riskControlStatus.add(riskControlEffectivenesDetails.getTestExecutionStatus().concat("-").concat(riskControlEffectivenesDetails.getCustomTestcaseExecutionPlanId()));
    }
    row.getCells().add(String.join(",", riskControlVerifications));
    row.getCells().add(String.join(",", riskControlStatus));

}
private void addCellsToRowOfTable(Row tableHeaderRow) {
    for (String headerLabel : RMMServicePortImpl.HEADER_LABELS) {
        tableHeaderRow.getCells().add(headerLabel);
    }
}

private String getColorNameIfValueInRange(int value, Map<ValueRange, String> colorNameByRange) {
    if (colorNameByRange != null && !colorNameByRange.isEmpty()) {
        for (ValueRange valueRange : colorNameByRange.keySet()) {
            if (valueRange.isValidValue(value)) {
                return colorNameByRange.get(valueRange);
            }
        }
    }
    return null;
}
private Map<Integer, String> segregateProbabilityNameById(ArrayNode probabilityNameAndId) {
    Map<Integer, String> probabilityNameById = new HashMap<>();
    for (JsonNode matrix :probabilityNameAndId) {
        probabilityNameById.put(matrix.get("value").asInt(), matrix.get("name").asText());

    }
    return probabilityNameById;
}

private Map<Integer, String> segregateSeverityNameById(ArrayNode severityNameAndId) {
    Map<Integer, String> severityNameById = new HashMap<>();
    for (JsonNode matrix :severityNameAndId) {
        severityNameById.put(matrix.get("value").asInt(), matrix.get("name").asText());
    }
    return severityNameById;
}

private Map<ValueRange, String> segregateColorByRange(ArrayNode colorRangeMatrix) {
    Map<ValueRange, String> colorNameByRange = new HashMap<>();

    if (colorRangeMatrix != null) {
        for (JsonNode matrix : colorRangeMatrix) {
            JsonNode range = matrix.get("range");
            ValueRange rangeData = ValueRange.of(range.get("min").asInt(), range.get("max").asInt());
            String color = matrix.get("colour").asText();
            colorNameByRange.put(rangeData, color);
        }
    }
    return colorNameByRange;
}

private Color getColorByName(String colorName) {
    if (colorName.equalsIgnoreCase("green")) {
        return Color.fromArgb(123, 185, 81);
    } else if (colorName.equalsIgnoreCase("blue")) {
        return Color.fromArgb(84, 131, 215);
    } else if (colorName.equalsIgnoreCase("red")) {
        return Color.fromArgb(255, 48, 48);
    } else if (colorName.equalsIgnoreCase("amber")) {
        return Color.fromArgb(255, 191, 0);
    }
    return null;
}

private static String getFileChecksum(InputStream inputStream) throws Exception {
    //Use MD5 algorithm
    MessageDigest md5Digest = MessageDigest.getInstance("MD5");

    //Get file input stream for reading the file content
    BufferedInputStream fis = new BufferedInputStream(inputStream);

    //Create byte array to read data in chunks
    byte[] byteArray = new byte[1024];
    int bytesCount;

    //Read file data and update in message digest
    while ((bytesCount = fis.read(byteArray)) != -1) {
        md5Digest.update(byteArray, 0, bytesCount);
    }

    //close the stream; We don't need it now.
    fis.close();

    //Get the hash's bytes
    byte[] bytes = md5Digest.digest();

    //This bytes[] has bytes in decimal format;
    //Convert it to hexadecimal format
    StringBuilder sb = new StringBuilder();
    for (byte aByte : bytes) {
        sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
    }
    //return complete hash
    return sb.toString();
}

//Prepare document version detail to store in db
private Version getVersion(com.scubetech.rm.domain.Document document, Double newFileVersion) {

    if (newFileVersion != null) {
        return Version.builder()
                .contentId(document.getContentId())
                .contentLength(document.getContentLength())
                .fileVersion(newFileVersion)
                .customFileVersion(document.getCustomFileVersion())
                .status(Status.valueOf(document.getStatus()))
                .build();
    } else {
        return Version.builder()
                .contentId(document.getContentId())
                .contentLength(document.getContentLength())
                .fileVersion(document.getFileVersion())
                .customFileVersion(document.getCustomFileVersion())
                .status(Status.valueOf(document.getStatus()))
                .build();
    }
}

com.aspose.pdf.Document addFirstPage(com.aspose.pdf.Document pdfDocument, String tenantName, Double width, Double height) {

    Page firstPage = pdfDocument.getPages().insert(1);
    if (width != 0 && height != 0) {
        firstPage.setPageSize(width, height);
    }
    TextStamp textStamp = new TextStamp(tenantName);
    textStamp.setHorizontalAlignment(HorizontalAlignment.Center);
    textStamp.setVerticalAlignment(VerticalAlignment.Center);
    textStamp.setTextAlignment(TextAlignment.Center);
    textStamp.getTextState().setFontSize(20);
    firstPage.addStamp(textStamp);
    return pdfDocument;
}

@SravanDevarai,

I cannot debug your whole code. That is not the purpose of the forum. Tell me what part of the code is failing, please.

Also, try using the latest version. You have an API that is more than three years old. You can request a temporary license here: https://helpdesk.aspose.com

@carlos.molina It’s hanging at the below statement
rmmPdfDoc.save(byteArrayOutputStream, SaveFormat.Pdf);

@SravanDevarai,

Can you run this code using the latest version of the API to see if the problem is solved there?

Also, Can you do a miniminzed version of your code where you removed everything that is no Aspose? You are using using libraries or classes I do not have so I cannot even run your code to try to replicate the issue.

Just create a simple method with no external references where youi create the pdf with all the columns you needs. See if that fails. If it does share that code snipped with me so I can investigate further. But please dont add extra references as we support only Aspose.Pdf API.

@carlos.molina Thanks.

@SravanDevarai,

No problem. Let me know when you have that so I can continue helping you.