A Quick Snippet for Drawing Images in Java

Java does not have the best built-in tools in the world for drawing images, but it’s still useful for many purposes. Below is just a snippet on getting started drawing in Java. For more information on what’s available see the Java Graphics class reference.

BufferedImage i = new BufferedImage(500, 500,BufferedImage.TYPE_INT_RGB);
Graphics g=i.createGraphics();
g.setColor(Color.BLUE);
g.drawLine(0, 0, 500, 500);
g.drawString("This is a test", 20,20);
ImageIO.write(i,"jpg",new File("test.jpg");

A basic 3d to 2d projection

Developing an actual 3D engine is an incredible amount of work, and including a 3D library in your project can add a considerable amount of bloat to your project. Fortunately you can implement some very simple 3D projections in just a couple of lines of code, and they are not computationally intensive. There are limitations on using this particular method though:

  • This can draw wire frames only.
  • You need all of the coordinates of your “world” to be centered horizontally and vertically relative to your screen (or you need to convert them to be that way).
  • All of the lines must fit on the screen (e.g. you can’t have the edge of an object partially off-screen)

The basic algorithm is incredibly simple. For each given point (x,y,z) in your 3D model, you convert it to 2D screen coordinates (x’,y’) by the following equations:

x'=d*x/z
y'=d*y/z

Where (x,y,z) are the points in your 3D world, (x’,y’) are the x,y coordinates from the center of your screen. And d is the focal length of the camera (or scaling factor), if you’re not sure what to use you can get good results just by experimenting.

Below is C# code to demonstrate this concept. Notice that most of the code is for manipulating, offsetting, and scaling the box, the actual code projecting to 2D is only two lines.

        protected override void OnPaint(PaintEventArgs e) 
        {
            float[]  box = {
                            -1,-1,0,
                            1,-1,0,
                            1,1,0,
                            -1,1,0,
                            -1,-1,0,
                            -1,-1,2,
                            1,-1,2,
                            1,-1,0,
                            1,-1,2,
                            1,1,2,
                            1,1,0,
                            1,1,2,
                            -1,1,2,
                            -1,1,0,
                            -1,1,2,
                            -1,-1,2
                         };
            base.OnPaint(e);

            float scale = .2f;
            for (int x = 0; x < box.Length; x++) box[x] *= scale;

            for (int j = 0; j < 10; j++)
            {
                for (int k = 0; k < 10; k++)
                {
                    float zoffset = 10f;
                    float xoffset = 1f*(j-5);
                    float yoffset = 1f*(k-5);

                    float d = 500;
                    float lastX = d * (box[0] + xoffset) / (box[2] + zoffset);
                    float lastY = d * (box[1] + yoffset) / (box[2] + zoffset);

                    Pen p = new Pen(new SolidBrush(ForeColor));
                    int i = 3;
                    while (i < box.Length)
                    {
                        float x = d * (box[i + 0] + xoffset) / (box[i + 2] + zoffset);
                        float y = d * (box[i + 1] + yoffset) / (box[i + 2] + zoffset);
                        e.Graphics.DrawLine(p, translate(new PointF(lastX, lastY)), translate(new PointF(x, y)));
                        lastX = x;
                        lastY = y;

                        i += 3;
                    }
                }
            }
            

        }

        private PointF translate(PointF p)
        {
            PointF f = new PointF(p.X+this.Width/2, p.Y+this.Height/2);
            return f;
        }
    }

3D Projection example

This is a very useful technique for drawing diagrams and simple objects, and can be a starting point for adding more features like rotation, or solids.

Android: Accessing other views from inside a custom view using findViewById().

If you attempt to call findViewById() on the ID of a view that is not from the Activity that holds the view, findViewById() returns null. I’ve seen a lot of solutions posted for attempting to access a View from outside the activity that created it. Most of them involve inflating the original view and going from there. I can’t speak to whether or not that actually works (I do not believe they will), but I can offer an alternative, more attractive solution.

For this option, you will need a reference to the activity that holds the view you want to modify, this is usually given to you in the form of a Context object passed into your constructor. You can save that context in a member variable, and from there call context.findViewById(), which will return the view you want.

public class SomeClass extends View{
     Context context;
     ...

     public SomeClass(Context context, AttributeSet attrSet){
          super(context,attrSet);
          this.context=context;
          ...
     }

     public void someFunction(){
          TextView t=(TextView)context.findViewById(R.id.someTextView);
          ...
     }
}

In many cases, it will be preferable to not access the View directly, and instead add a public function to the Activity that actually holds the view. This way many other classes will be able to access the same function, which is very often necessary. Then, in order to access that function, you cast the Context to the Activity Class that holds the view:

public class SomeClass extends View{
     Context context;
     ...

     public SomeClass(Context context, AttributeSet attrSet){
          super(context,attrSet);
          this.context=context;
          ...
     }

     public void someFunction(){
          ((MyActivity)context).manipulateSomeViews();
          ...
     }
}

I would say the second example is a much more elegant solution as it keeps the logic controlling a View inside the class that holds it. But, as with everything, you’ll likely find many exceptions.