How and when to use PIXI.RenderTexture - pixi.js

I am building a tool which visualises bicycle wheels. It uses approximately 100 PIXI.Graphics to build the entire wheel, which is all placed in a PIXI.Container and then rendered. It seems like quite a lot to render every frame, so I was looking into the PIXI.RenderTexture class and thought it might make sense to use it in this case. So question 1, is this a good use case? and question 2, how can I use it because I am having trouble working it out.
const options = {
transparent: true,
antialias: true,
backgroundColor: 0xffffff,
resolution: window.devicePixelRatio,
view: canvasEle,
};
const app = new PIXI.Application(width, height, options);
const wrapper = new PIXI.Container(); // Wrapper is used for zooming and panning the wheel
app.stage.addChild(wrapper);
const wheel = new Wheel(wheelOpts); // Returns PIXI.Container full of PIXI.Graphics
wrapper.addChild(wheel);
And my attempt to use the renderTexture is as follows. But I can't seem to work it out
const options = {
transparent: true,
antialias: true,
backgroundColor: 0xffffff,
resolution: window.devicePixelRatio,
view: canvasEle,
};
const app = new PIXI.Application(width, height, options);
const wrapper = new PIXI.Container(); // Wrapper is used for zooming and panning the wheel
app.stage.addChild(wrapper);
const wheelRenderTexture = new PIXI.RenderTexture.create(width, height);
const wheelSprite = new PIXI.Sprite(wheelRenderTexture)
wrapper.addChild(wheelSprite)
const wheel = new Wheel(wheelOpts); // Returns PIXI.Container full of PIXI.Graphics
app.ticker.add(() =>
{
app.renderer.render(wheel, wheelRenderTexture);
})
Thanks for any help

I worked out how to use it and made a small jsfiddle https://jsfiddle.net/hp98ygz5/1/
const width = 600
const height = 600
var app = new PIXI.Application(width, height, {backgroundColor : 0xffffff});
document.body.appendChild(app.view);
const wheelRenderTexture = PIXI.RenderTexture.create(width, height);
const wheelRenderSprite = new PIXI.Sprite(wheelRenderTexture);
app.stage.addChild(wheelRenderSprite)
const wheelContainer = new PIXI.Container()
//app.stage.addChild(wheelContainer)
wheelContainer.addChild(drawCircle(100,100,50,0xfec3dc,2,0Xfe68a4))
wheelContainer.addChild(drawCircle(100,100,20,0xFFCC66,2,0X55ff77))
app.renderer.render(wheelContainer,wheelRenderTexture)
I am not sure what was wrong with the above example but it works now

Related

How to center continued text using PdfKit?

I have this code:
const PDFDocument = require("pdfkit");
const QRCode = require("qrcode");
const fs = require("fs");
const exec = async () => {
const doc = new PDFDocument({ layout: "landscape" });
doc.pipe(fs.createWriteStream("output.pdf"));
for (let pageNumber = 1; pageNumber <= 1000; pageNumber++) {
const url = await QRCode.toDataURL("I am a url!");
doc
.image(url, 10, 100, {
width: 420,
height: 420,
align: "center",
valign: "center",
})
doc
.font("Helvetica")
.fontSize(50)
.fillColor("#000")
.text(`Item `, 465, 200, { continued: true })
.fontSize(55)
.font("Courier-Bold")
.fillColor("#1b83c5")
.text(`${pageNumber}`);
doc
.font("Helvetica-Bold")
.fontSize(40)
.fillColor("#000")
.text("Order and Pay", 420, 320);
doc.addPage();
}
doc.end();
};
exec();
Which would produce something like this:
It looks centered and all, but as pages increase it will no longer be centered since the numbers are fixed.
I saw in the docs that there's an align property, but the docs didn't explain how to handle continued text.
Any working examples?
Maybe it's a little late, but I found a solution battling with the same problem:
First you need to create a constant with the width of the container you want to center your text in: (this value you have to calculate or invent, but it's easy to do that)
const containerWidth = 100 // as an example
Then, you need to create a variable that contains a plain string that contains all the text you want to center, in your example:
var appendedText = `Item ${pageNumber}`
To finish, you need to use pdf-kit's function: widthOfString, and add the text in the document as follows:
const xOffset = 465 // The original X offset value
doc
.text(`Item `, xOffset + (containerWidth / 2) - (doc.widthOfString(appendedText) / 2), 200, { continued: true })
.text(`${pageNumber}`);
Removed the text styling lines for clarity, but you have to add them later.

Expiry date of PDFs in Node

I'm trying to generate a PDF with an expiry date (auto expiring after 24 hours).
I have strong experience with pdf-lib, but searching through their repo there is no mention of expiry dates.
I've also found two articles on how to do it in C# and Python:
C#/VB:
https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/Security/How-to-Add-Expiry-Date-to-PDF-Files-in-C-VB.NET.html
https://docs.aspose.com/pdf/java/set-pdf-expiration-in-python/
I'm trying to make a PDF expire on a person's device after they have downloaded it from the server and surprised to see there isn't much support in the node/pdf area.
Any suggestions? Is this possible?
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'
const pdfDoc = await PDFDocument.create()
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman)
const page = pdfDoc.addPage()
const { width, height } = page.getSize()
const fontSize = 30
page.drawText('Creating PDFs in JavaScript would be great if the PDF had an expiry date!', {
x: 50,
y: height - 4 * fontSize,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0.53, 0.71),
})
// TODO: add expiry before the save.
const pdfBytes = await pdfDoc.save()
You can use addJavascript method, so your code will look like:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'
const pdfDoc = await PDFDocument.create()
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman)
pdfDoc.addJavaScript(
'main',
'var year=2020; var month=11;today = new Date();today = new Date(today.getFullYear(), today.getMonth());expiry = new Date(year, month);if (today.getTime() > expiry.getTime())app.alert("The file is expired. You need a new one.");',
);
const page = pdfDoc.addPage()
const { width, height } = page.getSize()
const fontSize = 30
page.drawText('Creating PDFs in JavaScript would be great if the PDF had an expiry date!', {
x: 50,
y: height - 4 * fontSize,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0.53, 0.71),
})
const pdfBytes = await pdfDoc.save()
You can more investigate it there https://github.com/Hopding/pdf-lib/commit/30d2aa22c0c0d694189ae3202562d4c0565cce42

Create a grid on top of an image

I hope you are all well and safe.
In NodeJS, I wanted to create a grid on top of an image. Like this:
Image without grid
Image with grid
Can someone tell me, please, how can I achieve this (some library or something)?
After creating the grid, I would like to go square by square and check the information for each square. Does anyone have any ideas?
Thank you very much for your time!
The first answer has a native Cairo dependency... Below I used pureimage instead, which has Pure JS implementations of jpeg and png encoding.
static drawParallel = (canvas, step, isYAxis) => {
const c2d = canvas.getContext('2d')
const numberOfSteps = (canvas.width / step) | 0
const end = isYAxis ? canvas.height : canvas.width
console.log(`Steps: ${numberOfSteps}\n`)
c2d.lineWidth = 1.1 // PureImage hides thin lines
c2d.strokeStyle = 'rgba(255,192,203,0.69)'
for (let i = 1; i < numberOfSteps; i++) {
const from = i * step
const to = i * step
const mx = isYAxis ? [from, 0, to, end] : [0, from, end, to]
console.log(`Stroking ${mx[0]}, ${mx[1]} to ${mx[2]}, ${mx[3]}`)
c2d.beginPath()
c2d.moveTo(mx[0], mx[1])
c2d.lineTo(mx[2], mx[3])
c2d.stroke()
}
}
source: https://stackblitz.com/edit/feathersjs-7kqlyt
I would use Canvas. You can use it for all sorts of image jobs and editing. For example, you could get a transparent PNG image of the grid and lay it on:
const Canvas = require("canvas");
const canvas = Canvas.createCanvas(619, 319);
const ctx = canvas.getContext("2d");
let img = await Canvas.loadImage("./path/to/image.png");
ctx.drawImage(img, 0, 0, img.width, img.height);
let grid = await Canvas.loadImage("./path/to/grid.png");
ctx.drawImage(grid, 0, 0, canvas.width, canvas.height);
console.log(canvas.toDataURL());
I myself managed to get something like this.

Draw Threejs TextGeometry along the path

I have some model and want cover it with text.
I've rendered and bended TextGeometry but it is difficult to combine these two meshes.
(Аnd yes, I've tried the dynamic textures, this way prohibits the use of own fonts)
scrinshot of existing model
Perhaps there is another way to draw the text along the path?
As you want to cover it with text, why not to use textures.
You can set it from a picture with THREE.TextureLoader() or you can draw your own on a canvas and apply it to a texture with var texture = new THREE.Texture(canvas);
For exmaple:
var texture = new THREE.Texture(canvas);
texture.repeat.set(5, 1);
texture.needsUpdate = true;
See the jsfiddle example.
There you can uncomment those lines
//texture.wrapS = THREE.RepeatWrapping;
//texture.wrapT = THREE.RepeatWrapping;
and see, how the result will change.
UPD. I've updated the fiddle. Used the trick with WebFontLoader (from this SO)
WebFontConfig = {
google: {families: ['Monoton']},
active: function() {
init();
animate();
},
};
(function(){
var wf = document.createElement("script");
wf.src = 'https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.26/webfontloader.js';
wf.async = 'true';
document.head.appendChild(wf);
})();

Loading a collada file with Vertex Colors using three.js

I'm trying to load a dae file using three.js, but I can't get the material to show. I can't find any examples that use a dae file to load vertex colors that are in the file itself. I can get it to load at threejs.org/editor by setting the material to MeshBasicMaterial and the property Vertex Colors to Vertex Colors. I tried to replicate that in code but I don't think I quite understand how. Here is my loader function...
loader.load( 'objects/chair.dae', function ( collada ) {
//dummy1.dae
var dae = collada.scene;
var skin = collada.skins[ 0 ];
console.log(collada.scene);
//collada.dae.materials[0] = collada.scene.children[0].children[0].material;
//dae.material = collada.scene.children[0].children[0].material;
//var material = collada.scene.children[0].children[0].material;
var material = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors
});
collada.scene.position.set(0,0,0);//x,z,y- if you think in blender dimensions ;)
collada.scene.scale.set(15.0, 15.0, 15.0);
var mesh = new THREE.Mesh(collada, material);
scene.add(mesh);
//scene.add(collada.scene);
var axes = new THREE.AxisHelper(50);
axes.position = dae.position;
scene.add(axes);
var gridXZ = new THREE.GridHelper(100, 10);
gridXZ.setColors( new THREE.Color(0x8f8f8f), new THREE.Color(0x8f8f8f) );
gridXZ.position.set(0,0,0 );
scene.add(gridXZ);
});
This is producing an error.
As for the code, basically you have to change the material of the mesh in the Collada object. Something like:
loader.load(
// resource URL
'models/example.dae',
// Function when resource is loaded
function ( collada ) {
var dae = collada.scene;
// CORRECT FOR IMPORTER
// collada object with only vertex color are not correctly loaded
dae.traverse( function(child) {
if (child instanceof THREE.Mesh) {
child.material = new THREE.MeshBasicMaterial( { vertexColors: true } );
}
});
dae.position.set(0,0,0);
dae.scale.set(10, 10, 10);
scene.add(dae);
animate();
},
// Function called when download progresses
function ( xhr ) {
console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
}
);

Resources