I am developing an application with iText 7 (7.1.14) to write a text on the top right of existing PDFs.
I have a problem with rotated pages, example 90, 270.
I tried to apply AffineTransform.getRotateInstance to canvas but nothing.
PdfFont bf = PdfFontFactory.createFont(FontConstants.HELVETICA);
float stringWidth = bf.getWidth(stringa,fontSize);
PdfCanvas canvas=new PdfCanvas(page, true);
float centeredPosition = pageSize.getWidth() - (pageSize.getWidth()/30);
float yCoord = (pageSize.getHeight()-fontSize-5);
float xCoord = centeredPosition-stringWidth;
canvas.beginText().setFontAndSize(bf, fontSize)
.moveText(xCoord, yCoord)
.showText(stringa)
.setTextRenderingMode(pageN)
.endText();
You want to add text that is displayed at the top right of the page, even after page rotation has been applied to the page.
Make sure you get the page size with the rotation taken into account, so your coordinate calculations are correct for the rotated page:
Rectangle pageSize = page.getPageSizeWithRotation();
For an A4 page with 90 degree rotation, for example, this returns 842x595 instead of 595x842.
Then "ignore" the page rotation when adding new content:
page.setIgnorePageRotationForContent(true);
This essentially applies the appropriate counterrotation for the added text, which cancels out the page rotation, so the text is seemingly not rotated.
Related
What do I want to achieve ?
I'd like to achieve an effect in Unity3D, where I superpose a few cameras on top of each other. Each cameras would draw to a specific area of the screen. If possible, I'd like these areas to change dynamically.
I am using unity (latest version), and URP.
How technically I see it :
For implementation and performances reasons, it seems writing to the stencil buffer is the way to go. That way, I can only render what part of the screen I want for each camera. It is also quite easy once the stencil is made, cause the ForwardRendering settings in Unity offer such capabilities out of the box.
What I can't figure out :
The problem is, I don't know to efficiently write to the whole stencil buffer (each frame). The best way would be to use a compute shader (or maybe a simple script), that directly write the values after some calculations. Is there a way for that ? If yes, How ?
Another alternative may be to use a transparent quad in front of one of each camera, and to write to the stencil buffers like that. But 1) It seems there exist a SV_StencilRef keyword in the fragment buffer, but not supported by Unity yet ? 2) I will still lose performance nevertheless.
Thanks for any help / ideas about how to tackle this problem.
Edit (Clarification) : I'd like to be able to render free shapes, and not only rects, which prevent the use of the standard ViewportRect.
After some search, I found the Voronoi split screen to be quite similar (with a technical view) to what I'd like to achieve (See here)
If I understand correctly, you only need to play with the different camera Viewport Rect (https://docs.unity3d.com/ScriptReference/Camera-rect.html) to determine what camera should render what part of the screen.
Response to comment: no, it's not stretched. Here is an example with four cameras:
Create a scene with four cameras, add this script to it and add the cameras to the array on the script. I added the _movingObject just to see something moving, but it's not necessary.
using UnityEngine;
public class CameraHandler : MonoBehaviour
{
[SerializeField] private Transform _movingObject;
[SerializeField] private float _posMod = 10.0f;
[SerializeField] private float _cameraPosMod = 0.1f;
[SerializeField] private Camera[] _cameras;
private void Update()
{
float t = Time.time;
float x = Mathf.Sin(t);
float y = Mathf.Cos(t);
if (_movingObject) _movingObject.position = new(x * _posMod, 1.0f, y * _posMod);
Vector2 center = new(0.5f + x * _cameraPosMod, 0.5f + y * _cameraPosMod);
// bottom left camera
_cameras[0].rect = new(0.0f, 0.0f, center.x, center.y);
// bottom right camera
_cameras[1].rect = new(center.x, 0.0f, 1.0f - center.x, center.y);
// upper left camera
_cameras[2].rect = new(0.0f, center.y, center.x, 1.0f - center.y);
// upper right camera
_cameras[3].rect = new(center.x, center.y, 1.0f - center.x, 1.0f - center.y);
}
}
Not exactly an answer to your question about stencil buffer but I had a (hopefully) similar use case recently.
The main issue: In the URP Camera stack
If your camera is set to Base it will overdraw the entire screen
you can not adjust the Viewport on any Overlay camera
You can actually try to set the viewport via code -> result your camera renders only the correct part of the scene ... but it gets stretched to the entire screen ^^
What I did in the end was
Leave all content and cameras at the origin position
Apply according masks to filter the content per camera
Make your camera Overlay (as usual)
go through a custom Camera.projectionMatrix
m_Camera.projectionMatrix = Matrix4x4.Translate(projectionOffset) * Matrix4x4.Perspective(m_Camera.fieldOfView, m_Camera.aspect, m_Camera.nearClipPlane, m_Camera.farClipPlane);
where the projectionOffset is an offset in viewport space (normalized 0 - 1) from the bottom left corner.
For example in my case I wanted a minimap at 400, 400 pixels from the top-right corner so I did
var topRightOffsetPixels = new Vector2(400, 400);
var topRightOffsetViewport = Vector2.one - new Vector2(topRightOffsetPixels.x * 2 / Screen.width, topRightOffsetPixels.y * 2 / Screen.height);
m_Camera.projectionMatrix = Matrix4x4.Translate(topRightOffsetViewport) * Matrix4x4.Perspective(m_Camera.fieldOfView, m_Camera.aspect, m_Camera.nearClipPlane, m_Camera.farClipPlane);
See also Matrix4x4.Perspective
I'm creating a game in flutter. I'm using a tilesheet to render tiles. I chop the image in 50x50 sections and then render them depending on their surrounding.
The tiles are rendered at the position of their corresponding "game object". In order to keep the code clean from details about converting from the game world positions and sizes to actual screen sizes my painting classes always obtain world space and then scales it up to screen space.
However, after scaling up the tiles I'm sometimes left with gaps between the tiles.
I've tried:
Placing the tiles at their appropriate screen position, without scaling the canvas first, in case the scaling produces the problem.
Adding borders around the tiles in the tilesheet in case the canvas.drawImageRect samples too many pixels.
Making the board take a size divisible by the number of tiles, in case there is a rounding error.
Drawing a subsection of the tile.
I can't seem to make the gap disappear. Do you have any suggestions?
Below is the relevant drawing code, where size and position are in world space and frameX and frameY is the positions to extract from the spritesheet.
void drawFrameAt(int x, int y, Canvas canvas, Offset position, Size size) {
var frameX = x * frameWidth;
var frameY = y * frameHeight;
var rect = Rect.fromLTWH(frameX, frameY, frameWidth, frameHeight);
var width = size.width;
var height = size.height;
var destination = Rect.fromLTWH(position.dx, position.dy, width, height);
canvas.drawImageRect(image, rect, destination, Paint());
}
How do we can set a certain size of units for defining the width of the Orthographic size of the camera in the portrait mode?
I want to set the horizontal dimension to the 5 meters exactly from the center-left to the center-right of the screen for any mobile device? how can I achieve this? I've found this piece of code from a video clip but I don't understand it and I think it does not help me since I don't have a game field and also my game world will be generated automatically during the game (it's an infinite 2D scrolling game).
[SerializeField] private SpriteRenderer gameField;
void Start()
{
float screenRatio = (float)Screen.width / (float)Screen.height;
float targetRatio = gameField.bounds.size.x / gameField.bounds.size.y;
if (screenRatio > targetRatio)
{
Camera.main.orthographicSize = gameField.bounds.size.y / 2;
}
else
{
float differenceInSize = targetRatio / screenRatio;
Camera.main.orthographicSize = gameField.bounds.size.y / 2 * differenceInSize;
}
}
I don't know why unity doesn't handle these issues automatically?
I have found the video you have been talking about and it is actually pretty simple. For reference, it is this video. I will try to explain it to you.
These 5 boxes represent all content that you want to show on your screen. You want your camera to always adjust itself so it fits all of those boxes inside of it.
To archive this you have to multiply the width of our boxes (all of our boxes are 1 meter wide in all dimensions) by the screen height devided by the screen width. You then want to divide that number by two.
boxes.width * screen.height / screen.width * 0.5
In our code it looks like this:
public float sizeInMeters;
void Start()
{
float orthoSize = sizeInMeters * Screen.height / Screen.width * 0.5f;
Camera.main.orthographicSize = orthoSize;
}
If you want to have five meters to the left and right from the middle then put in 10 into the sizeInMeters variable. If your total screen width from left to right should only cover 5 meters you have to put in 5 into the sizeInMeters variable.
The if inside of your code is only there if you want the user to be able to flip his phone into a vertical position.
I'm trying to draw a rectangle to the very top left of a page using ITextSharp (5.5.13). I want to draw in the page margins. However, the rectangle is around 25 pixels too low. How can I draw the rectangle in the top left corner?
Below is how I'm adding the rectangle to the page:
using (PdfReader reader = new PdfReader(inputPdf.FullName))
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(outputPdf.FullName, FileMode.Create)))
{
PdfContentByte contentByte = stamper.GetOverContent(1);
PdfDocument doc = contentByte.PdfDocument;
float X = 0.0f;
float Y = 0.0f;
float Height = Utilities.InchesToPoints(0.50f);
float Width = Utilities.InchesToPoints(0.50f);
float llx = (doc.Left - doc.LeftMargin) + X;
float lly = (doc.Top - doc.TopMargin) - (Height + Y);
float urx = (doc.Left - doc.LeftMargin) + Width + X;
float ury = (doc.Top - doc.TopMargin) - Y;
Rectangle rectangle = new Rectangle(llx, lly, urx, ury)
{
BackgroundColor = BaseColor.BLACK
};
contentByte.Rectangle(rectangle);
}
Below are the debug values for each aforementioned variable:
Whenever you use a PdfStamper, the PdfDocument you can retrieve from its parts does not contain sensible information, it merely is a dummy object.
Thus, don't try to determine the page size from that PdfDocument doc, instead use the appropriate methods or properties of your PdfReader reader, e.g.
/** Gets the crop box without taking rotation into account. This
* is the value of the /CropBox key. The crop box is the part
* of the document to be displayed or printed. It usually is the same
* as the media box but may be smaller. If the page doesn't have a crop
* box the page size will be returned.
* #param index the page number. The first page is 1
* #return the crop box
*/
virtual public Rectangle GetCropBox(int index)
I have a map app where the user can place waypoints manually. I would like for them to press the waypoint button and have a waypoint placed in the center of their currently visible view on the content view.
I'm afraid you'd have to calculate it yourself. contentSize returns size of the scrolled content, contentOffset gives you the origin of the scroll view inside the content. Then with scrollView.bounds.size you can find the center of the view.
Haven't tested this, but maybe you could convert scrollView.center to your scrolled map like this:
CGPoint viewportCenterInMapCoords =
[scrollView.superview convertPoint:scrollView.center
toView:mapViewInsideScrollView];
Need to account for how zoomed it is, then I can convert the content offset to the size of the full image and add some.
/// this is the full size of the map image
CGSize fullSize = CGPointMake(13900, 8400);
/// determines how the current content size compares to the full size
float zoomFactor = size.width/self.contentSize.width;
/// apply the zoom factor to the content offset , this basically upscales
/// the content offset to apply to the dimensions of the full size map
float newContentOffsetX = self.contentOffset.x*zoomFactor + (self.bounds.size.width/2) *zoomFactor-300;
float newContentOffsetY = self.contentOffset.y*zoomFactor + (self.bounds.size.height/2) * zoomFactor-300;
/// not sure why i needed to subtract the 300, but the formula wasn't putting
/// the point in the exact center, subtracting 300 put it there in all situations though
CGPoint point = CGPointMake(newContentOffsetX,newContentOffsetY );