• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:Iconを回転する
#navi(../)
RIGHT:Posted by [[aterai]] at 2012-06-11
#tags(Icon, AffineTransform)
RIGHT:Posted by &author(aterai); at 2012-06-11
*Iconを回転する [#oa0e79cb]
画像ファイルから90、180、270度回転したIconを作成します。
画像ファイルから90、180、270度回転した``Icon``を作成します。

-&jnlp;
-&jar;
-&zip;

//#screenshot
#ref(https://lh4.googleusercontent.com/-OK_vUTiAiCA/T9WIzXvRm9I/AAAAAAAABNk/ubus049qH04/s800/RotatedIcon.png)

**サンプルコード [#gaa350d7]
#code(link){{
class RotateIcon implements Icon {
class RotateIcon implements Icon{
  private int width, height;
  private Image image;
  private AffineTransform trans;
  public RotateIcon(Icon icon, int rotate) {
    image = new BufferedImage(
      icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
    if((rotate%90)!=0) {
      throw new IllegalArgumentException(
        rotate + ": Rotate must be (rotate % 90 == 0)");
    }

    width  = icon.getIconWidth();
    height = icon.getIconHeight();
    image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics g = image.getGraphics();
    icon.paintIcon(null, g, 0, 0);
    g.dispose();

    width  = icon.getIconWidth();
    height = icon.getIconHeight();
    if((rotate+360)%360==90) {
    int numquadrants = (rotate / 90) % 4;
    if(numquadrants==1 || numquadrants==-3) {
      trans = AffineTransform.getTranslateInstance(height, 0);
      trans.rotate(Math.toRadians(90)); //== trans.quadrantRotate(1);
    }else if((rotate+360)%360==270) {
      int v = width; width = height; height = v;
    }else if(numquadrants==-1 || numquadrants==3) {
      trans = AffineTransform.getTranslateInstance(0, width);
      trans.rotate(Math.toRadians(270)); //== trans.quadrantRotate(-1);
    }else if((rotate+360)%360==180) {
      //trans = AffineTransform.getTranslateInstance(width, height);
      //trans.rotate(Math.toRadians(180));
      trans = AffineTransform.getScaleInstance(1.0, -1.0);
      trans.translate(0, -height);
      width  = icon.getIconHeight();
      height = icon.getIconWidth();
      int v = width; width = height; height = v;
    }else if(Math.abs(numquadrants)==2) {
      trans = AffineTransform.getTranslateInstance(width, height);
    }else{
      throw new IllegalArgumentException("Rotate must be (rotate % 90 == 0)");
      trans = AffineTransform.getTranslateInstance(0, 0);
    }
    trans.quadrantRotate(numquadrants);
  }
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D)g.create();
    g2.translate(x, y);
    g2.drawImage(image, trans, c);
    g2.translate(-x, -y);
    g2.dispose();
  }
  @Override public int getIconWidth()  {
    return height;
    return width;
  }
  @Override public int getIconHeight() {
    return width;
    return height;
  }
}
}}

**解説 [#v278afec]
- Default
- ``Default``
-- 幅高さ: 83x100
- Rotate: 180
- ``Rotate``: 180
-- 幅高さ: 83x100 
-- 上下反転: [[AffineTransformOpで画像を反転する>Swing/AffineTransformOp]]
- Rotate: 90(時計回りに90度)
-- 上下反転と同等: [[AffineTransformOpで画像を反転する>Swing/AffineTransformOp]]
- ``Rotate``: 90(時計回りに90度)
-- 幅高さ: 100x83(元画像の幅高さを入れ替え)
-- 左上を原点に90度回転し、元画像の高さだけX軸プラス方向に移動
- Rotate: -90(反時計回りに90度)
- ``Rotate``: -90(反時計回りに90度)
-- 幅高さ: 100x83(元画像の幅高さを入れ替え)
-- 左上を原点に270度回転し、元画像の幅だけY軸プラス方向に移動

----
以下のような方法もあります。
#code{{
enum QuadrantRotate {
  CLOCKWISE(1),
  VERTICAL_FLIP(2),
  COUNTER_CLOCKWISE(-1);
  private final int numquadrants;
  private QuadrantRotate(int numquadrants) {
    this.numquadrants = numquadrants;
  }
  public int getNumQuadrants() {
    return numquadrants;
  }
}
class QuadrantRotateIcon implements Icon{
  private final QuadrantRotate rotate;
  private final Icon icon;
  public QuadrantRotateIcon(Icon icon, QuadrantRotate rotate) {
    this.icon = icon;
    this.rotate = rotate;
  }
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    int w = icon.getIconWidth();
    int h = icon.getIconHeight();
    Graphics2D g2 = (Graphics2D)g.create();
    g2.translate(x, y);
    switch(rotate) {
      case CLOCKWISE:         g2.translate(h, 0); break;
      case VERTICAL_FLIP:     g2.translate(w, h); break;
      case COUNTER_CLOCKWISE: g2.translate(0, w); break;
    }
    g2.rotate(Math.toRadians(90*rotate.getNumQuadrants()));
    icon.paintIcon(c, g2, 0, 0);
    g2.dispose();
  }
  @Override public int getIconWidth()  {
    return rotate==QuadrantRotate.VERTICAL_FLIP
      ? icon.getIconWidth() : icon.getIconHeight();
  }
  @Override public int getIconHeight() {
    return rotate==QuadrantRotate.VERTICAL_FLIP
      ? icon.getIconHeight() : icon.getIconWidth();
  }
}
}}

**参考リンク [#g40193cd]
- [http://duke.kenai.com/iconSized/index.html Duke Images: iconSized]
- [[AffineTransformOpで画像を反転する>Swing/AffineTransformOp]]
- [[Mouseで画像を移動、回転>Swing/MouseDrivenImageRotation]]

**コメント [#r9e710fd]
#comment