2010-02-13 2 views
10

У меня есть некоторые проблемы с вращающимися изображениями на Java с использованием класса AffineTransform.Проблемы с вращением BufferedImage

У меня есть следующий метод для создания повернуто (90 градусов) копии изображения:

private BufferedImage createRotatedCopy(BufferedImage img, Rotation rotation) { 
    int w = img.getWidth(); 
    int h = img.getHeight(); 

    BufferedImage rot = new BufferedImage(h, w, BufferedImage.TYPE_INT_RGB); 

    double theta; 
    switch (rotation) { 
     case CLOCKWISE: 
      theta = Math.PI/2; 
      break; 
     case COUNTERCLOCKWISE: 
      theta = -Math.PI/2; 
      break; 
     default: 
      throw new AssertionError(); 
    } 

    AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 
    Graphics2D g = (Graphics2D) rot.createGraphics(); 
    g.drawImage(img, xform, null); 
    g.dispose(); 

    return rot; 
} 

вращения является простым перечислением со значениями NONE, и против часовой стрелки.

Симптомы моих проблем отображаются здесь:

http://perp.se/so/rotate_problems.html

Таким образом, вращение работает нормально, но полученные изображения не привязаны к правильным координатам (или как следует положить его). И поскольку я не знаю, что, черт возьми, я делаю в первую очередь (моя линейная алгебра слаба), я не знаю, как решить это самостоятельно.

Я попытался с некоторым случайным возиться с экземпляром AffineTransform, но мне это не помогло (конечно). Я пробовал поиск в Интернете (и поиск SO), но все примеры, которые я видел, в основном используют тот же подход, что и я, который не работает для меня.

Благодарен за совет.

+1

Эквивалент вопрос для .NET: http://stackoverflow.com/questions/2225363/c-rotate-bitmap-90-degrees – finnw

ответ

16

Если вы должны выразить преобразование в один оборот, точка привязки зависит от направления вращения: либо (w/2, w/2) или (h/2, h/2).

Но, вероятно, проще выразить как translate; rotate; translate, например.

AffineTransform xform = new AffineTransform(); 
xform.translate(0.5*h, 0.5*w); 
xform.rotate(theta); 
xform.translate(-0.5*w, -0.5*h); 

рассмотреть также с использованием getQuadrantRotateInstance вместо getRotateInstance.

+0

Я получаю то, что вы говорите, и я тоже это пробовал. Однако проблема сохраняется.Они все еще нарисованы «вне» целевой области, хотя и на «другой стороне» горизонтально, так сказать. Я мог бы предоставить еще несколько скриншотов, если неясно, к чему я иду. – perp

+0

@perp, вы правы, исправлены. Я тестировал новую версию, и она работает. – finnw

+0

Работает как очарование! Думаю, я лучше понимаю, что происходит сейчас. Благодаря! – perp

0

Я не знаю, может ли это быть вашей проблемой.

AffineTransform xform = AffineTransform.getRotateInstance(theta, w/2, h/2); 

Почему бы не попробовать?

AffineTransform xform = AffineTransform.getRotateInstance(theta); 

ИЛИ

g.transform(AffineTransform.getRotateInstance(theta)); 
g.drawImage(img, 0, 0, w/2, h/2, null, null); 
+0

Я попробовал. :-) – perp

1

Вы можете попробовать альтернативное приложение и создать значок с изображения, а затем использовать Rotated Icon.

Или вы можете попробовать этот старый код, который я нашел в форумах Sun:

import java.awt.*; 
import java.awt.geom.*; 
import java.awt.image.*; 
import java.io.*; 
import java.net.*; 
import javax.imageio.*; 
import javax.swing.*; 

public class RotateImage { 
    public static void main(String[] args) throws IOException { 
     URL url = new URL("https://blogs.oracle.com/jag/resource/JagHeadshot-small.jpg"); 
     BufferedImage original = ImageIO.read(url); 
     GraphicsConfiguration gc = getDefaultConfiguration(); 
     BufferedImage rotated1 = tilt(original, -Math.PI/2, gc); 
     BufferedImage rotated2 = tilt(original, +Math.PI/4, gc); 
     BufferedImage rotated3 = tilt(original, Math.PI, gc); 
     display(original, rotated1, rotated2, rotated3); 
    } 

    public static BufferedImage tilt(BufferedImage image, double angle, GraphicsConfiguration gc) { 
     double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle)); 
     int w = image.getWidth(), h = image.getHeight(); 
     int neww = (int)Math.floor(w*cos+h*sin), newh = (int)Math.floor(h*cos+w*sin); 
     int transparency = image.getColorModel().getTransparency(); 
     BufferedImage result = gc.createCompatibleImage(neww, newh, transparency); 
     Graphics2D g = result.createGraphics(); 
     g.translate((neww-w)/2, (newh-h)/2); 
     g.rotate(angle, w/2, h/2); 
     g.drawRenderedImage(image, null); 
     return result; 
    } 

    public static GraphicsConfiguration getDefaultConfiguration() { 
     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice gd = ge.getDefaultScreenDevice(); 
     return gd.getDefaultConfiguration(); 
    } 

    public static void display(BufferedImage im1, BufferedImage im2, BufferedImage im3, BufferedImage im4) { 
     JPanel cp = new JPanel(new GridLayout(2,2)); 
     addImage(cp, im1, "original"); 
     addImage(cp, im2, "rotate -PI/2"); 
     addImage(cp, im3, "rotate +PI/4"); 
     addImage(cp, im4, "rotate PI"); 

     JFrame f = new JFrame("RotateImage"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setContentPane(cp); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    static void addImage(Container cp, BufferedImage im, String title) { 
     JLabel lbl = new JLabel(new ImageIcon(im)); 
     lbl.setBorder(BorderFactory.createTitledBorder(title)); 
     cp.add(lbl); 
    } 
} 
3

Так как вам нужно только 90 градусов вращения можно избежать, используя AffineTransform материал:

public BufferedImage rotate90DX(BufferedImage bi) { 
    int width = bi.getWidth(); 
    int height = bi.getHeight(); 
    BufferedImage biFlip = new BufferedImage(height, width, bi.getType()); 
    for(int i=0; i<width; i++) 
     for(int j=0; j<height; j++) 
      biFlip.setRGB(height-1-j, width-1-i, bi.getRGB(i, j)); 
    return biFlip; 
} 

Это также позволяет избежать отрезая края прямоугольных изображений.

От: http://snippets.dzone.com/posts/show/2936

+3

Просто голова, вынуждающая прямой доступ к значениям пикселей RGB, выводит изображение из ускоренного конвейера в Java2D. Такой подход может дать вам результат, который вы хотите, но он намного медленнее. –

+0

Aha. Не знал этого. Спасибо –

+0

Я протестировал этот код, и он не просто поворачивает изображение, он также изменяется влево и вправо (как в зеркале) – Radon8472

Смежные вопросы