TCPDF Rotate and Clip using a Rect Polygon inside the same transformation - tcpdf

So I'm using TCPDF in order to do some image manipulation on a PDF output.
What I have is an image (which needs to be rotated) and a clipping mask based on a Rect Polygon.
The problem I am facing is that when I do the transformation to rotate the image, the Rect Polygon I am using to do the clipping is also rotating.
Is there a way to rotate the image and then do the clipping after the initial StopTransform on the rotation has been executed?
Here's some sample code:
PDF::setXY($x, $y);
PDF::StartTransform();
PDF::Rotate($objectImageRotation * -1);
PDF::Rect($rectx, $recty, $rectwidth, $rectheight, 'CNZ');
PDF::Image($objectImageSrc, $x, $y, $width, $height, '', '', '', true, 300, '', false, false, ($objectBorderWidth > 0 ? 1 : 0), false, false, false);
PDF::StopTransform();
Now in the above, $rectx, $recty, $rectwidth and $rectheight are exactly where I want them to be.

So after much experimentation I figured out that by posting the 'Rect' before doing the actual rotation was the key to my requirement.
So given the above, the following change worked for me:
' Translate to a new XY coordinate in preparation for the placement of the image
PDF::setXY($x, $y);
' Start the transformation including the clipping according to the given shape and then rotating as per the rotation parameter
PDF::StartTransform();
' Clipping Rectangle
PDF::Rect($rectx, $recty, $rectwidth, $rectheight, 'CNZ');
' Rotate
PDF::Rotate($objectImageRotation * -1);
' Place the image at the set rotation
PDF::Image($objectImageSrc, $x, $y, $width, $height, '', '', '', true, 300, '', false, false, ($objectBorderWidth > 0 ? 1 : 0), false, false, false);
' Stop the transformation (reset)
PDF::StopTransform();

Related

Is there a way to scale the text fontsize using react konva on transform end

I have the following code below where once the text has been transformed on the screen the font size has gotten bigger but when i log fontsize it is the exact same as before.Is there anyway to get the updated fontsize as when I reload the page after the value have been saved to the db it is the previous font size.
<Text
name={eid}
zIndex={i}
x={x}
y={y}
text={text}
fontSize={fontSize}
fontFamily={fontFamily}
fill={fill}
width={width}
height={height}
align={align}
draggable={draggable}
onDragMove={(e) => {
let transformedData = {
'x' : e.target.x(),
'y' : e.target.y(),
}
socket.emit('element:update',{data:transformedData})
}}
onTransformEnd={(e) => {
let text = e.target
let transformedData = {
'x': text.x(),
'y': text.y(),
'rotation': text.rotation(),
'width': text.width() * text.scaleX(),
'height': text.height() * text.scaleY(),
'fontSize': text.fontSize() //this font size never changes ...not sure why
}
socket.emit('element:updatedata'{data:tranformedData})
}}
/>
When you scale a shape its dimensions do not change. Internally, what happens is that a transformation matrix is applied that changes the scale at which the shape is drawn, but none of the shape attributes other than scaleX() and scaleY() are changed.
A common question concerns how to get the size of the shape on the stage. The answer to that is
shapeSize.width = shape.width() * shape.scaleX();
shapeSize.height= shape.height() * shape.scaleY();
And the same approach would be taken for the font size:
shapeSize.fontSize = textShape.fontSize () * textShape.scaleY();

Scaling IMAGE around pointer in Konva

Can't wrap my head around this and get it to work. Trying to transpose this sample on Konva, but can not get it to work with an image inside a layer, inside the stage.
The sample I am trying to reproduce is the "Zooming stage relative to pointer position" sample.
https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html
Any help would generate kudos.
The trick with zooming from an arbitrary point such as the mouse position is to understand that you must relocate the stage to keep the point under the mouse consistent. I provide the working vanilla JS snippet below to illustrate the point. The guts are based on the original demo at the Konva docs site, just with more comments in the code. Translating into React should not be difficult once the basis of the technique is explained.
The gray area is the canvas, and the pink rect is the stage. Note that we start with the stage positioned into the canvas just to show that the stage can be moved like any other object.
The stage has a dot-pattern to help show the effects in the demo. The solution works for any layout of layers, shapes or images (as per OP question). Note that the shapes themselves do not need to be handled individually - the scaling is applied to the stage.
Move your mouse anywhere on the stage and scroll to see the zoom effect, noting how the top-left of the pink stage rectangle moves with the zoom. Now un-tick the checkbox to turn off the stage position adjustment - note now that the zoom is no longer respecting the mouse position because the stage position is not being moved.
Thus we have illustrated that it is necessary to move the stage sympathetically during the zoom but how do we know the amount to move by?
The tip to know is that you need to get the absolute distance of the mouse position over the stage before the new scale is applied, then apply the new scale to the stage, then use the computed distance * new scale to compute the new stage position. See the stage.on('wheel') event in the snippet for working code.
See also the codepen here.
// Making the stage
let stage = new Konva.Stage({
container: "container1",
width: $('#container1').width(),
height: $('#container1').height(),
draggable: true,
x: 40,
y: 60
});
// Make the layer
let layer = new Konva.Layer();
// make a rect to fill stage to show where it is.
let rect = new Konva.Rect({
x:0,
y: 0,
width: $('#container1').width(),
height: $('#container1').height(),
fill: 'magenta',
opacity: 0.3
})
layer.add(rect);
let grid = {w: $('#container1').width(), h: $('#container1').height()},
gridStep = 40,
mouseCircleRadius = 80,
circles = [],
dotRadius = 10;
// Make the grid of circles
for (let i = gridStep; i < grid.w; i = i + gridStep ){
for (let j = gridStep; j < grid.h; j = j + gridStep ){
let c = new Konva.Circle({ x: i, y: j, radius: dotRadius, fill: 'cyan'})
circles.push(c);
layer.add(c)
}
}
// Add layer to stage
stage.add(layer)
stage.on('mousemove', function (e) {
var pointer = stage.getPointerPosition();
// show the pointer and stage positions for illustration
$('#trace').html('Pointer.x = ' + pointer.x + ' stage.x() = ' + stage.x())
});
// this is the scale factor to be applied at each step.
var scaleBy = 1.01;
// this is the event that fires when the mouse wheel spins.
stage.on('wheel', (e) => {
e.evt.preventDefault();
// note the old scale to be used when deciding the current stage position
var oldScale = stage.scaleX();
// note the mouse pointer position relative to the stage at current scale
var pointer = stage.getPointerPosition();
// calculate the mouse pointer position at scale = 1.
// pointer.x is relative to the canvas - not affected by stage scale,
// stage.x() is the poistion of the stage on the canvas.
// This gives the distance from the pointer to the
var mousePointTo = {
x: (pointer.x - stage.x()) / oldScale,
y: (pointer.y - stage.y()) / oldScale,
};
// Calculate the new scale - slightly different calc for zoom in versus zoom out, as you would expect.
var newScale = (e.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy);
// Apply the new scale to the stage. Note that, assuming a zoom-in op, at this point in time the shapes on the stage would
// seem to have jumped down + right. We will shortly 'move' the stage left+up to counter this effect.
stage.scale({ x: newScale, y: newScale });
// To do that we have to calculate what the position of the stage must be relative to the mouse pointer position at the new scale.
// Note - remove the 'if' for your live code, the checkbox is for illustration only.
if ($('#fixstagepos').prop('checked')){
var newPos = {
x: pointer.x - mousePointTo.x * newScale,
y: pointer.y - mousePointTo.y * newScale,
};
// and apply the new position to the stage. Again in the case of a zoom-in op this has the effect of moving the stage left + up, countering the apparent movement
// caused by the change in scale.
stage.position(newPos);
}
});
.container {
width: 800px;
height: 400px;
background-color: silver;
margin: 5px;
}
#trace {
max-height: 200px;
overflow-y: scroll;
font-family: 'Courier'
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva#8/konva.min.js"></script>
<p id="info">Grey is the canvas and the pink rect shows the stage position. The stage is intitially positioned at {x: 40, y: 60} and can be dragged.</p>
<p>Move mouse over stage and scroll to zoom in & out. Use checkbox to see what happens without stage pos correction. </p>
<p>Apply correction to stage position <input id='fixstagepos' type='checkbox' checked='1' /></p>
<div id='container1' class='container'>
</div>
<p id='trace'></p>

Any way to make an image round in Konvajs?

I have a Konva image. How do I set radius or border-radius?
In the docs the Image class has width and height, but I want to set the Radius (border-radius). There is a circle class that can have an image as a background. However, when I use this you need to specify the dimensions for each image to make it zoom into and crop the correct location.
<v-image
:config="{
x: 50,
y: 50,
image: image,
shadowBlur: 5
}"
/>
In the Image class there should be a property Radius. Just like in the circle class. Is their an alternative way to do this that I am missing?
If you want rounded corners, or even a complete circle, you need to use a clipping function applied to your group or shape.
See Konva docs example here
The important part if that in the creation of your group or shape you include the definition of the clip func. The example below creates 2 overlapping circles - see the Konva docs for the working code.
var group = new Konva.Group({
clipFunc: function(ctx) {
ctx.arc(250, 120, 50, 0, Math.PI * 2, false);
ctx.arc(150, 120, 60, 0, Math.PI * 2, false);
}
});
For rounded corners see the answer to a similar question with a working code snippet here.

change the color of images using renderTarget

I try to draw an image on the screen with render target.
I used this code:
_renderTarget = new RenderTarget2D(
this._graphicsDevice,
this._graphicsDevice.PresentationParameters.BackBufferWidth,
this._graphicsDevice.PresentationParameters.BackBufferHeight,
false,
this._graphicsDevice.PresentationParameters.BackBufferFormat,
DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
_graphicsDevice.SetRenderTarget(_renderTarget);
_spriteBatch.Begin();
_spriteBatch.Draw(texture, drawPoint, null, Color.Red, 0.0f
, new Vector2(texture.Width / 2, texture.Height / 2), 0.5f, SpriteEffects.None, 0 .0f);
_spriteBatch.End();
_graphicsDevice.SetRenderTarget(null);
But, the result image is always black!
Could you help me to change the color of this image.
Thanks.
From the code shown, _spriteBatch.Draw is only rendering content to _renderTarget.
Next you need to render the resulting RenderTarget2D to your screen so you can see it.
You already have _graphicsDevice.SetRenderTarget(null) in place. You then just need to make a separate SpriteBatch.Draw call passing in your _renderTarget.
You can do this because RenderTarget2D extends Texture2D.

Two ribbon with same z, they covered each other

I'm drawing map roads with THREE.Ribbon, every road has border with different color, so I use two ribbons, one is wider with the color of border, one is narrower, then I can achieve my purpose.
I also draw cap on two ends of ribbon with circles, certainly draw two circles, the smaller one covers bigger one, just like linecap in canvas2D.
I can't use THREE.Line as my alternative, because the maximum value of width of Line is 1 in my webgl.
My codes are just like this:
var circleShape = new THREE.Shape();
var circleRadius = lineWidth/2;
circleShape.moveTo( 0, circleRadius );
circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 );
circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius );
circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 );
circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius );
var circle = new THREE.ShapeGeometry( circleShape);
var material = new THREE.MeshBasicMaterial( { color: color, depthWrite: false} );
var mesh = new THREE.Mesh( circle, material );
this.parent.add( mesh );
var material = new THREE.MeshBasicMaterial( { color: widerColor, depthWrite: false} );
var widerRibbon = new THREE.Ribbon( widerGeometry, material );
this.parent.add( widerRibbon );
var material = new THREE.MeshBasicMaterial( { color: narrowerColor, depthWrite: false} );
var narrowerRibbon = new THREE.Ribbon( narrowerGeometry, material );
this.parent.add( narrowerRibbon );
My logic is the latter will cover the former. so narrower ribbon will cover wider ribbon, ribbon will cover half of circle.
My difficulty:
The consequence is they cover each other(without depthWrite:false).
I have found that THREE.MeshBasicMaterial can set depthWrite to false, I add it, then I find that narrower ribbon covered wider ribbon successfully, but what is weird is the cap on the ends of ribbon seems abnormal, when I look at the ribbon right on top, it works well, but when I look it with a angle, I find that the ribbon can't cover circle.
I don't know how to deal this issue, I just want the later drawing covers the former drawing when they all have same z coordinate.
Thanks for your guidance!
If you want to use "painter's algorith" (whatevr is painted last is always what you see), just turn Z off in the material(s). This is, set the "depthTest" attribute to false when declaring the material

Resources