diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelTemplateReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelTemplateReportGenerationService.java index 7b28342..5a603cd 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelTemplateReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/ExcelTemplateReportGenerationService.java @@ -1,5 +1,48 @@ package com.iqser.red.service.redaction.report.v1.server.service; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.DOSSIER_NAME_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.EXCERPT_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FILE_NAME_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_ENG; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_ENG_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_GER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_GER_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_ISO; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_DATE_ISO_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_TIME_ISO; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.FORMAT_TIME_ISO_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.JUSTIFICATION_PARAGRAPH_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.JUSTIFICATION_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.JUSTIFICATION_REASON_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.PAGE_PLACEHOLDER; +import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.PARAGRAPH_PLACEHOLDER; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + +import javax.imageio.ImageIO; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Picture; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Service; + import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.DossierAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierAttribute; @@ -10,22 +53,10 @@ import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributes import com.iqser.red.service.redaction.report.v1.server.client.FileAttributesConfigClient; import com.iqser.red.service.redaction.report.v1.server.model.ImagePlaceholder; import com.iqser.red.service.redaction.report.v1.server.model.ReportRedactionEntry; + import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.springframework.stereotype.Service; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.time.OffsetDateTime; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Pattern; - -import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.*; @Slf4j @Service @@ -232,30 +263,30 @@ public class ExcelTemplateReportGenerationService { for (Cell cell : row) { if (cell.getStringCellValue().contains(imagePlaceholder.getPlaceholder())) { try (ByteArrayInputStream is = new ByteArrayInputStream(imagePlaceholder.getImage())) { + +// ByteArrayInputStream scaledImage = getScaledImage(is, PixelUtil.widthUnits2Pixel((short) sheet.getColumnWidth(cell.getColumnIndex())), PixelUtil.heightUnits2Pixel(cell.getRow().getHeight())); +// is.reset(); + + double factor = calculateScale(is, PixelUtil.widthUnits2Pixel((short) sheet.getColumnWidth(cell.getColumnIndex())), PixelUtil.heightUnits2Pixel(cell.getRow().getHeight())); + is.reset(); + int pictureIdx = workbook.addPicture(is, XSSFWorkbook.PICTURE_TYPE_JPEG); + is.reset(); + //Returns an object that handles instantiating concrete classes CreationHelper helper = workbook.getCreationHelper(); - //Creates the top-level drawing patriarch. - Drawing drawing = sheet.createDrawingPatriarch(); //Create an anchor that is attached to the worksheet ClientAnchor anchor = helper.createClientAnchor(); + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); anchor.setCol1(cell.getColumnIndex()); anchor.setRow1(cell.getRowIndex()); - anchor.setCol2(cell.getColumnIndex() + 1); - anchor.setRow2(cell.getRowIndex() + 1); - drawing.createPicture(anchor, pictureIdx); + //Creates the top-level drawing patriarch. + Drawing drawing = sheet.createDrawingPatriarch(); - //set width to n character widths = count characters * 256 - int widthUnits = 6 * 5 * 256; - sheet.setColumnWidth(cell.getColumnIndex(), widthUnits); - - //set height to n points in twips = n * 20 - short heightUnits = 6 * 20; - cell.getRow().setHeightInPoints(heightUnits); - -// pict.resize(); + Picture picture = drawing.createPicture(anchor, pictureIdx); + picture.resize(factor); cell.setCellValue(""); } @@ -265,6 +296,26 @@ public class ExcelTemplateReportGenerationService { } + private double calculateScale(ByteArrayInputStream imageByteArrayInputStream, float cellWidth, float cellHeight) throws IOException { + BufferedImage img = ImageIO.read(imageByteArrayInputStream); + + double imageWidth = img.getWidth(); + double imageHeight = img.getHeight(); + + double widthFactor = (double) cellWidth/ imageWidth; + double heightFactor = (double) cellHeight/ imageHeight; + + if (imageWidth < cellWidth && imageHeight < cellHeight) { + return 1; + } else if (cellWidth > cellHeight) { + return heightFactor; + } else { + return widthFactor; + } + + } + + private String getPlaceholderValue(String placeholder, Dossier project, FileModel fileStatus, Map fileAttributePlaceholders, Map dossierAttributesPlaceholders) { @@ -303,7 +354,6 @@ public class ExcelTemplateReportGenerationService { throw new RuntimeException("unknown placeholder"); } - @SneakyThrows public byte[] toByteArray(XSSFWorkbook workbook) { diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PixelUtil.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PixelUtil.java new file mode 100644 index 0000000..538b471 --- /dev/null +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/PixelUtil.java @@ -0,0 +1,29 @@ +package com.iqser.red.service.redaction.report.v1.server.service; + +public class PixelUtil { + + public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256; + public static final short EXCEL_ROW_HEIGHT_FACTOR = 20; + public static final int UNIT_OFFSET_LENGTH = 7; + public static final int[] UNIT_OFFSET_MAP = new int[] { 0, 36, 73, 109, 146, 182, 219 }; + + public static short pixel2WidthUnits(int pxs) { + short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR * (pxs / UNIT_OFFSET_LENGTH)); + widthUnits += UNIT_OFFSET_MAP[pxs % UNIT_OFFSET_LENGTH]; + return widthUnits; + } + + public static int widthUnits2Pixel(short widthUnits) { + int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR) * UNIT_OFFSET_LENGTH; + int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR; + pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH)); + return pixels; + } + + public static int heightUnits2Pixel(short heightUnits) { + int pixels = heightUnits / EXCEL_ROW_HEIGHT_FACTOR; + int offsetWidthUnits = heightUnits % EXCEL_ROW_HEIGHT_FACTOR; + pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_ROW_HEIGHT_FACTOR / UNIT_OFFSET_LENGTH)); + return pixels; + } +} \ No newline at end of file diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java index ad87f42..9875fa7 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/main/java/com/iqser/red/service/redaction/report/v1/server/service/WordReportGenerationService.java @@ -18,10 +18,12 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Units; import org.apache.poi.xwpf.usermodel.*; import org.springframework.stereotype.Service; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -31,6 +33,8 @@ import java.util.regex.Pattern; import static com.iqser.red.service.redaction.report.v1.server.service.PlaceholderService.*; +import javax.imageio.ImageIO; + @Service @RequiredArgsConstructor public class WordReportGenerationService { @@ -196,7 +200,8 @@ public class WordReportGenerationService { XWPFRun run = p.getRuns().get(0); run.setText("", 0); run.addBreak(); - run.addPicture(is2, XWPFDocument.PICTURE_TYPE_JPEG, "image.jpg", Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels + Dimension2DDouble dim = getImageDimension(is2); + run.addPicture(is2, XWPFDocument.PICTURE_TYPE_JPEG, "image.jpg", Units.toEMU(dim.getWidth()), Units.toEMU(dim.getHeight())); int size = p.getRuns().size(); for (int i = 1; i < size; i++) { p.removeRun(1); @@ -328,6 +333,17 @@ public class WordReportGenerationService { } + private Dimension2DDouble getImageDimension(ByteArrayInputStream bais) throws IOException { + BufferedImage bufImg = ImageIO.read(bais); + bais.reset(); + + double width = bufImg.getWidth(); + double height = bufImg.getHeight(); + + return new Dimension2DDouble(width, height); + } + + private void setText(XWPFTableCell cell, String value) { cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java index 1797807..05e41a5 100644 --- a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java +++ b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/java/com/iqser/red/service/redaction/report/v1/server/RedactionReportIntegrationTest.java @@ -12,7 +12,6 @@ import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.List; -import java.util.ListIterator; import java.util.Map; import org.apache.commons.io.IOUtils; @@ -34,12 +33,10 @@ import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.Re import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierAttribute; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.DossierAttributeType; -import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileAttribute; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileAttributeType; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.legalbasis.LegalBasis; -import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.legalbasis.LegalBasisMapping; import com.iqser.red.service.redaction.report.v1.api.model.ReportType; import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesClient; import com.iqser.red.service.redaction.report.v1.server.client.DossierAttributesConfigClient; @@ -129,7 +126,7 @@ public class RedactionReportIntegrationTest { .label("label2") .editable(true) .type(DossierAttributeType.IMAGE) - .placeholder("{{dossier.attribute.image}}") + .placeholder("{{dossier.attribute.Signature}}") .build(); @@ -209,7 +206,7 @@ public class RedactionReportIntegrationTest { String templateId = "templateId"; String dossierId = "dossierId"; - ClassPathResource templateResource = new ClassPathResource("templates/Excel Report.xlsx"); + ClassPathResource templateResource = new ClassPathResource("templates/TestReport.xlsx"); XSSFWorkbook workbook = new XSSFWorkbook(templateResource.getInputStream()); ClassPathResource legalBasisMappingResource = new ClassPathResource("files/legalBasisMapping.json"); @@ -219,7 +216,7 @@ public class RedactionReportIntegrationTest { List reportEntries2 = redactionLogConverterService.convertAndSort(redactionLog2, legalBasisMapping); DossierAttributeConfig dossierAttributeConfig = new DossierAttributeConfig("id", "label", true, "{{dossier.attribute.name}}", DossierAttributeType.TEXT, dossierTemplateId);// - DossierAttributeConfig dossierAttributeConfig2 = new DossierAttributeConfig("id2", "label2", false, "{{dossier.attribute.image}}", DossierAttributeType.IMAGE, dossierTemplateId); + DossierAttributeConfig dossierAttributeConfig2 = new DossierAttributeConfig("id2", "label2", false, "{{dossier.attribute.Signature}}", DossierAttributeType.IMAGE, dossierTemplateId); when(dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId)).thenReturn(List.of(dossierAttributeConfig, dossierAttributeConfig2)); DossierAttribute dossierAttribute = new DossierAttribute(dossierId, dossierAttributeConfig.getId(), "Michael"); @@ -245,7 +242,7 @@ public class RedactionReportIntegrationTest { excelTemplateReportGenerationService.generateReport(reportEntries2, "dossierTemplateId", workbook, fileModel2, dossier, true); byte[] excelTemplateReport = excelTemplateReportGenerationService.toByteArray(workbook); - try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/report_excel_template.xlsx")) { + try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/test_report_excel_template.xlsx")) { fileOutputStream.write(excelTemplateReport); } } @@ -272,7 +269,7 @@ public class RedactionReportIntegrationTest { List reportEntries2 = redactionLogConverterService.convertAndSort(redactionLog2, legalBasisMapping); DossierAttributeConfig dossierAttributeConfig = new DossierAttributeConfig("id", "label", true, "{{dossier.attribute.name}}", DossierAttributeType.TEXT, dossierTemplateId); - DossierAttributeConfig dossierAttributeConfig2 = new DossierAttributeConfig("id2", "label2", false, "{{dossier.attribute.image}}", DossierAttributeType.IMAGE, dossierTemplateId); + DossierAttributeConfig dossierAttributeConfig2 = new DossierAttributeConfig("id2", "label2", false, "{{dossier.attribute.Signature}}", DossierAttributeType.IMAGE, dossierTemplateId); when(dossierAttributesConfigClient.getDossierAttributes(dossierTemplateId)).thenReturn(List.of(dossierAttributeConfig, dossierAttributeConfig2)); DossierAttribute dossierAttribute = new DossierAttribute(dossierId, "id", "Michael"); DossierAttribute dossierAttribute2 = new DossierAttribute(dossierId, "id2", Base64.getEncoder().encodeToString(IOUtils.toByteArray(imageResource.getInputStream()))); @@ -412,11 +409,11 @@ public class RedactionReportIntegrationTest { public void testIuclidReport() { String dossierTemplateId = "dossierTemplateId"; - ClassPathResource redactionLogResource = new ClassPathResource("files/redactionLog.json"); + ClassPathResource redactionLogResource = new ClassPathResource("files/S11RedactionLog.json"); RedactionLog redactionLog = objectMapper.readValue(redactionLogResource.getInputStream(), RedactionLog.class); - ClassPathResource legalBasisMappingResource = new ClassPathResource("files/legalBasisMapping.json"); + ClassPathResource legalBasisMappingResource = new ClassPathResource("files/S1116LegalBasis.json"); List legalBasisMapping = objectMapper.readValue(legalBasisMappingResource.getInputStream(), new TypeReference<>() { }); @@ -433,7 +430,7 @@ public class RedactionReportIntegrationTest { when(fileAttributesConfigClient.getFileAttributeConfigs(dossierTemplateId)).thenReturn(new ArrayList<>()); - FileModel fileStatus = FileModel.builder().filename("filename").build(); + FileModel fileStatus = FileModel.builder().filename("VV123456").build(); Dossier project = Dossier.builder().id("dossierId").dossierName("projectName").build(); @@ -455,7 +452,7 @@ public class RedactionReportIntegrationTest { .build(); byte[] report = wordReportGenerationService.generateReport(ReportType.WORD_SINGLE_FILE, reportEntries, dossierTemplateId, reportTemplate, fileStatus, project); - try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/iuclid_report.docx")) { + try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/iuclid_report_2.docx")) { fileOutputStream.write(report); } } diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage2.jpeg b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage2.jpeg new file mode 100644 index 0000000..e08bec8 Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage2.jpeg differ diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage3.jpeg b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage3.jpeg new file mode 100644 index 0000000..2c5ce48 Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage3.jpeg differ diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage4.jpeg b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage4.jpeg new file mode 100644 index 0000000..6573f5a Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/files/exampleImage4.jpeg differ diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport.xlsx b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport.xlsx new file mode 100644 index 0000000..09e80a4 Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport.xlsx differ diff --git a/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport2.xlsx b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport2.xlsx new file mode 100644 index 0000000..88dfc40 Binary files /dev/null and b/redaction-report-service-v1/redaction-report-service-server-v1/src/test/resources/templates/TestReport2.xlsx differ