Problem: We have various annotations, which are rectangles defined by the grader, floating above images (JPGs and PDFs) submitted by the student. They look like the yellow box in this image:
We want to rotate the image. This is not very difficult, but how do we rotate the annotation so that it stays over the same area of the image?
The answer is that it depends on how the coordinates of the annotation are stored. I found that the solution was much more elegant for PDFs than for JPGs. Thus, I will attempt to explain my code for rotating PDF annotations.
A PDF annotation is defined by four corner points, which are relative to the boundaries of the page. The left of the page is x=0, the right is x=PAGE_WIDTH, the top is y=0, and the bottom is y=PAGE_HEIGHT. For the above image the four sides would be defined approximately by these four values:
xleft=0.08 * PAGE_WIDTH xright=0.5 * PAGE_WIDTH ytop=0.84 * PAGE_HEIGHT ybottom=0.96 * PAGE_HEIGHT
The important point is that they are relative to the page (the JPG annotations are in screen space coordinates, which made it much messier). We can find the algorithm for rotating the annotations by visual inspection. In the following image, the red box is the annotation. Since we are only rotating the PDF by 90-degree clockwise increments, we know that:
The new ytop is the previous xleft.
The new ybottom is 1 minus the previous xright. The new xleft is 1 minus previous ybottom.
The new xright is the previous ytop.
When we rotate another 90 degrees, we just apply the same transformation again.
Now that we know how to rotate annotations, the main problem remaining is how to store the annotations in the database now that they can be rotated. My solution was to store them in unrotated form. So, if the grader rotates the PDF by 90 degrees clockwise and then makes some annotations, when the coordinates are saved, they would first be rotated 90 degrees counterclockwise. Whenever we render an annotation, we know the unrotated coordinates and the rotation of the PDF, so we can rotate the coordinates to the correct orientation using the method I described.
And so we now have rotating PDF annotations in Markus!