public class AddDimensionedImage extends Object
The best way to make use of these techniques is to delay adding the image to the sheet until all other work has been completed. That way, the sizes of all rows and columns will have been adjusted - assuming that step was necessary. Even though the anchors type is set to prevent the image moving or re-sizing, this setting does not have any effect until the sheet is being viewed using the Excel application.
The key to the process is the ClientAnchor class. It defines methods that allow us to define the location of an image by specifying the following;
* How far - in terms of coordinate positions - the image should be inset from the left hand border of a cell. * How far - in terms of coordinate positions - the image should be inset from the from the top of the cell. * How far - in terms of coordinate positions - the right hand edge of the image should protrude into a cell (measured from the cells left hand edge to the images right hand edge). * How far - in terms of coordinate positions - the bottom edge of the image should protrude into a row (measured from the cells top edge to the images bottom edge). * The index of the column that contains the cell whose top left hand corner should be aligned with the top left hand corner of the image. * The index of the row that contains the cell whose top left hand corner should be aligned with the images top left hand corner. * The index of the column that contains the cell whose top left hand corner should be aligned with the images bottom right hand corner * The index number of the row that contains the cell whose top left hand corner should be aligned with the images bottom right hand corner.
It can be used to add an image into cell A1, for example, in the following manner;
ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
anchor.setDx1(0); anchor.setDy1(0); anchor.setDx2(0); anchor.setDy2(0); anchor.setCol1(0); anchor.setRow1(0); anchor.setCol2(1); anchor.setRow2(1);
Taken together, the first four methods define the locations of the top left and bottom right hand corners of the image if you imagine that the image is represented by a simple rectangle. The setDx1() and setDy1() methods locate the top left hand corner of the image while setDx2() and and Dy2() locate the bottom right hand corner of the image. An individual image can be inserted into a single cell or is can lie across many cells and the latter four methods are used to define just where the image should be positioned. They do this by again by identifying where the top left and bottom right hand corners of the image should be located but this time in terms of the indexes of the cells in which those corners should be located. The setCol1() and setRow1() methods together identify the cell that should contain the top left hand corner of the image while setCol2() and setRow2() do the same for the images bottom right hand corner.
Knowing that, it is possible to look again at the example above and to see that the top left hand corner of the image will be located in cell A1 (0, 0) and it will be aligned with the very top left hand corner of the cell. Likewise, the bottom right hand corner of the image will be located in cell B2 (1, 1) and it will again be aligned with the top left hand corner of the cell. This has the effect of making the image seem to occupy the whole of cell A1. Interestingly, it also has an effect on the images resizing behaviour because testing has demonstrated that if the image is wholly contained within one cell and is not 'attached' for want of a better word, to a neighbouring cell, then that image will not increase in size in response to the user dragging the column wider or the cell higher.
The following example demonstrates a slightly different way to insert an image into cell A1 and to ensure that it occupies the whole of the cell. This is accomplished by specifying the images bottom right hand corner should be aligned with the bottom right hand corner of the cell. It is also a case where the image will not increase in size if the user increases the size of the enclosing cell - irrespective of the anchors type - but it will reduce in size if the cell is made smaller.
ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
anchor.setDx1(0); anchor.setDy1(0); anchor.setDx2(1023); anchor.setDy2(255); anchor.setCol1(0); anchor.setRow1(0); anchor.setCol2(0); anchor.setRow2(0);
Note that the final four method calls all pass the same value and seem to indicate that the images top left hand corner is aligned with the top left hand corner of cell A1 and that its bottom right hand corner is also aligned with the top left hand corner of cell A1. Yet, running this code would see the image fully occupying cell A1. That is the result of the values passed to parameters three and four; these I have referred to as determining the images coordinates within the cell. They indicate that the image should occupy - in order - the full width of the column and the full height of the row.
The co-ordinate values shown are the maxima; and they are independent of row height/column width and of the font used. Passing 255 will always result in the image occupying the full height of the row and passing 1023 will always result in the image occupying the full width of the column. They help in situations where an image is larger than a column/row and must overlap into the next column/row. Using them does mean, however, that it is often necessary to perform conversions between Excels characters units, points, pixels and millimetres in order to establish how many rows/columns an image should occupy and just what the various insets ought to be.
Note that the setDx1(int) and setDy1(int) methods of the ClientAchor class are not made use of in the code that follows. It would be fairly trivial however to extend this example further and provide methods that would centre an image within a cell or allow the user to specify that a plain border a fixed number of millimetres wide should wrap around the image. Those first two parameters would make this sort of functionality perfectly possible.
Owing to the various conversions used, the actual size of the image may vary from that required; testing has so far found this to be in the region of plus or minus two millimetres. Most likely by modifying the way the calculations are performed - possibly using double(s) throughout and rounding the values at the correct point - it is likely that these errors could be reduced or removed.
A note concerning Excels image resizing behaviour. The ClientAnchor class contains a method called setAnchorType(int) which can be used to determine how Excel will resize an image in response to the user increasing or decreasing the dimensions of the cell containing the image. There are three values that can be passed to this method; 0 = To move and size the image with the cell, 2 = To move but don't size the image with the cell, 3 = To prevent the image from moving or being resized along with the cell. If an image is inserted using this class and placed into a single cell then if the setAnchorType(int) method is called and a value of either 0 or 2 passed to it, the resultant resizing behaviour may be a surprise. The image will not grow in size of the column is made wider or the row higher but it will shrink if the columns width or rows height are reduced.
| Modifier and Type | Class and Description |
|---|---|
static class |
AddDimensionedImage.ClientAnchorDetail
The HSSFClientAnchor class accepts eight arguments.
|
static class |
AddDimensionedImage.ConvertImageUnits
Utility methods used to convert Excels character based column and row
size measurements into pixels and/or millimetres.
|
| Modifier and Type | Field and Description |
|---|---|
static int |
EXPAND_COLUMN |
static int |
EXPAND_ROW |
static int |
EXPAND_ROW_AND_COLUMN |
static int |
OVERLAY_ROW_AND_COLUMN |
| Constructor and Description |
|---|
AddDimensionedImage() |
| Modifier and Type | Method and Description |
|---|---|
void |
addImageToSheet(int colNumber,
int rowNumber,
Sheet sheet,
Drawing<?> drawing,
URL imageFile,
double reqImageWidthMM,
double reqImageHeightMM,
int resizeBehaviour)
Add an image to a worksheet.
|
void |
addImageToSheet(String cellNumber,
Sheet sheet,
Drawing<?> drawing,
URL imageFile,
double reqImageWidthMM,
double reqImageHeightMM,
int resizeBehaviour)
Add an image to a worksheet.
|
static void |
main(String[] args)
The main entry point to the program.
|
public static final int EXPAND_ROW
public static final int EXPAND_COLUMN
public static final int EXPAND_ROW_AND_COLUMN
public static final int OVERLAY_ROW_AND_COLUMN
public void addImageToSheet(String cellNumber, Sheet sheet, Drawing<?> drawing, URL imageFile, double reqImageWidthMM, double reqImageHeightMM, int resizeBehaviour) throws IOException, IllegalArgumentException
cellNumber - A String that contains the location of the cell whose
top left hand corner should be aligned with the top
left hand corner of the image; for example "A1", "A2"
etc. This is to support the familiar Excel syntax.
Whilst images are not actually inserted into cells
this provides a convenient method of indicating where
the image should be positioned on the sheet.sheet - A reference to the sheet that contains the cell referenced
above.drawing - An instance of the DrawingPatriarch class. This is now
passed into the method where it was, previously, recovered
from the sheet in order to allow multiple pictures be
inserted. If the patriarch was not 'cached in this manner
each time it was created any previously positioned images
would be simply over-written.imageFile - An instance of the URL class that encapsulates the name
of and path to the image that is to be 'inserted into'
the sheet.reqImageWidthMM - A primitive double that contains the required
width of the image in millimetres.reqImageHeightMM - A primitive double that contains the required
height of the image in millimetres.resizeBehaviour - A primitive int whose value will determine how
the code should react if the image is larger than
the cell referenced by the cellNumber parameter.
Four constants are provided to determine what
should happen;
AddDimensionedImage.EXPAND_ROW
AddDimensionedImage.EXPAND_COLUMN
AddDimensionedImage.EXPAND_ROW_AND_COLUMN
AddDimensionedImage.OVERLAY_ROW_AND_COLUMNFileNotFoundException - If the file containing the image
cannot be located.IOException - If a problem occurs whilst reading the file
of image data.IllegalArgumentException - If an invalid value is passed
to the resizeBehaviour
parameter.public void addImageToSheet(int colNumber,
int rowNumber,
Sheet sheet,
Drawing<?> drawing,
URL imageFile,
double reqImageWidthMM,
double reqImageHeightMM,
int resizeBehaviour)
throws IOException,
IllegalArgumentException
colNumber - A primitive int that contains the index number of a
column on the worksheet; POI column indices are zero
based. Together with the rowNumber parameter's value,
this parameter identifies a cell on the worksheet. The
images top left hand corner will be aligned with the
top left hand corner of this cell.rowNumber - A primitive int that contains the index number of a row
on the worksheet; POI row indices are zero based.
Together with the rowNumber parameter's value, this
parameter identifies a cell on the worksheet. The
images top left hand corner will be aligned with the
top left hand corner of this cell.sheet - A reference to the sheet that contains the cell identified
by the two parameters above.drawing - An instance of the DrawingPatriarch class. This is now
passed into the method where it was, previously, recovered
from the sheet in order to allow multiple pictures be
inserted. If the patriarch was not 'cached in this manner
each time it was created any previously positioned images
would be simply over-written.imageFile - An instance of the URL class that encapsulates the name
of and path to the image that is to be 'inserted into'
the sheet.reqImageWidthMM - A primitive double that contains the required
width of the image in millimetres.reqImageHeightMM - A primitive double that contains the required
height of the image in millimetres.resizeBehaviour - A primitive int whose value will determine how
the code should react if the image is larger than
the cell referenced by the colNumber and
rowNumber parameters. Four constants are provided
to determine what should happen;
AddDimensionedImage.EXPAND_ROW
AddDimensionedImage.EXPAND_COLUMN
AddDimensionedImage.EXPAND_ROW_AND_COLUMN
AddDimensionedImage.OVERLAY_ROW_AND_COLUMNFileNotFoundException - If the file containing the image
cannot be located.IOException - If a problem occurs whilst reading the file
of image data.IllegalArgumentException - If an invalid value is passed
to the resizeBehaviour
parameter or if the extension
of the image file indicates that
it is of a type that cannot
currently be added to the worksheet.public static void main(String[] args) throws IOException
Note, the code is not restricted to use on new workbooks only. If an image is to be inserted into an existing workbook. just open that workbook, gat a reference to a sheet and pass that;
AddDimensionedImage addImage = new AddDimensionedImage();
File file = new File("....... Existing Workbook ......."); FileInputStream fis = new FileInputStream(file); Workbook workbook = new HSSFWorkbook(fis); HSSFSheet sheet = workbook.getSheetAt(0); addImage.addImageToSheet("C3", sheet, "image.jpg", 30, 20, AddDimensionedImage.EXPAND.ROW);
args - the command line argumentsIOException