From 59f90ba782f3fe2f0be5edcc6bb173d2dbb1f3d5 Mon Sep 17 00:00:00 2001 From: dota17 Date: Fri, 27 Mar 2020 17:55:03 +0800 Subject: [PATCH] Add new feature: use annotation to set image position --- .../annotation/write/style/ImagePosition.java | 61 ++++++++ .../BoxingByteArrayImageConverter.java | 10 +- .../bytearray/ByteArrayImageConverter.java | 14 +- .../converters/file/FileImageConverter.java | 10 +- .../InputStreamImageConverter.java | 10 +- .../string/StringImageConverter.java | 10 +- .../com/alibaba/excel/metadata/CellData.java | 45 +++++- .../property/ImagePositionProperty.java | 132 ++++++++++++++++++ .../executor/AbstractExcelWriteExecutor.java | 30 ++-- .../demo/write/ImageDataWithAnnotation.java | 42 ++++++ .../easyexcel/test/demo/write/WriteTest.java | 35 ++++- 11 files changed, 379 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/ImagePosition.java create mode 100644 src/main/java/com/alibaba/excel/metadata/property/ImagePositionProperty.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/write/ImageDataWithAnnotation.java diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ImagePosition.java b/src/main/java/com/alibaba/excel/annotation/write/style/ImagePosition.java new file mode 100644 index 00000000..8a401122 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ImagePosition.java @@ -0,0 +1,61 @@ +package com.alibaba.excel.annotation.write.style; + + +import org.apache.poi.ss.usermodel.ClientAnchor; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Retention; + +/** + * This annotation is used to set the position of a picture. + * See {@link ClientAnchor} + */ + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ImagePosition { + + /** + * The x coordinate within the first cell. + */ + int dx1(); + + /** + * The y coordinate within the first cell. + */ + int dy1(); + + /** + * The x coordinate within the second cell. + */ + int dx2(); + + /** + * The y coordinate within the second cell + */ + int dy2(); + + /** + * 0-based column of the first cell. + */ + short col1(); + + /** + * 0-based row of the first cell. + */ + int row1(); + + /** + * 0-based column of the second cell. + */ + short col2(); + + /** + * 0-based row of the second cell. + */ + int row2(); +} diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java index c083601b..2840df73 100644 --- a/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java @@ -1,5 +1,8 @@ package com.alibaba.excel.converters.bytearray; +import java.lang.annotation.Annotation; + +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -35,7 +38,12 @@ public class BoxingByteArrayImageConverter implements Converter { for (int i = 0; i < value.length; i++) { byteValue[i] = value[i]; } - return new CellData(byteValue); + ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); + if (imagePosition != null) { + return new CellData(byteValue, imagePosition); + } else { + return new CellData(byteValue); + } } } diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java index 991999d1..b186c374 100644 --- a/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java @@ -1,5 +1,8 @@ package com.alibaba.excel.converters.bytearray; +import java.lang.annotation.Annotation; + +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -24,14 +27,19 @@ public class ByteArrayImageConverter implements Converter { @Override public byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { + GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to byte arrays"); } @Override public CellData convertToExcelData(byte[] value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(value); + GlobalConfiguration globalConfiguration) { + ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); + if (imagePosition != null) { + return new CellData(value, imagePosition); + } else { + return new CellData(value); + } } } diff --git a/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java index 10522154..2e974378 100644 --- a/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java @@ -2,7 +2,7 @@ package com.alibaba.excel.converters.file; import java.io.File; import java.io.IOException; - +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -35,7 +35,11 @@ public class FileImageConverter implements Converter { @Override public CellData convertToExcelData(File value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { - return new CellData(FileUtils.readFileToByteArray(value)); + ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); + if (imagePosition != null) { + return new CellData(FileUtils.readFileToByteArray(value), imagePosition); + } else { + return new CellData(FileUtils.readFileToByteArray(value)); + } } - } diff --git a/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java index abc2fe68..1e752a54 100644 --- a/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java @@ -2,12 +2,15 @@ package com.alibaba.excel.converters.inputstream; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Annotation; +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.IoUtils; /** @@ -35,7 +38,12 @@ public class InputStreamImageConverter implements Converter { @Override public CellData convertToExcelData(InputStream value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { - return new CellData(IoUtils.toByteArray(value)); + ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); + if (imagePosition != null) { + return new CellData(IoUtils.toByteArray(value), imagePosition); + } else { + return new CellData(IoUtils.toByteArray(value)); + } } } diff --git a/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java index 931d4fa9..c15d9a0e 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java @@ -2,13 +2,16 @@ package com.alibaba.excel.converters.string; import java.io.File; import java.io.IOException; +import java.lang.annotation.Annotation; +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.IoUtils; /** * String and image converter @@ -35,7 +38,12 @@ public class StringImageConverter implements Converter { @Override public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { - return new CellData(FileUtils.readFileToByteArray(new File(value))); + ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); + if (imagePosition != null) { + return new CellData(FileUtils.readFileToByteArray(new File(value)), imagePosition); + } else { + return new CellData(FileUtils.readFileToByteArray(new File(value))); + } } } diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java index 2124e103..cdce6ad2 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellData.java +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -1,8 +1,9 @@ package com.alibaba.excel.metadata; import java.math.BigDecimal; - +import com.alibaba.excel.annotation.write.style.ImagePosition; import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.property.ImagePositionProperty; import com.alibaba.excel.util.StringUtils; /** @@ -29,6 +30,16 @@ public class CellData extends AbstractCell { private Boolean formula; private String formulaValue; private byte[] imageValue; + + /** + * Keep the information of image position in annotation. + */ + private ImagePositionProperty imagePositionProperty; + + /** + * It will be set true when using annotation to set the image's position. + */ + private Boolean useImagePositionProperty = false; /** * The number formatting.Currently only supported when reading */ @@ -50,6 +61,8 @@ public class CellData extends AbstractCell { this.formula = other.formula; this.formulaValue = other.formulaValue; this.imageValue = other.imageValue; + this.imagePositionProperty = other.imagePositionProperty; + this.useImagePositionProperty = other.useImagePositionProperty; this.dataFormat = other.dataFormat; this.dataFormatString = other.dataFormatString; this.data = other.data; @@ -101,6 +114,20 @@ public class CellData extends AbstractCell { this.formula = Boolean.FALSE; } + public CellData(byte[] imageValue, ImagePosition imagePosition) { + if (imageValue == null) { + throw new IllegalArgumentException("ImageValue can not be null"); + } + if (imagePosition == null) { + throw new IllegalArgumentException("ImagePosition can not be null"); + } + this.type = CellDataTypeEnum.IMAGE; + this.imageValue = imageValue; + this.imagePositionProperty = ImagePositionProperty.build(imagePosition); + this.useImagePositionProperty = true; + this.formula = Boolean.FALSE; + } + public CellData(Boolean booleanValue) { if (booleanValue == null) { throw new IllegalArgumentException("BooleanValue can not be null"); @@ -174,6 +201,22 @@ public class CellData extends AbstractCell { this.imageValue = imageValue; } + public ImagePositionProperty getImagePositionProperty() { + return imagePositionProperty; + } + + public void setImagePositionProperty(ImagePositionProperty imagePositionProperty) { + this.imagePositionProperty = imagePositionProperty; + } + + public Boolean getUseImagePositionProperty() { + return useImagePositionProperty; + } + + public void setUseImagePositionProperty(Boolean useImagePositionProperty) { + this.useImagePositionProperty = useImagePositionProperty; + } + public Integer getDataFormat() { return dataFormat; } diff --git a/src/main/java/com/alibaba/excel/metadata/property/ImagePositionProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ImagePositionProperty.java new file mode 100644 index 00000000..b5eff3af --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/ImagePositionProperty.java @@ -0,0 +1,132 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.write.style.ImagePosition; + +/** + * Keep the information of image position from an annotation. + */ +public class ImagePositionProperty { + + /** + * The x coordinate within the first cell. + */ + private int dx1; + + /** + * The y coordinate within the first cell. + */ + private int dy1; + + /** + * The x coordinate within the second cell. + */ + private int dx2; + + /** + * The y coordinate within the second cell + */ + private int dy2; + + /** + * 0-based column of the first cell. + */ + private short col1; + + /** + * 0-based row of the first cell. + */ + private int row1; + + /** + * 0-based column of the second cell. + */ + private short col2; + + /** + * 0-based row of the second cell. + */ + private int row2; + + public static ImagePositionProperty build(ImagePosition imagePosition) { + if (imagePosition == null) { + return null; + } + return new ImagePositionProperty(imagePosition.dx1(), imagePosition.dy1(), imagePosition.dx2(), + imagePosition.dy2(), imagePosition.col1(), imagePosition.row1(), imagePosition.col2(), imagePosition.row2()); + } + + public ImagePositionProperty(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2) { + this.dx1 = dx1; + this.dy1 = dy1; + this.dx2 = dx2; + this.dy2 = dy2; + this.col1 = col1; + this.row1 = row1; + this.col2 = col2; + this.row2 = row2; + } + + public int getDx1() { + return dx1; + } + + public void setDx1(int dx1) { + this.dx1 = dx1; + } + + public int getDy1() { + return dy1; + } + + public void setDy1(int dy1) { + this.dy1 = dy1; + } + + public int getDx2() { + return dx2; + } + + public void setDx2(int dx2) { + this.dx2 = dx2; + } + + public int getDy2() { + return dy2; + } + + public void setDy2(int dy2) { + this.dy2 = dy2; + } + + public short getCol1() { + return col1; + } + + public void setCol1(short col1) { + this.col1 = col1; + } + + public int getRow1() { + return row1; + } + + public void setRow1(int row1) { + this.row1 = row1; + } + + public short getCol2() { + return col2; + } + + public void setCol2(short col2) { + this.col2 = col2; + } + + public int getRow2() { + return row2; + } + + public void setRow2(int row2) { + this.row2 = row2; + } +} diff --git a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java index 4eb115c5..eb094d7f 100644 --- a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java @@ -136,15 +136,27 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { } CreationHelper helper = sheet.getWorkbook().getCreationHelper(); ClientAnchor anchor = helper.createClientAnchor(); - anchor.setDx1(0); - anchor.setDx2(0); - anchor.setDy1(0); - anchor.setDy2(0); - anchor.setCol1(cell.getColumnIndex()); - anchor.setCol2(cell.getColumnIndex() + 1); - anchor.setRow1(cell.getRowIndex()); - anchor.setRow2(cell.getRowIndex() + 1); - anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); + if(cellData.getUseImagePositionProperty()) { + anchor.setDx1(cellData.getImagePositionProperty().getDx1()); + anchor.setDx2(cellData.getImagePositionProperty().getDx2()); + anchor.setDy1(cellData.getImagePositionProperty().getDy1()); + anchor.setDy2(cellData.getImagePositionProperty().getDy2()); + anchor.setCol1(cellData.getImagePositionProperty().getCol1()); + anchor.setCol2(cellData.getImagePositionProperty().getCol2()); + anchor.setRow1(cellData.getImagePositionProperty().getRow1()); + anchor.setRow2(cellData.getImagePositionProperty().getRow2()); + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE); + } else { + anchor.setDx1(0); + anchor.setDx2(0); + anchor.setDy1(0); + anchor.setDy2(0); + anchor.setCol1(cell.getColumnIndex()); + anchor.setCol2(cell.getColumnIndex() + 1); + anchor.setRow1(cell.getRowIndex()); + anchor.setRow2(cell.getRowIndex() + 1); + anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); + } drawing.createPicture(anchor, index); } } diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageDataWithAnnotation.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageDataWithAnnotation.java new file mode 100644 index 00000000..d76715f6 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageDataWithAnnotation.java @@ -0,0 +1,42 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.ImagePosition; +import com.alibaba.excel.converters.string.StringImageConverter; + +import lombok.Data; + +/** + * 图片导出类 + * + */ +@Data +@ContentRowHeight(100) +@ColumnWidth(100 / 8) +public class ImageDataWithAnnotation { + @ImagePosition(dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, col1 = 0, row1 = 3, col2 = 1, row2 = 4) + private File file; + @ImagePosition(dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, col1 = 0, row1 = 1, col2 = 2, row2 = 2) + private InputStream inputStream; + /** + * 如果string类型 必须指定转换器,string默认转换成string + */ + @ExcelProperty(converter = StringImageConverter.class) + @ImagePosition(dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, col1 = 2, row1 = 1, col2 = 3, row2 = 3) + private String string; + @ImagePosition(dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, col1 = 3, row1 = 1, col2 = 4, row2 = 5) + private byte[] byteArray; + /** + * 根据url导出 + * + * @since 2.1.1 + */ + @ImagePosition(dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0, col1 = 4, row1 = 1, col2 = 5, row2 = 2) + private URL url; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index c54ceb7f..49621979 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -225,7 +225,7 @@ public class WriteTest { inputStream = FileUtils.openInputStream(new File(imagePath)); imageData.setInputStream(inputStream); imageData.setUrl(new URL( - "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg")); + "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg")); EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list); } finally { if (inputStream != null) { @@ -234,6 +234,39 @@ public class WriteTest { } } + /** + * 使用注解设置图片位置,然后导出 + *

+ * 1. 创建excel对应的实体对象 参照{@link ImageData} + *

+ * 2. 直接写即可 + */ + @Test + public void imageWriteWithAnnotation() throws Exception { + String fileName = TestFileUtil.getPath() + "imageWriteWithAnnotation" + System.currentTimeMillis() + ".xlsx"; + // 如果使用流 记得关闭 + InputStream inputStream = null; + try { + List list = new ArrayList(); + ImageDataWithAnnotation imageData = new ImageDataWithAnnotation(); + list.add(imageData); + String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; + // 放入五种类型的图片 实际使用只要选一种即可 + imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); + imageData.setFile(new File(imagePath)); + imageData.setString(imagePath); + inputStream = FileUtils.openInputStream(new File(imagePath)); + imageData.setInputStream(inputStream); + imageData.setUrl(new URL( + "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg")); + EasyExcel.write(fileName, ImageDataWithAnnotation.class).sheet().doWrite(list); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + /** * 根据模板写入 *