I am trying to resize an EMF image after inserting it into an XSSFWorkbook.
There is support resizing PNG, JPEG and DIB images.
private void addNormalFigure(XSSFSheet sheet, byte[] imgData){
XSSFWorkbook w = sheet.getWorkbook();
int picIdx = w.addPicture(imgData, Workbook.PICTURE_TYPE_EMF);
CreationHelper helper = w.getCreationHelper();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
// Column : A
anchor.setCol1(0);
// Row : 4
anchor.setRow1(4);
Picture pic = drawing.createPicture(anchor, picIdx);
double height = 2.0;
double width = 2.0;
// sets the anchor.col2 to 0 and anchor.row2 to 0
pic.getImageDimension().setSize(inchToPixel(width), inchToPixel(height));
// pic.resize(); -> this too sets the anchor.col2 to 0 and anchor.row2 to 0
}
private double inchToPixel(double in) {
return in * 96.0;
}
Is there any way we can workaround this problem?
Apache poi not provides to get image dimensions from Picture of type Workbook.PICTURE_TYPE_EMF. The used ImageUtils method getImageDimension only is able to get dimensions from JPEG, PNG and DIB pictures,
But apache poi provides org.apache.poi.hemf.usermodel.HemfPicture. So
import org.apache.poi.hemf.usermodel.HemfPicture;
...
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(imgData));
System.out.println(hemfPicture.getSize());
...
will print the correct dimensions.
But then it lacks a possibility to set those dimensions to the anchor. There is a method scaleCell in ImageUtils but not public accessible. So only way would be to copy source code of that method into your code.
Following complete example does that. It uses methos scaleCell having same code as in ImageUtils. The method resizeHemfPicture resizes the Picture to the HemfPicture dimension.
This is tested and works using apache poi 5.0.0 and Java 12.
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Units;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.hemf.usermodel.HemfPicture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.awt.Dimension;
import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
class CreateExcelEMFPicture {
public static double getRowHeightInPixels(Sheet sheet, int rowNum) {
Row r = sheet.getRow(rowNum);
double points = (r == null) ? sheet.getDefaultRowHeightInPoints() : r.getHeightInPoints();
return Units.toEMU(points)/(double)Units.EMU_PER_PIXEL;
}
private static void scaleCell(final double targetSize,
final int startCell,
final int startD,
Consumer<Integer> endCell,
Consumer<Integer> endD,
final int hssfUnits,
Function<Integer,Number> nextSize) {
if (targetSize < 0) {
throw new IllegalArgumentException("target size < 0");
}
int cellIdx = startCell;
double dim, delta;
for (double totalDim = 0, remDim;; cellIdx++, totalDim += remDim) {
dim = nextSize.apply(cellIdx).doubleValue();
remDim = dim;
if (cellIdx == startCell) {
if (hssfUnits > 0) {
remDim *= 1 - startD/(double)hssfUnits;
} else {
remDim -= startD/(double)Units.EMU_PER_PIXEL;
}
}
delta = targetSize - totalDim;
if (delta < remDim) {
break;
}
}
double endDval;
if (hssfUnits > 0) {
endDval = delta/dim * (double)hssfUnits;
} else {
endDval = delta * Units.EMU_PER_PIXEL;
}
if (cellIdx == startCell) {
endDval += startD;
}
endCell.accept(cellIdx);
endD.accept((int)Math.rint(endDval));
}
static void resizeHemfPicture(Picture picture, HemfPicture hemfPicture) {
ClientAnchor anchor = picture.getClientAnchor();
boolean isHSSF = (anchor instanceof HSSFClientAnchor);
double height = hemfPicture.getSize().getHeight();
double width = hemfPicture.getSize().getWidth();
Sheet sheet = picture.getSheet();
int WIDTH_UNITS = 1024;
int HEIGHT_UNITS = 256;
scaleCell(width, anchor.getCol1(), anchor.getDx1(), anchor::setCol2, anchor::setDx2, isHSSF ? WIDTH_UNITS : 0, sheet::getColumnWidthInPixels);
scaleCell(height, anchor.getRow1(), anchor.getDy1(), anchor::setRow2, anchor::setDy2, isHSSF ? HEIGHT_UNITS : 0, (row) -> getRowHeightInPixels(sheet, row));
}
public static void main(String[] args) throws Exception{
Workbook workbook = new XSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xlsx";
//Workbook workbook = new HSSFWorkbook(); String filePath = "./CreateExcelEMFPicture.xls";
CreationHelper helper = workbook.getCreationHelper();
//add picture data to this workbook.
FileInputStream is = new FileInputStream("./image.emf");
byte[] bytes = IOUtils.toByteArray(is);
int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_EMF);
is.close();
HemfPicture hemfPicture = new HemfPicture(new ByteArrayInputStream(bytes));
System.out.println(hemfPicture.getSize()); // returns correct dimension
Sheet sheet = workbook.createSheet("Sheet1");
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(0);
anchor.setRow1(4);
Picture picture = drawing.createPicture(anchor, pictureIdx);
System.out.println(picture.getImageDimension()); // 0, 0
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // 0, 0
//picture.resize(); //will not work
resizeHemfPicture(picture, hemfPicture);
System.out.println(ImageUtils.getDimensionFromAnchor(picture)); // correct dimension
FileOutputStream out = new FileOutputStream(filePath);
workbook.write(out);
out.close();
workbook.close();
}
}
Related
I am trying to create yolov4 detection code, using java with (.weights and .cfg) file from python. here I am tring to open python file in java using these two files, so I faced problem when I run the code run time error.
note: I used opencv 4.5.5, yolov4.
package YOLOv4;
import org.opencv.core.*;
import org.opencv.dnn.*;
import org.opencv.utils.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import java.util.ArrayList;
import java.util.List;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class yolo {
private static List<String> getOutputNames(Net net) {
List<String> names = new ArrayList<>();
List<Integer> outLayers = net.getUnconnectedOutLayers().toList();
List<String> layersNames = net.getLayerNames();
outLayers.forEach((item) -> names.add(layersNames.get(item - 1)));//unfold and create R-CNN layers from the loaded YOLO model//
return names;
}
public static void main(String[] args) throws InterruptedException {
System.load("C:/Users/mayal/OneDrive/Desktop/opencv/build/java/x64/opencv_java455.dll"); // Load the openCV 4.0 dll //
String modelWeights = "C:/Users/mayal/OneDrive/Desktop/yolov4-opencv-python/yolov4-tiny.weights"; //Download and load only wights for YOLO , this is obtained from official YOLO site//
String modelConfiguration = "C:/Users/mayal/OneDrive/Desktop/yolov4-opencv-python/yolov4-tiny";//Download and load cfg file for YOLO , can be obtained from official site//
String filePath = "C:/Users/mayal/OneDrive/Desktop/yolov4-opencv-python/cars.mp4"; //My video file to be analysed//
VideoCapture cap = new VideoCapture(filePath);// Load video using the videocapture method//
Mat frame = new Mat(); // define a matrix to extract and store pixel info from video//
Mat dst = new Mat ();
//cap.read(frame);
JFrame jframe = new JFrame("Video"); // the lines below create a frame to display the resultant video with object detection and localization//
JLabel vidpanel = new JLabel();
jframe.setContentPane(vidpanel);
jframe.setSize(620, 620);
jframe.setVisible(true);// we instantiate the frame here//
Net net = Dnn.readNetFromDarknet(modelWeights, modelConfiguration); //OpenCV DNN supports models trained from various frameworks like Caffe and TensorFlow. It also supports various networks architectures based on YOLO//
//Thread.sleep(5000);
//Mat image = Imgcodecs.imread("D:\\yolo-object-detection\\yolo-object-detection\\images\\soccer.jpg");
Size sz = new Size(620,620);
List<Mat> result = new ArrayList<>();
List<String> outBlobNames = getOutputNames(net);
while (true) {
if (cap.read(frame)) {
Mat blob = Dnn.blobFromImage(frame, 0.00392, sz, new Scalar(0), true, false); // We feed one frame of video into the network at a time, we have to convert the image to a blob. A blob is a pre-processed image that serves as the input.//
net.setInput(blob);
net.forward(result, outBlobNames); //Feed forward the model to get output //
// outBlobNames.forEach(System.out::println);
// result.forEach(System.out::println);
float confThreshold = 0.6f; //Insert thresholding beyond which the model will detect objects//
List<Integer> clsIds = new ArrayList<>();
List<Float> confs = new ArrayList<>();
List<Rect2d> Rect2ds = new ArrayList<>();
for (int i = 0; i < result.size(); ++i)
{
// each row is a candidate detection, the 1st 4 numbers are
// [center_x, center_y, width, height], followed by (N-4) class probabilities
Mat level = result.get(i);
for (int j = 0; j < level.rows(); ++j)
{
Mat row = level.row(j);
Mat scores = row.colRange(5, level.cols());
Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
float confidence = (float)mm.maxVal;
Point classIdPoint = mm.maxLoc;
if (confidence > confThreshold)
{
int centerX = (int)(row.get(0,0)[0] * frame.cols()); //scaling for drawing the bounding boxes//
int centerY = (int)(row.get(0,1)[0] * frame.rows());
int width = (int)(row.get(0,2)[0] * frame.cols());
int height = (int)(row.get(0,3)[0] * frame.rows());
int left = centerX - width / 2;
int top = centerY - height / 2;
clsIds.add((int)classIdPoint.x);
confs.add((float)confidence);
Rect2ds.add(new Rect2d(left, top, width, height));
}
}
}
float nmsThresh = 0.5f;
MatOfFloat confidences = new MatOfFloat(Converters.vector_float_to_Mat(confs));
Rect2d[] boxesArray = Rect2ds.toArray(new Rect2d[0]);
MatOfRect2d boxes = new MatOfRect2d(boxesArray);
MatOfInt indices = new MatOfInt();
Dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThresh, indices); //We draw the bounding boxes for objects here//
int [] ind = indices.toArray();
int j=0;
for (int i = 0; i < ind.length; ++i)
{
int idx = ind[i];
Rect2d box = boxesArray[idx];
Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(0,0,255), 2);
//i=j;
System.out.println(idx);
}
// Imgcodecs.imwrite("D://out.png", image);
//System.out.println("Image Loaded");
ImageIcon image = new ImageIcon(Mat2bufferedImage(frame)); //setting the results into a frame and initializing it //
vidpanel.setIcon(image);
vidpanel.repaint();
// System.out.println(j);
// System.out.println("Done");
}
}
}
// }
private static BufferedImage Mat2bufferedImage(Mat image) { // The class described here takes in matrix and renders the video to the frame //
MatOfByte bytemat = new MatOfByte();
Imgcodecs.imencode(".jpg", image, bytemat);
byte[] bytes = bytemat.toArray();
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage img = null;
try {
img = ImageIO.read(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return img;
}
}
I am trying to compute the percentage images within a PDF "occupy" on each page. I have the following code:
PDPageTree list = document.getPages();
int pageNumber = 0;
float imagePerPage = 0;
for (PDPage page : list) {
BufferedImage pageImage = renderer.renderImage(pageNumber, 2);
float pageWidth = pageImage.getWidth();
float pageHeight = pageImage.getHeight();
PDResources pdResources = page.getResources();
int i = 1;
for (COSName name : pdResources.getXObjectNames()) {
PDXObject object = pdResources.getXObject(name);
if (object instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) object;
BufferedImage bufferedImage = image.getImage();
float imageWidth = bufferedImage.getWidth();
float imageHeight = bufferedImage.getHeight();
int sumr = 0;
int sumg = 0;
int sumb = 0;
for (int x = 0; x < imageWidth; x++) {
for (int y = 0; y < imageHeight; y++) {
Color pixel = new Color(bufferedImage.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
}
}
int num = image.getWidth() * image.getHeight();
Color avg = new Color(sumr / num, sumg / num, sumb / num);
if (!new Color(0, 0, 0).equals(avg)) {
String filename = "extracted-image-" + i + ".png";
ImageIO.write(
image.getImage(),
"png",
new File(filename)
);
imagePerPage++;
}
i++;
}
}
System.out.println("Image per page ratio is: " + imagePerPage);
imagePerPage = 0;
pageNumber++;
}
However, bufferedImage.getWidth() and bufferedImage.getHeight() return the actual size of the image in pixels. How could I get the displayed size for each image?
UPDATE 1
I have tried using PrintImageLocations.java example for retrieving display image sizes. However, in case of an actual pdf, it seems to give wrong responses.
In case of this PDF whose mediabox has 612 in width and 792 as height, the scaled numbers for the images of 25 (as width) and 16.61 (as height) do not seem to be correct. After all, each image has at least a third of the total width.
did something useful for me using example present on pdfbox documentation site
package br.gov.pb.mp.framework.util.pdf;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.pdfbox.contentstream.PDFStreamEngine;
import org.apache.pdfbox.contentstream.operator.DrawObject;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.contentstream.operator.state.Concatenate;
import org.apache.pdfbox.contentstream.operator.state.Restore;
import org.apache.pdfbox.contentstream.operator.state.Save;
import org.apache.pdfbox.contentstream.operator.state.SetGraphicsStateParameters;
import org.apache.pdfbox.contentstream.operator.state.SetMatrix;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.util.Matrix;
public class ImageSizeExtractor extends PDFStreamEngine {
private Map<String, float[]> pageImages;
public ImageSizeExtractor() throws IOException {
// preparing PDFStreamEngine
addOperator(new Concatenate());
addOperator(new DrawObject());
addOperator(new SetGraphicsStateParameters());
addOperator(new Save());
addOperator(new Restore());
addOperator(new SetMatrix());
pageImages = new HashMap<String, float[]>();
}
public Map<String, float[]> getPageImages() {
return pageImages;
}
public void setPageImages(Map<String, float[]> pageImages) {
this.pageImages = pageImages;
}
#Override
protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
String operation = operator.getName();
if ("Do".equals(operation)) {
COSName objectName = (COSName) operands.get(0);
// get the PDF object
PDXObject xobject = getResources().getXObject(objectName);
// check if the object is an image object
if (xobject instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) xobject;
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
System.out.println("\nImage [" + objectName.getName() + "]");
Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
float imageXScale = ctmNew.getScalingFactorX();
float imageYScale = ctmNew.getScalingFactorY();
System.out.println("displayed size = " + imageXScale + ", " + imageYScale + " in user space units");
float[] xy = {imageXScale,imageYScale};
pageImages.put(objectName.getName(), xy);
} else if (xobject instanceof PDFormXObject) {
PDFormXObject form = (PDFormXObject) xobject;
showForm(form);
}
} else {
super.processOperator(operator, operands);
}
}
}
method that makes use of the above class.
public static boolean analyseImageEntirePagePdfAto(byte[] sourcePdf) throws Throwable {
boolean containsEntirePageImage = false;
PDDocument docAto = PDDocument.load(sourcePdf);
int p = 0;
PDPageTree pageTree = docAto.getPages();
if (!containsEntirePageImage) {
for (PDPage pagina : pageTree) {
p++;
PDFTextStripper reader = new PDFTextStripper();
reader.setStartPage(p);
reader.setEndPage(p);
String pageText = reader.getText(docAto);
pageText = pageText.replaceAll("\r\n", "");
if (pageText == "" || pageText == null) {
containsEntirePageImage = true;
break;
}
float ph = pagina.getMediaBox().getHeight();
float pw = pagina.getMediaBox().getWidth();
float pageArea = ph * pw;
ImageSizeExtractor imageSizeExtractor = new ImageSizeExtractor();
imageSizeExtractor.processPage(pagina);
if (!imageSizeExtractor.getPageImages().entrySet().isEmpty()) {
for (Map.Entry<String, float[]> entry : imageSizeExtractor.getPageImages().entrySet()) {
float[] imageMeasures = entry.getValue();
float imageArea = imageMeasures[0] * imageMeasures[1];
float imgPercent = (imageArea / pageArea) * 100;
if (imgPercent > 80) {
containsEntirePageImage = true;
break;
}
}
}
}
}
return containsEntirePageImage;
}
the processPage(PDPage page) method is in the PDFStreamEngine class
I need to use Apache POI(4.1.1) to write some text inside a textbox (or rectangle shape), and this text must have superscripts in it. I can get this to work for data inside a cell, but not when using a textbox. Here is a minimal example:
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.*;
import java.io.FileOutputStream;
public class SuperScriptTest {
public static void main(String[] args) throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet ws = wb.createSheet("Sheet 1");
XSSFFont fontInfo = wb.createFont();
fontInfo.setFontName("Arial");
fontInfo.setFontHeightInPoints((short) 11);
XSSFFont fontInfoSuperscript = wb.createFont();
fontInfoSuperscript.setFontName("Arial");
fontInfoSuperscript.setFontHeightInPoints((short) 11);
fontInfoSuperscript.setTypeOffset(Font.SS_SUPER);
fontInfoSuperscript.setColor(IndexedColors.RED.getIndex());
Row row = ws.createRow(0);
Cell cell = row.createCell(0);
// Writing to a cell produces desired results:
XSSFRichTextString richString = new XSSFRichTextString("Level3");
richString.applyFont(fontInfo);
richString.applyFont(5, 6, fontInfoSuperscript);
cell.setCellValue(richString);
// Writing to a textbox does not:
XSSFDrawing drawing = ws.createDrawingPatriarch();
XSSFTextBox txtBox = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 0, 5, 2, 7));
XSSFRichTextString richString2 = new XSSFRichTextString("Level3");
richString2.applyFont(fontInfo);
richString2.applyFont(5, 6, fontInfoSuperscript);
txtBox.setText(richString2);
try (FileOutputStream fileOut = new FileOutputStream("Superscript.xlsx")) {
wb.write(fileOut);
}
}
}
The cell will give me the right font and size, and properly superscript the 3 and turn it red.
The textbox will give me the correct font and size, and will color the 3, but it will not superscript the 3.
Thank you for any help.
In Excel cells and text box shapes have different kinds of font settings. For Excel cells spreadsheet settings are used while for text box shapes drawing settings are used.
Because XSSFRichTextString mostly gets used for Excel cell values and shared strings, it internally uses spreadsheet settings. When it comes to XSSFRichTextStrings in context of shapes, the settings need to be converted. This is done in XSSFSimpleShape.setText(XSSFRichTextString str) using the method XSSFSimpleShape.applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr).
In spreadsheet settings CTRPrElt there is a CTVerticalAlignFontProperty used to set baseline, superscript or subscript. In drawing settings CTTextCharacterProperties there is a baseline attrtibute used which is 0 for baseline, +n% for superscript and -n% for subscript. There n% is the distance from the baseline.
Until now the XSSFSimpleShape.applyAttributes lacks converting CTVerticalAlignFontProperty to CTTextCharacterProperties.setBaseline. To get this, one could patching XSSFSimpleShape.applyAttributes like so:
private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr) {
...
if (pr.sizeOfVertAlignArray() > 0) {
CTVerticalAlignFontProperty vertAlign = pr.getVertAlignArray(0);
if (vertAlign.getVal() == STVerticalAlignRun.BASELINE) {
rPr.setBaseline(0);
} else if (vertAlign.getVal() == STVerticalAlignRun.SUPERSCRIPT) {
rPr.setBaseline(30000); //30% distance from baseline == default superscript
} else if (vertAlign.getVal() == STVerticalAlignRun.SUBSCRIPT) {
rPr.setBaseline(-25000); //-25% distance from baseline == default subscript
}
}
}
For superscript 30% distance from baseline is choosen because that is the default when someone ticks text effect superscript in text box font settings. For subscript -25% distance from baseline is choosen because that is the default when someone ticks text effect subscript in text box font settings.
Complete example having own setText and applyAttributes to show that it works:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import org.apache.poi.hssf.util.HSSFColor;
import java.io.FileOutputStream;
public class SuperScriptTest {
static void setText(XSSFSimpleShape shape, XSSFRichTextString str) {
XSSFWorkbook wb = (XSSFWorkbook) shape.getDrawing().getParent().getParent();
//str.setStylesTableReference(wb.getStylesSource()); // cannot be done here since XSSFRichTextString.setStylesTableReference has protected access
CTTextParagraph p = CTTextParagraph.Factory.newInstance();
if (str.numFormattingRuns() == 0) {
CTRegularTextRun r = p.addNewR();
CTTextCharacterProperties rPr = r.addNewRPr();
rPr.setLang("en-US");
rPr.setSz(1100);
r.setT(str.getString());
} else {
for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
CTRElt lt = str.getCTRst().getRArray(i);
CTRPrElt ltPr = lt.getRPr();
if (ltPr == null) {
ltPr = lt.addNewRPr();
}
CTRegularTextRun r = p.addNewR();
CTTextCharacterProperties rPr = r.addNewRPr();
rPr.setLang("en-US");
applyAttributes(ltPr, rPr);
r.setT(lt.getT());
}
}
//clearText(); //replaced by it's code, 3 lines below
shape.getTextParagraphs().clear();
CTTextBody txBody = shape.getCTShape().getTxBody();
txBody.setPArray(null); // remove any existing paragraphs
CTShape ctShape = shape.getCTShape();
ctShape.getTxBody().setPArray(new CTTextParagraph[] { p });
//shape.getTextParagraphs().add(new XSSFTextParagraph(ctShape.getTxBody().getPArray(0), ctShape)); // cannot be done here since XSSFTextParagraph contructor is not public
}
static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr) {
if (pr.sizeOfBArray() > 0) {
rPr.setB(pr.getBArray(0).getVal());
}
if (pr.sizeOfUArray() > 0) {
STUnderlineValues.Enum u1 = pr.getUArray(0).getVal();
if (u1 == STUnderlineValues.SINGLE) {
rPr.setU(STTextUnderlineType.SNG);
} else if (u1 == STUnderlineValues.DOUBLE) {
rPr.setU(STTextUnderlineType.DBL);
} else if (u1 == STUnderlineValues.NONE) {
rPr.setU(STTextUnderlineType.NONE);
}
}
if (pr.sizeOfIArray() > 0) {
rPr.setI(pr.getIArray(0).getVal());
}
if (pr.sizeOfRFontArray() > 0) {
CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
rFont.setTypeface(pr.getRFontArray(0).getVal());
}
if (pr.sizeOfSzArray() > 0) {
int sz = (int) (pr.getSzArray(0).getVal() * 100);
rPr.setSz(sz);
}
if (pr.sizeOfColorArray() > 0) {
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor xlsColor = pr.getColorArray(0);
if (xlsColor.isSetRgb()) {
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
clr.setVal(xlsColor.getRgb());
} else if (xlsColor.isSetIndexed()) {
HSSFColor indexed = HSSFColor.getIndexHash().get((int) xlsColor.getIndexed());
if (indexed != null) {
byte[] rgb = new byte[3];
rgb[0] = (byte) indexed.getTriplet()[0];
rgb[1] = (byte) indexed.getTriplet()[1];
rgb[2] = (byte) indexed.getTriplet()[2];
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
clr.setVal(rgb);
}
}
}
if (pr.sizeOfVertAlignArray() > 0) {
CTVerticalAlignFontProperty vertAlign = pr.getVertAlignArray(0);
if (vertAlign.getVal() == STVerticalAlignRun.BASELINE) {
rPr.setBaseline(0);
} else if (vertAlign.getVal() == STVerticalAlignRun.SUPERSCRIPT) {
rPr.setBaseline(30000); //30% distance from baseline == default superscript
} else if (vertAlign.getVal() == STVerticalAlignRun.SUBSCRIPT) {
rPr.setBaseline(-25000); //-25% distance from baseline == default subscript
}
}
}
public static void main(String[] args) throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet ws = wb.createSheet("Sheet 1");
XSSFFont fontInfo = wb.createFont();
fontInfo.setFontName("Arial");
fontInfo.setFontHeightInPoints((short) 11);
XSSFFont fontInfoSuperscript = wb.createFont();
fontInfoSuperscript.setFontName("Arial");
fontInfoSuperscript.setFontHeightInPoints((short) 11);
fontInfoSuperscript.setTypeOffset(Font.SS_SUPER);
//fontInfoSuperscript.setTypeOffset(Font.SS_SUB);
fontInfoSuperscript.setColor(IndexedColors.RED.getIndex());
Row row = ws.createRow(0);
Cell cell = row.createCell(0);
// Writing to a cell produces desired results:
XSSFRichTextString richString = new XSSFRichTextString("Level3");
richString.applyFont(fontInfo);
richString.applyFont(5, 6, fontInfoSuperscript);
cell.setCellValue(richString);
// Writing to a textbox does not:
XSSFDrawing drawing = ws.createDrawingPatriarch();
XSSFTextBox txtBox = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 0, 5, 2, 7));
XSSFRichTextString richString2 = new XSSFRichTextString("Level3");
richString2.applyFont(fontInfo);
richString2.applyFont(5, 6, fontInfoSuperscript);
//txtBox.setText(richString2);
setText(txtBox, richString2);
try (FileOutputStream fileOut = new FileOutputStream("Superscript.xlsx")) {
wb.write(fileOut);
}
}
}
I try to add a comment to a excel-field.
If I open the excel-file using Excel97 the Tooltip has bad boundings.
public static void main(String[] args) throws Exception {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell(0);
cell.setCellValue("Test1");
HSSFCreationHelper ch = sheet.getWorkbook().getCreationHelper();
HSSFClientAnchor anchor = ch.createClientAnchor();
HSSFComment comment = sheet.createDrawingPatriarch().createCellComment(anchor);
comment.setRow(0);
comment.setColumn(1);
comment.setString(ch.createRichTextString("Test2"));
comment.setAuthor("RM");
cell.setCellComment(comment);
sheet.autoSizeColumn(0);
workbook.close();
workbook.write(new FileOutputStream("d:/test.pdf"));
}
How to set the size of the tooltip programatically?
You should add comment along the lines of the example in Busy Developers' Guide to HSSF and XSSF Features.
Using the ClientAnchor position settings (col1, dx1, row1, dy1, col2, dx2, row2, dy2) you can set the position of the comment box.
Example:
import java.io.FileOutputStream;
import java.io.OutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
class CreateExcelWithComments {
public static void main(String[] args) throws Exception {
String type = "HSSF";
//String type = "XSSF";
Workbook wb = ("HSSF".equals(type))?new HSSFWorkbook():new XSSFWorkbook();
CreationHelper factory = wb.getCreationHelper();
Sheet sheet = wb.createSheet();
Row row = sheet.createRow(0);
Cell cell = row.createCell(0); // cell A1
cell.setCellValue("A1");
Drawing drawing = sheet.createDrawingPatriarch();
// When the comment box is visible, have it show in a 1x3 space
ClientAnchor anchor = factory.createClientAnchor();
anchor.setCol1(cell.getColumnIndex()+1); // starts at column A + 1 = B
anchor.setDx1(("HSSF".equals(type))?10*15:10*Units.EMU_PER_PIXEL); // plus 10 px
anchor.setCol2(cell.getColumnIndex()+2); // ends at column A + 2 = C
anchor.setDx2(("HSSF".equals(type))?10*15:10*Units.EMU_PER_PIXEL); // plus 10 px
anchor.setRow1(row.getRowNum()); // starts at row 1
anchor.setDy1(("HSSF".equals(type))?10*15:10*Units.EMU_PER_PIXEL); // plus 10 px
anchor.setRow2(row.getRowNum()+3); // ends at row 4
anchor.setDy2(("HSSF".equals(type))?10*15:10*Units.EMU_PER_PIXEL); // plus 10 px
// Create the comment and set the text+author
Comment comment = drawing.createCellComment(anchor);
RichTextString str = factory.createRichTextString("Hello, World!");
comment.setString(str);
comment.setAuthor("Apache POI");
// Assign the comment to the cell
cell.setCellComment(comment);
String fname = ("HSSF".equals(type))?"./comment-xssf.xls":"./comment-xssf.xlsx";
try (OutputStream out = new FileOutputStream(fname)) {
wb.write(out);
}
wb.close();
}
}
Result:
I want to add row in excel by java POI and I try with both shiftRows() function and createRow() function
both function can add row in excel but below chart position is remain and not move
I also like to move (shift down) the position of chart
I use poi version 3.9
Can anyone give me the advice or idea to move the position of that chart image
As the fact, the data range of chart also not changed. I need not only to move the position of charts but also need to increase the data range of chart
thanks!!
The shifting of the drawing anchors which determine the chart positions is possible. The method void insertRowsShiftShapes(Sheet sheet, int startRow, int n) does this for all drawing anchors which are affected of row inserting process into the sheet.
The correcting of the chart data ranges which are affected of the row inserting into the sheet is complicated as said already. It is not well tested and not ready yet. But I will provide it as a working draft. I hope it is a useful start point for further programming.
For running the code the ooxml-schemas-1.3.jar is needed as mentioned in apache poi FAQ
A good resource for documentation of the ooxml-schema objects for me is grepcode
Examples: CTTwoCellAnchor, CTPieChart, CTPieSer
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import java.io.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer;
import java.util.List;
class InsertRowsAboveChart {
//a method for shift rows and shift all anchors in drawing below the shifted rows
private static void insertRowsShiftShapes(Sheet sheet, int startRow, int n) {
java.util.List<CTTwoCellAnchor> drawingAnchors = ((XSSFDrawing)sheet.getDrawingPatriarch()).getCTDrawing().getTwoCellAnchorList();
for (CTTwoCellAnchor drawingAnchor : drawingAnchors) {
int fromRow = drawingAnchor.getFrom().getRow();
int toRow = drawingAnchor.getTo().getRow();
if (fromRow >= startRow) {
drawingAnchor.getFrom().setRow(fromRow + n);
drawingAnchor.getTo().setRow(toRow + n);
}
}
sheet.shiftRows(startRow, sheet.getLastRowNum(), n);
correctDataRangesOfCharts(sheet, startRow, n);
}
//a method for correcting data ranges for charts which are affected of the shifted rows
//!!working draft, not ready yet!!
private static void correctDataRangesOfCharts(Sheet sheet, int startRow, int n) {
java.util.List<XSSFChart> charts = ((XSSFDrawing)sheet.getDrawingPatriarch()).getCharts();
for (XSSFChart chart : charts) {
//pie charts
java.util.List<CTPieChart> piecharts = chart.getCTChart().getPlotArea().getPieChartList();
for (CTPieChart piechart : piecharts) {
java.util.List<CTPieSer> pieseries = piechart.getSerList();
for (CTPieSer pieserie : pieseries) {
boolean strRefchanged = false;
if (pieserie.getCat().isSetMultiLvlStrRef()) {
String strRef = pieserie.getCat().getMultiLvlStrRef().getF();
//todo: this only corrects the end row of the ranges, should also correct start row if affected
int strRefEndRow = Integer.parseInt(strRef.substring(strRef.lastIndexOf('$') + 1));
if (strRefEndRow >= startRow) {
strRef = strRef.substring(0, strRef.lastIndexOf('$') +1) + (strRefEndRow + n);
pieserie.getCat().getMultiLvlStrRef().setF(strRef);
strRefchanged = true;
}
} else if (pieserie.getCat().isSetStrRef()) {
String strRef = pieserie.getCat().getStrRef().getF();
int strRefEndRow = Integer.parseInt(strRef.substring(strRef.lastIndexOf('$') + 1));
if (strRefEndRow >= startRow) {
strRef = strRef.substring(0, strRef.lastIndexOf('$') +1) + (strRefEndRow + n);
pieserie.getCat().getStrRef().setF(strRef);
strRefchanged = true;
}
}
if (strRefchanged) {
String numRef = pieserie.getVal().getNumRef().getF();
int numRefEndRow = Integer.parseInt(numRef.substring(numRef.lastIndexOf('$') + 1));
if (numRefEndRow >= startRow) {
numRef = numRef.substring(0, numRef.lastIndexOf('$') +1) + (numRefEndRow + n);
pieserie.getVal().getNumRef().setF(numRef);
}
}
}
}
//pie charts end
}
}
public static void main(String[] args) {
try {
InputStream inp = new FileInputStream("Workbook.xlsx");
Workbook wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheetAt(0);
//sheet.shiftRows(3, 5, 4);
insertRowsShiftShapes(sheet, 2, 4);
FileOutputStream fileOut = new FileOutputStream("Workbook.xlsx");
wb.write(fileOut);
wb.close();
} catch (InvalidFormatException ifex) {
} catch (FileNotFoundException fnfex) {
} catch (IOException ioex) {
}
}
}