I've tested your code, it still only works with default font settings.
Actually, the method you use to calculate column width is as the same as I
written.

George


Yegor Kozlov wrote:
> 
> I wrote a custom resizer which attempts to take into account the actual
> default font in the workbook. See the code 
> below. It works, although the result can be 'off' by about 10% - depends
> on the font.
> Play with it, may be you will figure out how to tweak it to produce the
> exact result.
> 
> Patches are always welcome.
> 
> 
> import org.apache.poi.hssf.usermodel.*;
> import org.apache.poi.util.IOUtils;
> 
> import java.io.FileInputStream;
> import java.io.FileOutputStream;
> import java.awt.*;
> 
> /**
>   * @author Yegor Kozlov
>   */
> public class ResizeImage {
> 
> 
>      public static void main(String[] args) throws Exception {
> 
>          HSSFWorkbook wb = new HSSFWorkbook();
>          HSSFSheet sh = wb.createSheet();
> 
>          //change the default font
>          for(short i=0; i < wb.getNumberOfFonts(); i++){
>              HSSFFont f = wb.getFontAt(i);
>              f.setFontHeight((short)(f.getFontHeight()*2));
>              f.setFontName("Verdana");
>          }
> 
>          HSSFPatriarch p = sh.createDrawingPatriarch();
>          for (int i = 0; i < args.length; i++) {
> 
>              byte[] bytes = IOUtils.toByteArray(new
> FileInputStream(args[i]));
>              int idx = wb.addPicture(bytes,
> HSSFWorkbook.PICTURE_TYPE_JPEG);
>              HSSFPicture picture = p.createPicture(new HSSFClientAnchor(),
> idx);
>              new PictureResizer(sh, picture).resize();
>          }
> 
> 
>          FileOutputStream out = new FileOutputStream("workbook.xls");
>          wb.write(out);
>          out.close();
>      }
> 
> 
>      public static class PictureResizer {
>          final HSSFPicture _picture;
>          final HSSFSheet _sheet;
>          final float _pw;
>          final float _ph;
> 
> 
>          public PictureResizer(HSSFSheet sheet, HSSFPicture picture){
>              _picture = picture;
>              _sheet = sheet;
> 
>              HSSFFont defaultFont =
> sheet.getWorkbook().getFontAt((short)0);
>              Font font = new Font(defaultFont.getFontName(), Font.PLAIN,
> defaultFont.getFontHeightInPoints());
> 
>              FontMetrics fontMetrics = new Label().getFontMetrics(font);
>              //width of the default character in pixels at 96 dpi
>              _pw = (float)fontMetrics.charWidth('0')*96/72;
>              // height of the default character in pixels at 96 dpi
>              // (if the row has a medium or thick top border, or if any
> cell in the row directly above
>              // the current row has a thick bottom border then the row
> height has been adjusted higher by .75 points )
>              _ph = (float)(fontMetrics.getMaxAscent() +
> fontMetrics.getMaxDescent() + 0.75)*96/72;
> 
>          }
> 
>          private float getColumnWidthInPixels(int column){
> 
>              int cw = _sheet.getColumnWidth(column);
>              return _pw*cw/256;
>          }
> 
>          private float getRowHeightInPixels(int i){
> 
>              HSSFRow row = _sheet.getRow(i);
>              float height;
>              if(row != null) height = row.getHeight();
>              else height = _sheet.getDefaultRowHeight();
> 
>              return height/255*_ph;
>          }
> 
> 
>          public HSSFClientAnchor getPreferredSize(){
>              HSSFClientAnchor anchor =
> (HSSFClientAnchor)_picture.getAnchor();
> 
>              Dimension size = _picture.getImageDimension();
>              double scaledWidth = size.getWidth();
>              double scaledHeight = size.getHeight();
> 
>              float w = 0;
> 
>              //space in the leftmost cell
>              w += getColumnWidthInPixels(anchor.getCol1())*(1 -
> (float)anchor.getDx1()/1024);
>              short col2 = (short)(anchor.getCol1() + 1);
>              int dx2 = 0;
> 
>              while(w < scaledWidth){
>                  w += getColumnWidthInPixels(col2++);
>              }
> 
>              if(w > scaledWidth) {
>                  //calculate dx2, offset in the rightmost cell
>                  col2--;
>                  double cw = getColumnWidthInPixels(col2);
>                  double delta = w - scaledWidth;
>                  dx2 = (int)((cw-delta)/cw*1024);
>              }
>              anchor.setCol2(col2);
>              anchor.setDx2(dx2);
> 
>              float h = 0;
>              h += (1 - (float)anchor.getDy1()/256)*
> getRowHeightInPixels(anchor.getRow1());
>              int row2 = anchor.getRow1() + 1;
>              int dy2 = 0;
> 
>              while(h < scaledHeight){
>                  h += getRowHeightInPixels(row2++);
>              }
>              if(h > scaledHeight) {
>                  row2--;
>                  double ch = getRowHeightInPixels(row2);
>                  double delta = h - scaledHeight;
>                  dy2 = (int)((ch-delta)/ch*256);
>              }
>              anchor.setRow2(row2);
>              anchor.setDy2(dy2);
> 
>              return anchor;
>          }
> 
>          public void resize(){
>              HSSFClientAnchor anchor =
> (HSSFClientAnchor)_picture.getAnchor();
>              anchor.setAnchorType(2);
> 
>              HSSFClientAnchor pref = getPreferredSize();
> 
>              int row2 = anchor.getRow1() + (pref.getRow2() -
> pref.getRow1());
>              int col2 = anchor.getCol1() + (pref.getCol2() -
> pref.getCol1());
> 
>              anchor.setCol2((short)col2);
>              anchor.setDx1(0);
>              anchor.setDx2(pref.getDx2());
> 
>              anchor.setRow2(row2);
>              anchor.setDy1(0);
>              anchor.setDy2(pref.getDy2());
>          }
>      }
> }
> 
> 
> Yegor
> 
>> 
>> I have to insert images precisely enough, so I try to use java.awt.* to
>> calculate the column width. The dpi is fixed at 96 on Windows, but the
>> default font may be changed. So I wrote the code as follows:
>> 
>> public final class HssfHelper
>> {
>> 
>>   private final static int DPI_WINDOWS_NORMAL = 96;
>>   private final static int DPI_INDUSTRY_STANDARD = 72;
>> 
>>   /**
>>    * Get default font width in points
>>    *
>>    */
>>   public static int getDefaultFontWidth(HSSFWorkbook workbook) {
>>     //get default workbook font. HSSFWorkbook.getFontAt(0) should always
>> return the default one.
>>     HSSFFont defFont = workbook.getFontAt((short)0);
>> 
>>     //cast workbook font to Java font
>>     Font font = new Font(defFont.getFontName(), Font.PLAIN,
>> defFont.getFontHeightInPoints());
>> 
>>     //get font metrics
>>     FontMetrics fontMetrics = new Label().getFontMetrics(font);
>> 
>>     //get char width
>>     fontWidth = fontMetrics.charWidth('0');
>> 
>>     fontWidth = fontWidth * DPI_WINDOWS_NORMAL / DPI_INDUSTRY_STANDARD;
>> //Normally, Windows font is larger than industry standard
>> 
>>     return fontWidth;
>>   }
>> 
>>   /**
>>    * Get column width in points
>>    *
>>    */
>>   public static int getColumnWidthInPoints(HSSFWorkbook workbook,
>> HSSFSheet
>> sheet, int colIndex) {
>>     return (int)(sheet.getColumnWidth(colIndex) *
>> getDefaultFontWidth(workbook) + 255) / 256;
>>   }
>> 
>> }
>> 
>> But this still only works with default font settings. Is there something
>> wrong of my code? Thanks for any help.
>> 
>> George
>> 
>> 
>> Yegor Kozlov wrote:
>>> I hope my belated answer is of help
>>>
>>> HSSFPicture.resize() as well as XSSFPicture.resize() indeed work only
>>> for
>>> the default font which is Arial 10pt for .xls 
>>> and Calibri 11pt for .xlsx.
>>>
>>> Excel uses a funny coordinate system to position graphic objects. X and
>>> Y
>>> axes  are measured not in pixels but in units 
>>> proportional to a character width of the default font. To properly
>>> position and size an image POI needs to translate the 
>>> actual dimensions measured in pixels to columns and rows. This is the
>>> key
>>> of the problem. At the moment POI performs 
>>> this translation using hardcoded constants obtained empirically for
>>> Arial
>>> 10pt and Calibri 11pt. It works OK in most 
>>> cases and also explains why HSSFPicture.resize() is 'off' if the default
>>> font is changed.
>>>
>>> Unfortunately it can not be easily fixed. To measure a custom font POI
>>> needs to load it (i.e. the font must be 
>>> physically available) and get the font metrics using java.awt.*
>>> utilities.
>>> It will make the result machine dependent and 
>>> impossible to test.
>>>
>>> I'm going to update javadocs on HSSFPicture.resize() and close Bug 48415
>>> as 'wontfix'
>>>
>>> Yegor
>>>
>>>> Dear all,
>>>>
>>>> As my test result, this function only works when the default font size
>>>> of
>>>> workbook not changed. If I modified its size (For example, from 12 to
>>>> 22)
>>>> and then call this function to insert an image, it stretchs
>>>> horizontally.
>>>>
>>>> Image 1 (Default font size set to 12):
>>>> http://old.nabble.com/file/p26738706/1.jpg 
>>>>
>>>> Image 2 (Default font size set to 22):
>>>> http://old.nabble.com/file/p26738706/2.jpg 
>>>>
>>>> I've checked the source code of HSSFPicture.java, function resize()
>>>> calls
>>>> another function getPixelWidth() to calculate the column width in
>>>> pixels,
>>>> but the later function only works correctly when the default font size
>>>> of
>>>> workbook not changed.
>>>>
>>>> Can somebody give me some suggestions to correct this problem? Thanks.
>>>>
>>>> George
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: [email protected]
>>> For additional commands, e-mail: [email protected]
>>>
>>>
>>>
>> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
> 
> 
> 

-- 
View this message in context: 
http://old.nabble.com/Bug-of-HSSFPicture.resize%28%29-tp26738706p26925251.html
Sent from the POI - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to