Pull request #94: RED-2414 rrs2

Merge in RED/redaction-report-service from RED-2414-rrs2 to master

* commit '599a099d357b15ae05f8557af9f72713dea27fbd':
  RED-2414 Wrong scaling for Images in Reports
  RED-2414 Wrong scaling for Images in Reports - not fixed excel part
This commit is contained in:
Ali Oezyetimoglu 2021-11-08 14:46:47 +01:00 committed by Dominique Eiflaender
commit 6980e1e342
9 changed files with 133 additions and 41 deletions

View File

@ -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<String, String> fileAttributePlaceholders,
Map<String, String> dossierAttributesPlaceholders) {
@ -303,7 +354,6 @@ public class ExcelTemplateReportGenerationService {
throw new RuntimeException("unknown placeholder");
}
@SneakyThrows
public byte[] toByteArray(XSSFWorkbook workbook) {

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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<ReportRedactionEntry> 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<ReportRedactionEntry> 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<LegalBasis> 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);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB