mirror of
https://fietkau.software/QRSVG.git
synced 2024-12-04 16:23:08 -06:00
Add confetti shape style
This commit is contained in:
parent
a072d608c0
commit
59c0d2d5cd
114
qrsvg-v1.0.1.js
114
qrsvg-v1.0.1.js
|
@ -230,6 +230,10 @@ function compactPathSpec(oldPathSpec) {
|
|||
if((step[0] == 'h' || step[0] == 'v') && step[0] == prev[0]) {
|
||||
let distance = parseInt(prev.substring(1), 10) + parseInt(step.substring(1), 10);
|
||||
newPathSpec[newPathSpec.length - 1] = step[0] + distance;
|
||||
} else if(step[0] == 'm' && (prev[0] == 'm' || prev[0] == 'M')) {
|
||||
let prevPos = prev.substring(1).split(' ').map(c => parseFloat(c));
|
||||
let newDelta = step.substring(1).split(' ').map(c => parseFloat(c));
|
||||
newPathSpec[newPathSpec.length - 1] = prev[0] + (prevPos[0] + newDelta[0]).toPrecision(3) + ' ' + (prevPos[1] + newDelta[1]).toPrecision(3);
|
||||
} else {
|
||||
newPathSpec.push(step);
|
||||
}
|
||||
|
@ -243,8 +247,62 @@ function calculateTileStyleContour(bitmask, margin, style) {
|
|||
if(!['dots', 'mosaic', 'confetti'].includes(style)) {
|
||||
throw Error('Unsupported tiled render style: ' + style);
|
||||
}
|
||||
let confettiShapes = [
|
||||
[ // circle
|
||||
'M 0.5 0.1',
|
||||
'A 0.4 0.4 0 0 1 0.5 0.9',
|
||||
'A 0.4 0.4 0 0 1 0.5 0.1',
|
||||
],
|
||||
[ // rectangle
|
||||
'M 0.1 0.15',
|
||||
'L 0.9 0.15',
|
||||
'L 0.9 0.85',
|
||||
'L 0.1 0.85',
|
||||
'L 0.1 0.15',
|
||||
],
|
||||
[ // star
|
||||
'M 0.68 0.254',
|
||||
'Q 1.21 0.284 0.786 0.58',
|
||||
'Q 0.9275 1.0925 0.498 0.801',
|
||||
'Q 0.0545 1.1 0.212 0.606',
|
||||
'Q -0.208 0.269 0.312 0.259',
|
||||
'Q 0.5 -0.25 0.68 0.254',
|
||||
],
|
||||
[ // heart
|
||||
'M 0.5 0.3',
|
||||
'C 1.2 -0.1 1 0.7 0.5 1',
|
||||
'C 0 0.7 -0.2 -0.1 0.5 0.3',
|
||||
],
|
||||
[ // diamond
|
||||
'M 0.5 0',
|
||||
'Q 0.65 0.35 1 0.5',
|
||||
'Q 0.65 0.65 0.5 1',
|
||||
'Q 0.35 0.65 0 0.5',
|
||||
'Q 0.35 0.35 0.5 0',
|
||||
],
|
||||
[ // shamrock
|
||||
'M 0.45 0.45',
|
||||
'A 0.23 0.23 0 1 1 0.55 0.45',
|
||||
'A 0.23 0.23 0 1 1 0.54 0.48',
|
||||
'L 0.7 0.95',
|
||||
'L 0.3 0.95',
|
||||
'L 0.46 0.48',
|
||||
'A 0.23 0.23 0 1 1 0.45 0.45',
|
||||
],
|
||||
[ // lemon
|
||||
'M 0.5 0',
|
||||
'Q 1.5 0.5 0.5 1',
|
||||
'Q -0.5 0.5 0.5 0',
|
||||
],
|
||||
];
|
||||
let contour = new Contour();
|
||||
let prng = new PRNG(1);
|
||||
// Rotate a point around (0.5, 0.5) by angle in radians
|
||||
let rotatePoint = (x, y, angle) => {
|
||||
let rotatedX = 0.5 + (x - 0.5) * Math.cos(angle) - (y - 0.5) * Math.sin(angle);
|
||||
let rotatedY = 0.5 + (x - 0.5) * Math.sin(angle) + (y - 0.5) * Math.cos(angle);
|
||||
return [rotatedX, rotatedY];
|
||||
};
|
||||
for(let y = 0; y < bitmask.height; y++) {
|
||||
for(let x = 0; x < bitmask.width; x++) {
|
||||
if(bitmask.width > 16 && bitmask.height > 16) {
|
||||
|
@ -269,22 +327,48 @@ function calculateTileStyleContour(bitmask, margin, style) {
|
|||
let size = 0.9; // relative to grid size
|
||||
let maxAngle = Math.PI * 0.03;
|
||||
let angle = (prng.next() * 2 - 1) * maxAngle;
|
||||
// |------ middle of the pixel ------| |-north displacement-| |-west displacement-|
|
||||
let topLeftX = x + margin + 0.5 + ((1 - size) / 2) - 0.5 * Math.cos(angle) + 0.5 * Math.sin(angle);
|
||||
let topLeftY = y + margin + 0.5 + ((1 - size) / 2) + 0.5 * Math.cos(angle) - 0.5 * Math.sin(angle) - 1;
|
||||
newPathSpec.push('M' + topLeftX.toPrecision(3) + ' ' + topLeftY.toPrecision(3));
|
||||
newPathSpec.push('l' + (size * Math.cos(angle)).toPrecision(3) + ' ' + (size * Math.sin(angle)).toPrecision(3));
|
||||
newPathSpec.push(('l-' + (size * Math.sin(angle)).toPrecision(3) + ' ' + (size * Math.cos(angle)).toPrecision(3)).replaceAll('--', ''));
|
||||
newPathSpec.push(('l-' + (size * Math.cos(angle)).toPrecision(3) + ' -' + (size * Math.sin(angle)).toPrecision(3)).replaceAll('--', ''));
|
||||
newPathSpec.push(('l' + (size * Math.sin(angle)).toPrecision(3) + ' -' + (size * Math.cos(angle)).toPrecision(3)).replaceAll('--', ''));
|
||||
newPathSpec.push('M' + (x + 1) + ' ' + (y + 1));
|
||||
let tileCorners = [
|
||||
rotatePoint(0.5 - (size / 2), 0.5 - (size / 2), angle),
|
||||
rotatePoint(0.5 + (size / 2), 0.5 - (size / 2), angle),
|
||||
rotatePoint(0.5 + (size / 2), 0.5 + (size / 2), angle),
|
||||
rotatePoint(0.5 - (size / 2), 0.5 + (size / 2), angle),
|
||||
];
|
||||
newPathSpec.push('m' + tileCorners[0][0].toPrecision(3) + ' ' + tileCorners[0][1].toPrecision(3));
|
||||
newPathSpec.push('l' + (tileCorners[1][0] - tileCorners[0][0]).toPrecision(3) + ' ' + (tileCorners[1][1] - tileCorners[0][1]).toPrecision(3));
|
||||
newPathSpec.push('l' + (tileCorners[2][0] - tileCorners[1][0]).toPrecision(3) + ' ' + (tileCorners[2][1] - tileCorners[1][1]).toPrecision(3));
|
||||
newPathSpec.push('l' + (tileCorners[3][0] - tileCorners[2][0]).toPrecision(3) + ' ' + (tileCorners[3][1] - tileCorners[2][1]).toPrecision(3));
|
||||
newPathSpec.push('z');
|
||||
} else if(style == 'confetti') {
|
||||
// TODO
|
||||
newPathSpec.push('M' + (x + margin + 0.5) + ' ' + (y + margin));
|
||||
newPathSpec.push('a0.5 0.5 0 0 1 0.5 0.5');
|
||||
newPathSpec.push('a0.5 0.5 0 0 1 -0.5 0.5');
|
||||
newPathSpec.push('a0.5 0.5 0 0 1 -0.5 -0.5');
|
||||
newPathSpec.push('a0.5 0.5 0 0 1 0.5 -0.5');
|
||||
newPathSpec.push('M' + (x + margin) + ' ' + (y + margin));
|
||||
let currentShape = confettiShapes[Math.floor(prng.next() * confettiShapes.length)];
|
||||
let previousPoint = [0, 0];
|
||||
let angle = prng.next() * Math.PI * 2;
|
||||
for(let segment of currentShape) {
|
||||
segment = segment.split(' ');
|
||||
let formatRotatedPoint = (i, j) => {
|
||||
let rotated = rotatePoint(segment[i], segment[j], angle);
|
||||
return (rotated[0] - previousPoint[0]).toPrecision(3) + ' ' + (rotated[1] - previousPoint[1]).toPrecision(3);
|
||||
}
|
||||
if(segment[0] == 'M') {
|
||||
let rotated = rotatePoint(segment[1], segment[2], angle);
|
||||
newPathSpec.push('m' + formatRotatedPoint(1, 2));
|
||||
previousPoint = rotated;
|
||||
} else if(segment[0] == 'L') {
|
||||
let rotated = rotatePoint(segment[1], segment[2], angle);
|
||||
newPathSpec.push('l' + formatRotatedPoint(1, 2));
|
||||
previousPoint = rotated;
|
||||
} else if(segment[0] == 'Q') {
|
||||
newPathSpec.push('q' + formatRotatedPoint(1, 2) + ' ' + formatRotatedPoint(3, 4));
|
||||
previousPoint = rotatePoint(segment[3], segment[4], angle)
|
||||
} else if(segment[0] == 'C') {
|
||||
newPathSpec.push('c' + formatRotatedPoint(1, 2) + ' ' + formatRotatedPoint(3, 4) + ' ' + formatRotatedPoint(5, 6));
|
||||
previousPoint = rotatePoint(segment[5], segment[6], angle);
|
||||
} else if(segment[0] == 'A') {
|
||||
newPathSpec.push('a' + segment.slice(1, 6).join(' ') + ' ' + formatRotatedPoint(6, 7));
|
||||
previousPoint = rotatePoint(segment[6], segment[7], angle);
|
||||
}
|
||||
}
|
||||
newPathSpec.push('z');
|
||||
}
|
||||
if(!bitmask.get(x - 1, y) && !bitmask.get(x + 1, y) && !bitmask.get(x, y - 1) && !bitmask.get(x, y + 1)) {
|
||||
|
@ -466,7 +550,7 @@ function calculateContour(bitmask, margin = 1, style = 'basic') {
|
|||
contour.pdpInner.push(...Array(3).fill('v-1'));
|
||||
contour.pdpInner.push('z');
|
||||
}
|
||||
if(style == 'dots' || style == 'rounded') {
|
||||
if(['dots', 'rounded', 'confetti'].includes(style)) {
|
||||
contour.pdpInner = makePathSpecRound(contour.pdpInner);
|
||||
contour.pdpOuter = makePathSpecRound(contour.pdpOuter);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user