0

アプリで非常に大きな.png画像を生成します (たとえば、40000x10000 ピクセル)。過度のメモリ使用を避けるために、ImageIO行ごとに書き込むという事実を利用したため、一度にメモリに保持する必要があるのは 40000 ピクセルだけです (実際にはもう少し多くの 100 行を保持しますが、まだ完全な画像ではありません)。

その後、次のコードを使用して POI ワークブックに画像を追加します。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
int pictureIdx = workbook.addPicture(baos.toByteArray, Workbook.PICTURE_TYPE_PNG);
CreationHelper helper = workbook.getCreationHelper();
Sheet sh = workbook.createSheet("Picture");
Drawing patriarch = sh.createDrawingPatriarch();
ClientAnchort anchor = helper.createClientAnchor();
anchor.setCol1(0);
anchor.setRow1(0);
Picture picture = patriarch.createPicture(anchor, pictureIdx);
picture.resize(); // here's the trouble :(

ここpicture.resize()での最大の問題は呼び出しです。「優先」画像サイズを決定するために、画像全体をメモリにロードしようとします。この例の画像は、非圧縮時に最大 1.6GB のメモリを消費します。一部のユーザー マシンで 1.6GB のメモリを割り当てようとすると、OOM 例外が発生します。

への呼び出しを省略した場合picture.resize()、画像は結果の xls に表示されません。サイズから判断すると、ファイル内にありますが、表には表示されません。

イメージ全体のメモリへのロードをスキップする方法はありますか? Pictureに好みの画像サイズを手動で指定できますか?

4

1 に答える 1

1

この問題を回避する方法を見つけました。基本的には、POI ソースからコードをコピーし、getImageDimension(). このコードは HSSF の内部について過度に想定しているため、更新中に壊れる可能性があることに注意してください。

以下は私の解決策です(スカラ構文):

/** Applies resizing to HSSFPicture - without loading the whole image into memory. */
private def safeResize(pic: HSSFPicture, width: Double, height: Double, sheet: HSSFSheet) {
  val anchor = pic.getAnchor.asInstanceOf[HSSFClientAnchor]
  anchor.setAnchorType(2)
  val pref: HSSFClientAnchor = {
    val PX_DEFAULT = 32f
    val PX_MODIFIED = 36.56f
    val PX_ROW = 15
    def getPixelWidth(column: Int): Float = {
      val default = sheet.getDefaultColumnWidth*256
      val cw = sheet.getColumnWidth(column)
      if (default == cw) PX_DEFAULT else PX_MODIFIED
    }
    def getColumnWidthInPixels(column: Int): Float = {
      val cw = sheet.getColumnWidth(column)
      cw / getPixelWidth(column)
    }
    def getRowHeightInPixels(i: Int): Float = {
      val row = sheet.getRow(i)
      val height: Float = if (row != null) row.getHeight else sheet.getDefaultRowHeight
      height / PX_ROW
    }

    var w = 0f
    //space in the leftmost cell
    w += getColumnWidthInPixels(anchor.getCol1)*(1 - anchor.getDx1.toFloat/1024)
    var col2 = (anchor.getCol1 + 1).toShort
    var dx2 = 0
    while(w < width){
      w += getColumnWidthInPixels(col2)
      col2 = (col2 + 1).toShort
    }
    if (w > width) {
      //calculate dx2, offset in the rightmost cell
      col2 = (col2 - 1).toShort
      val cw = getColumnWidthInPixels(col2)
      val delta = w - width
      dx2 = ((cw-delta)/cw*1024).toInt
    }

    anchor.setCol2(col2)
    anchor.setDx2(dx2)

    var h = 0f
    h += (1 - anchor.getDy1.toFloat/256)* getRowHeightInPixels(anchor.getRow1)
    var row2 = anchor.getRow1 + 1
    var dy2 = 0
    while (h < height){
      h += getRowHeightInPixels(row2)
      row2+=1
    }
    if(h > height) {
      row2-=1
      val ch = getRowHeightInPixels(row2)
      val delta = h - height
      dy2 = ((ch-delta)/ch*256).toInt
    }
    anchor.setRow2(row2)
    anchor.setDy2(dy2)

    anchor
  }

  val row2 = anchor.getRow1 + (pref.getRow2 - pref.getRow1)
  val col2 = anchor.getCol1 + (pref.getCol2 - pref.getCol1)

  anchor.setCol2(col2.toShort)
  anchor.setDx1(0)
  anchor.setDx2(pref.getDx2)

  anchor.setRow2(row2)
  anchor.setDy1(0)
  anchor.setDy2(pref.getDy2)
}
于 2013-08-15T07:42:53.293 に答える