1. giovannicavalli's Avatar
    Hi everybody.

    I've been trying to rotate an image for a few days without success. I searched other forums as well but still did not found what i wanted.

    So can someone please create a tiny program that rotates a bitmap at any given angle.

    Thanks very much.
    11-06-10 09:49 AM
  2. Thud Hardsmack's Avatar
    Hi everybody.

    I've been trying to rotate an image for a few days without success. I searched other forums as well but still did not found what i wanted.

    So can someone please create a tiny program that rotates a bitmap at any given angle.

    Thanks very much.
    What exactly are you trying to do that a PC/Mac can't do?
    11-06-10 11:47 AM
  3. giovannicavalli's Avatar
    What exactly are you trying to do that a PC/Mac can't do?
    let me ask my question again:

    I have the following method:

    Code:
    public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
        {
            int w = oldB.getWidth();
            int h = oldB.getHeight();
            
            double angRad = (angle % 360)*(Math.PI/180);
            Bitmap newB = new Bitmap(w,h);
            
            int[] oldD = new int[w*h];
            int[] newD = new int[w*h];
            
            oldB.getARGB(oldD, 0, w, 0, 0, w, h);
            
            int axisX = w/2;
            int axisY = h/2;
            
            for(int x = 0; x < oldD.length; x++)
            {
                int oldX = x%w;
                int oldY = x/w;
                int op = oldX-axisX;
                int adj = oldY-axisY;
                
                double oldT = MathUtilities.atan2(op, adj);
                double rad = Math.sqrt((op*op)+(adj*adj));
                double newT = oldT+angRad;
                
                int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
                int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
                
                if(newX<0||newY<0||newX>=w||newY>=h)
                {
                    newD[x] = 0x00000000;
                }
                else
                {
                    newD[x] = oldD[(newY*w)+newX];
                }
            }
            
            newB.setARGB(newD, 0, w, 0, 0, w, h);
            return newB;
        }
    And I am using it like this:

    Code:
    rotateImage(givenImage, 90);
    It is not doing anything. Can someone please tell me why? Or kindly post a better solution?
    Thanks very much.
    11-06-10 03:28 PM
  4. Thud Hardsmack's Avatar
    let me ask my question again:

    I have the following method:

    Code:
    public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
        {
            int w = oldB.getWidth();
            int h = oldB.getHeight();
            
            double angRad = (angle % 360)*(Math.PI/180);
            Bitmap newB = new Bitmap(w,h);
            
            int[] oldD = new int[w*h];
            int[] newD = new int[w*h];
            
            oldB.getARGB(oldD, 0, w, 0, 0, w, h);
            
            int axisX = w/2;
            int axisY = h/2;
            
            for(int x = 0; x < oldD.length; x++)
            {
                int oldX = x%w;
                int oldY = x/w;
                int op = oldX-axisX;
                int adj = oldY-axisY;
                
                double oldT = MathUtilities.atan2(op, adj);
                double rad = Math.sqrt((op*op)+(adj*adj));
                double newT = oldT+angRad;
                
                int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
                int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
                
                if(newX<0||newY<0||newX>=w||newY>=h)
                {
                    newD[x] = 0x00000000;
                }
                else
                {
                    newD[x] = oldD[(newY*w)+newX];
                }
            }
    N        
            newB.setARGB(newD, 0, w, 0, 0, w, h);
            return newB;
        }
    And I am using it like this:

    Code:
    rotateImage(givenImage, 90);
    It is not doing anything. Can someone please tell me why? Or kindly post a better solution?
    Thanks very much.
    That explains a bit better; rotating a bitmap anyone can do with an image editor. Coding it to rotate is beyond me, I've never had any success beyond making turtles in BASIC.
    11-06-10 03:42 PM
  5. phone9's Avatar
    There's no reason to get into all that if you just want to rotate by right angles. Just copy rows to columns, and use nested Y and X loops instead of wasting time doing modulo and division, they're slow. Counting down instead of up is also faster since you're comparing to 0 instead of a variable. To rotate by any angle, you'd have to do cubic or at least linear interpolation instead of rounding to nearest, or it will be full of aliasing distortion. Too tired right now to figure out why what you have is doing nothing, have you tried stepping through?
    Last edited by LSphone; 11-07-10 at 01:56 AM.
    11-07-10 01:46 AM
  6. giovannicavalli's Avatar
    right, here is the complete code. there are two java files and one image:

    Code:
    /**
     * AnimationScreen.java
     *
     * Author:  Mark Sohm
     *
     */
    
    package com.msohm.animationDemo;
    
    import net.rim.device.api.system.Bitmap;
    import net.rim.device.api.ui.container.FullScreen;
    import net.rim.device.api.ui.Graphics;
    import net.rim.device.api.system.Characters;
    import net.rim.device.api.ui.UiApplication;
    import java.util.Date;
    import net.rim.device.api.ui.component.Dialog;
    import net.rim.device.api.system.Alert;
    import net.rim.device.api.util.MathUtilities;
    
    
    //Optimized avg fps 7100 = 34, 7290 sim = 51 - this wasn't so good after all.  :)
    //Non optimized (draw house/sun, no clearAll) avg fps 7100 = 17, 7290 sim = 51
    //Non optimized (using invalidate, no _drawHouse = false) avg fps 7100 = 25, 7290 sim = 51
    //Non optimized (using invalidate, no _drawHouse = false, not overriding paintBackground) avg fps 7100 = 25, 7290 sim = 51
    // - but without overriding it things have to be redrawn every time.
    //Can't test with just using invalidate vs calling paint directly or else
    //the entire screen is cleared.
    //Optimized (using invalidate(#, #, #, #), not overriding paintBackground, no clearAll, _drawHouse/sun) 
    //  avg fps 7100 = 51, 7290 sim = 51
    //Optimized using invalidate(####), using _drawHouse saves ~ 400 ms per animation vs no _drawHouse.
    
    public class AnimationScreen extends FullScreen
    {
        
        private final static boolean SHOW_FRAMERATE = true;  //Controls the showing of the framerate dialog.
        
        //Images.
    
        private final static Bitmap brick = Bitmap.getBitmapResource("brick.png");
        
        private int _frameNo;  //The current frame number.    
        private int _runnerXVal;  //X coordinate of the runner.
        private int _runnerFrame;  //The current frame of the runner.
        private boolean _currentlyAnimating;  //Set to true if an animation is in progress.
        
        //Boolean variables to control what is drawn on the screen.
        private boolean _drawRunner;
        
        public AnimationScreen()
        {
            super();
            initialize();
        }
        
        //Initialize variables to their starting values.
        private void initialize()
        {
            _drawRunner = true;
            _frameNo = 0;
            _runnerFrame = 0;
            
            //Draw the screen in its initial state.
            invalidate();
        }
        
        private class AnimationThread extends Thread
        {
            
            Date rightNow = new Date();
            long animTime;
            int fps;
            int tempY = Graphics.getScreenHeight() - 50;        
    
                
            public void run()
            {
                int count;
                
                //Sleep 50ms to allow the invalidate method in the initialize method to fully execute.
                //This ensures that the screen is fully redrawn in its initial state before
                //this thread starts modifying drawing values, otherwise we'll see frames out of sync.
                try
                {
                    sleep(50);
                }
                catch (Exception ex)
                {
                    System.out.println("Couldn't sleep!");
                }
    
                //Get the start time for the animation (FPS timer).
                animTime = rightNow.getTime();
                
                _frameNo = 0;
    
                UiApplication.getUiApplication().invokeAndWait(new Runnable() {
                    public void run() 
                    {
                        //We want to clear the entire screen so call invalidate
                        //instead of invalidate(#, #, #, #).
                        invalidate();
                        ++_frameNo;
    
                    }
                });
    
                //Draw the house with the door open.
                //We don't need to obtain an event lock when using invalidate(#, #, #, #);
                invalidate(170, tempY, 5, 40);
    
                //Draw the person running out of the house.
                _drawRunner = true;
             
                //If show framerate is enabled calculate and display
                //the freamrate.
                if(SHOW_FRAMERATE)
                {
                    //Reset the time.
                    rightNow = new Date();
        
                    //Calculate the number of seconds the animation animated for.
                    //We selpt for 2710 ms so subtract that value from the total time.
                    animTime = (rightNow.getTime() - animTime) - 2910;
                    
                    //Ensure we don't divide by 0.
                    if ((animTime / 1000) > 0)
                    {
                        //If the animation took longer than a second, calculate it.
                        fps = (int)(_frameNo / (animTime / 1000));
                    }
                    else
                    {
                        //Otherwise assume 1 second.
                        fps = _frameNo;
                    }
                    
                    //Display the frames per second.
                    UiApplication.getUiApplication().invokeLater(new Runnable() {
                        public void run() 
                        {
                                                        
                            Dialog.alert("Animation time: " + animTime + " ms.\nAvg FPS: " + fps);
        
                        }
                    });
                }
                
                //Animation is over.
                _currentlyAnimating = false;
            }
            
        }
    
         public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
        {
            int w = oldB.getWidth();
            int h = oldB.getHeight();
            
            double angRad = (angle % 360)*(Math.PI/180);
            Bitmap newB = new Bitmap(w,h);
            
            int[] oldD = new int[w*h];
            int[] newD = new int[w*h];
            
            oldB.getARGB(oldD, 0, w, 0, 0, w, h);
            
            int axisX = w/2;
            int axisY = h/2;
            
            for(int x = 0; x < oldD.length; x++)
            {
                int oldX = x%w;
                int oldY = x/w;
                int op = oldX-axisX;
                int adj = oldY-axisY;
                
                double oldT = MathUtilities.atan2(op, adj);
                double rad = Math.sqrt((op*op)+(adj*adj));
                double newT = oldT+angRad;
                
                int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
                int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
                
                if(newX<0||newY<0||newX>=w||newY>=h)
                {
                    newD[x] = 0x00000000;
                }
                else
                {
                    newD[x] = oldD[(newY*w)+newX];
                }
            }
            
            newB.setARGB(newD, 0, w, 0, 0, w, h);
            
            return newB;
        }
    
        //Let's paint!
        protected void paint(Graphics graphics)
        {
    
            //Get the screen resolution.
            int width = Graphics.getScreenWidth();
            int height = Graphics.getScreenHeight();
            
            //Counters for the for loops.
            int count, count2;
            
            //Variables to hold temporary x and y values.
            //Storing these in a defined variable is more efficent
            //then calculating them inline as the inline calculation
            //will create a temporary int variable for each calculation.
            //This would result in the creation of a lot of garbage.
            int tempX, tempY;
    
            if (_drawRunner)
            {
                
                try{
                rotateImage(brick, 59);
            }catch (Exception ex) {
                ex.printStackTrace();
            }
                graphics.drawBitmap(width-30, height-60, 20, 10, brick, 0, 0);
                
            } //end if (_drawRunner)
            
        } //end paint
            
        //Invoked when the trackwheel is clicked.
        public boolean trackwheelClick(int status, int time) 
        {
            boolean retVal = false;
            
            //Only start the animation if one is not in progress.
            if (!_currentlyAnimating)
            {
                _currentlyAnimating = true;
                initialize();
                AnimationThread animationThread = new AnimationThread();
                animationThread.start();
                retVal = true;
            }
            
            return retVal;
        }
        
        //Invoked when the trackwheel is released.
        public boolean trackwheelUnclick(int status, int time) 
        {
            return false;
        }
        
        //Invoked when the trackwheel is rolled.
        public boolean trackwheelRoll(int amount, int status, int time) 
        {
            return false;
        }
        
        //Invoked when a key is pressed.
        public boolean keyChar(char key, int status, int time) 
        {
            boolean retVal = false;
            int tempY = Graphics.getScreenHeight() - 50;
            
            switch (key)
            {
                case Characters.ESCAPE:
                    System.exit(0);
                    retVal = true;
                break;
                
                case Characters.ENTER:
                case Characters.SPACE:
                    //Only start the animation if one is not in progress.
                    if (!_currentlyAnimating)
                    {
                        _currentlyAnimating = true;
                        initialize();
                        AnimationThread animationThread = new AnimationThread();
                        animationThread.start();
                        retVal = true;
                    }
                break;
                
                default:
                break;
            }
                     
            return retVal;
        }
    
        //Implementation of KeyListener.keyStatus.
        public boolean keyStatus(int keycode, int time) 
        {
           return false;
        }
    
        //Implementation of KeyListener.keyDown.
        public boolean keyDown(int keycode, int time) 
        {
           return false;
        }
       
        //Implementation of KeyListener.keyRepeat.
        public boolean keyRepeat(int keycode, int time) 
        {
           return false;
        } 
        
        //Implementation of KeyListener.keyUp.
        public boolean keyUp(int keycode, int time) 
        {
           return false;
        }
        
    }
    This is the other java file:

    Code:
    package com.msohm.animationDemo;
    
    import net.rim.device.api.ui.*;
    import net.rim.device.api.ui.component.*;
    import net.rim.device.api.ui.container.*;
    import net.rim.device.api.system.*;
    import net.rim.device.api.util.*;
    import java.util.*;
    
    public class AnimationDemo extends UiApplication
    {
        
        //The application enters the event thread by invoking the enterEventDispatcher method.
        public static void main(String[] args)
        {
            AnimationDemo theApp = new AnimationDemo();
            theApp.enterEventDispatcher();
        }
    
        public AnimationDemo()
        {
            
            AnimationScreen animScreen = new AnimationScreen();
            
            pushScreen(animScreen);
            
        }
        
    }
    I attached the png file as well. Now, in the AnimationScreen.java file (the first one) you can find the following code:

    Code:
     public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
        {
            int w = oldB.getWidth();
            int h = oldB.getHeight();
            
            double angRad = (angle % 360)*(Math.PI/180);
            Bitmap newB = new Bitmap(w,h);
            
            int[] oldD = new int[w*h];
            int[] newD = new int[w*h];
            
            oldB.getARGB(oldD, 0, w, 0, 0, w, h);
            
            int axisX = w/2;
            int axisY = h/2;
            
            for(int x = 0; x < oldD.length; x++)
            {
                int oldX = x%w;
                int oldY = x/w;
                int op = oldX-axisX;
                int adj = oldY-axisY;
                
                double oldT = MathUtilities.atan2(op, adj);
                double rad = Math.sqrt((op*op)+(adj*adj));
                double newT = oldT+angRad;
                
                int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
                int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
                
                if(newX<0||newY<0||newX>=w||newY>=h)
                {
                    newD[x] = 0x00000000;
                }
                else
                {
                    newD[x] = oldD[(newY*w)+newX];
                }
            }
            
            newB.setARGB(newD, 0, w, 0, 0, w, h);
            
            return newB;
        }
    And I am using this method inside the paint method:

    Code:
    try{
                rotateImage(brick, 59);
            }catch (Exception ex) {
                ex.printStackTrace();
            }
                graphics.drawBitmap(width-30, height-60, 20, 10, brick, 0, 0);
    The problem: the brick file is not rotating by a given angle. So what am I doing wrong?

    Thanks.
    11-07-10 06:38 AM
  7. phone9's Avatar
    What happens when you step through a call to the rotation?

    Are you getting any image at all out of it? Garbage? The original image?
    11-08-10 09:03 PM
  8. Chaoss's Avatar
    I didn't look at your code, but you can rotate an image using an SVGElement

    I used something like this to rotate a gps map

    private SVGImage _image;
    private SVGMatrix imageTransform;

    Document document = _image.getDocument();
    _indicatorElement = (SVGElement)document.createElementNS(SVG_NAMESPACE _URI, "image");
    imageTransform = _indicatorElement.getMatrixTrait("transform");
    imageTransform.mRotate((float)(-currentHeading));
    _indicatorElement.setMatrixTrait("transform",image Transform);

    edit: (there should not be a space between imageTransform, it's not showing in the post preview)
    Last edited by Chaoss; 11-08-10 at 09:37 PM.
    11-08-10 09:33 PM
  9. giovannicavalli's Avatar
    Thanks for your reply guys.

    @LSphone:
    When I run it on the BB-Simulator, it shows the original image (does not rotate).

    @Chaoss:
    Do I have to specify the location here: private SVGImage _image; And where do I specify the rotation angle in your code?
    11-10-10 11:30 AM
  10. Chaoss's Avatar
    set your rotation angle here
    imageTransform.mRotate((float)( rotation_angle_goes_here ));

    Play with the svgcldcdemo sample app or the other svg demos included with the jde, you should be able to take one of the existing elements in these samples and spin them around
    11-10-10 09:17 PM
  11. Chaoss's Avatar
    sample program to spin a png image, example uses a 120px square png image


    package spin;

    import net.rim.device.api.ui.*;
    import net.rim.device.api.system.Display;
    import net.rim.device.api.ui.container.*;
    import java.lang.Runnable;
    import javax.microedition.m2g.*;
    import org.w3c.dom.*;
    import org.w3c.dom.svg.*;

    final class spin extends UiApplication {
    spin() {
    Screen screen = new Screen();
    pushScreen(screen);
    }
    public static void main(String[] args) throws Exception {
    spin app = new spin();
    app.enterEventDispatcher();
    }
    }

    class Screen extends MainScreen {
    private SVGImage _image;
    private ScalableGraphics sg;
    private SVGElement svgElement, _brickElement;
    private SVGMatrix transform, imageTransform;
    private double angle;
    private UiApplication UiApp;

    private static final String SVG_NAMESPACE_URI = "http://www.w3.org/2000/svg";
    private static final String XLINK_NAMESPACE_URI = "http://www.w3.org/1999/xlink";

    Screen() {
    UiApp = spin.getUiApplication();
    int _screenWidth = Display.getWidth();
    int _screenHeight = Display.getHeight();

    _image = SVGImage.createEmptyImage(null);
    Document document = _image.getDocument();
    svgElement = (SVGSVGElement)document.getDocumentElement();
    svgElement.setFloatTrait("width", _screenWidth);
    svgElement.setFloatTrait("height", _screenHeight);

    sg = ScalableGraphics.createInstance();
    sg.setRenderingQuality(sg.RENDERING_QUALITY_HIGH);

    _image.setViewportWidth(_screenWidth);
    _image.setViewportHeight(_screenHeight - 64); //room for tab bar

    _brickElement = (SVGElement)document.createElementNS(SVG_NAMESPACE _URI, "image");
    _brickElement.setId("brickElement");
    _brickElement.setTraitNS(XLINK_NAMESPACE_URI, "href", "brick.png");

    _brickElement.setFloatTrait("x", -60); //set center of element...
    _brickElement.setFloatTrait("y", -60); // to half image size
    _brickElement.setFloatTrait("width", 120); //set element size = image size
    _brickElement.setFloatTrait("height", 120);

    transform = svgElement.getMatrixTrait("transform");
    transform.mTranslate(80,80); //set position of element on screen
    _brickElement.setMatrixTrait("transform",transform );
    svgElement.appendChild(_brickElement);

    angle = 1; // degrees to rotate

    //rotate element every second
    Runnable spinBrick = new Runnable() {
    public void run() {
    imageTransform = _brickElement.getMatrixTrait("transform");
    imageTransform.mRotate((float)(angle));
    _brickElement.setMatrixTrait("transform",imageTran sform);
    invalidate();
    }};
    UiApp.invokeLater(spinBrick, 1, true);
    }

    protected void paint( Graphics graphics ) {
    graphics.setBackgroundColor(Color.BLACK);
    graphics.clear();
    subpaint( graphics );

    sg.bindTarget(graphics);
    sg.render(100, 100, _image);
    sg.releaseTarget();
    }
    }

    edit: sorry bout the formatting, I'm new to the intertubes
    Last edited by Chaoss; 11-11-10 at 09:07 PM.
    11-11-10 09:03 PM
  12. giovannicavalli's Avatar
    Thanks very much for your effort, Chaoss. I solved the problem in other way.
    11-12-10 12:03 PM
LINK TO POST COPIED TO CLIPBOARD