Skip to content

Commit

Permalink
update text styles and warping
Browse files Browse the repository at this point in the history
  • Loading branch information
jhornsten committed Oct 13, 2023
1 parent d96ea48 commit 8b2e500
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 59 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,5 @@ tags
[._]*.un~

# End of https://www.toptal.com/developers/gitignore/api/node,vim

.DS_Store
49 changes: 15 additions & 34 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,37 +1,18 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Alla mot alla generator</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css"
/>
<style>
.github-fork-ribbon:before {
background-color: #000;
}
input[type="text"] {
width: 1296px;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
}
</style>
</head>

<body>
<a
class="github-fork-ribbon"
href="https://github.com/datahax/amagen"
data-ribbon="Fork me on GitHub"
title="Fork me on GitHub"
>Fork me on GitHub</a
>
<p>
<input type="text" name="text" id="text" placeholder="Enter text..." />
</p>
<canvas id="amaBoard" width="1296" height="714"></canvas>
<script src="public/image.js"></script>
</body>
</html>
<head>
<meta charset="utf-8" />
<title>Alla mot alla generator</title>
<link rel="stylesheet" href="/static/style.css" />
</head>

<body>
<div class="page">
<input type="text" name="text" id="text" placeholder="Enter text..." />
<canvas id="amaBoard" width="1200" height="675"></canvas>
</div>
<script src="image.js"></script>
</body>

</html>
3 changes: 2 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const app: Express = express();
const port = process.env.PORT || 8080;
const path = require('path');

app.use('/public', express.static('public'));
app.use('/', express.static('public'));
app.use('/static', express.static(path.join(__dirname, 'public/static')));

app.get('/', (req: Request, res: Response) => {
res.sendFile(path.join(__dirname, '/index.html'));
Expand Down
Binary file modified public/canvas.jpg
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
193 changes: 169 additions & 24 deletions public/image.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Helper function to split text into multiple lines
function splitToLines(ctx, text, maxWidth) {
var words = text.split(" ");
var lines = [];
Expand All @@ -9,58 +10,202 @@ function splitToLines(ctx, text, maxWidth) {
if (width < maxWidth) {
currentLine += " " + word;
} else {
// Check if the maximum number of lines is reached
if (lines.length >= 5) { // considering the current line will be the 5th
break;
}

lines.push(currentLine);
currentLine = word;
}
}

lines.push(currentLine);
// Add the current line if there's space left
if (lines.length < 6) {
lines.push(currentLine);
}

return lines;
}

// Matrix class for affine transformations
class Matrix {
constructor(points) {
if (points.length !== 6) {
throw new Error("Matrix initialization requires an array of 6 points.");
}
this.data = [...points];
}

invert() {
const [a, b, c, d, e, f] = this.data;
const det = a * d - b * c;
if (!det) {
throw new Error("Matrix is non-invertible.");
}
return new Matrix([
d / det,
-b / det,
-c / det,
a / det,
(c * f - d * e) / det,
(b * e - a * f) / det
]);
}

multiply(matrix) {
const [a1, b1, c1, d1, e1, f1] = this.data;
const [a2, b2, c2, d2, e2, f2] = matrix.data;

return new Matrix([
a1 * a2 + c1 * b2,
b1 * a2 + d1 * b2,
a1 * c2 + c1 * d2,
b1 * c2 + d1 * d2,
a1 * e2 + c1 * f2 + e1,
b1 * e2 + d1 * f2 + f1
]);
}
}

// Helper function to set canvas transformation
function setTransform(ctx, src, dst) {
const a = new Matrix(src);
const b = new Matrix(dst);
const c = b.multiply(a.invert());
ctx.setTransform(c.a, c.b, c.c, c.d, c.e, c.f);
}

// Main function to generate image with styled text
function generateImage(text) {
const imageObj = new Image();
const canvas = document.getElementById("amaBoard");
var ctx = canvas.getContext("2d");

var gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop("0", "gold");
gradient.addColorStop("0.5", "white");
gradient.addColorStop("1.0", "gold");

ctx.textAlign = "center";
ctx.font = "800 60px Arial";
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
ctx.color = "red";
ctx.shadowBlur = 5;
ctx.shadowColor = "gold";

var maxWidth = 800;
var lineHeight = 70;
var textLines = splitToLines(ctx, text.toUpperCase(), maxWidth);
var x = canvas.width / 2 - 90;
var y = canvas.height / 2;
const ctx = canvas.getContext("2d");

// Create the first offscreen canvas
const offscreenCanvas1 = document.createElement("canvas");
offscreenCanvas1.width = canvas.width;
offscreenCanvas1.height = canvas.height;
const offscreenCtx1 = offscreenCanvas1.getContext("2d");

// Create the second offscreen canvas
const offscreenCanvas2 = document.createElement("canvas");
offscreenCanvas2.width = canvas.width;
offscreenCanvas2.height = canvas.height;
const offscreenCtx2 = offscreenCanvas2.getContext("2d");

// Font setup and alignment
offscreenCtx1.textAlign = "center";
offscreenCtx1.font = "700 51px 'Poppins'";

// Text line splitting
const maxWidth = 700;
const lineHeight = 70;
const textLines = splitToLines(offscreenCtx1, text.toUpperCase(), maxWidth);
let x = 479; // Center X of the TV screen
let y = 305; // Center Y of the TV screen

if (textLines.length > 1) {
y -= (lineHeight * textLines.length) / 2 - lineHeight;
}

imageObj.src = "public/canvas.jpg";
let textWidth = 0;
let textHeight = lineHeight * textLines.length;

for (let i = 0; i < textLines.length; i++) {
const lineWidth = offscreenCtx1.measureText(textLines[i]).width;
if (lineWidth > textWidth) {
textWidth = lineWidth;
}
}

// Gradient setup
const fillAngle = -50 * (Math.PI / 180);
const length = Math.sqrt(textWidth * textWidth + textHeight * textHeight);
const x1 = x + Math.cos(fillAngle - Math.PI / 2) * length / 2;
const y1 = y + Math.sin(fillAngle - Math.PI / 2) * length / 2;
const x2 = x + Math.cos(fillAngle + Math.PI / 2) * length / 2;
const y2 = y + Math.sin(fillAngle + Math.PI / 2) * length / 2;

const gradient = offscreenCtx1.createLinearGradient(x1, y1, x2, y2);
gradient.addColorStop(0, "#b59514");
gradient.addColorStop(0.15, "#a68200");
gradient.addColorStop(0.31, "#9e780b");
gradient.addColorStop(0.40, "#c2c496");
gradient.addColorStop(0.52, "#cad9dc");
gradient.addColorStop(0.63, "#d1e7ff");
gradient.addColorStop(0.76, "#b0bdaa");
gradient.addColorStop(0.88, "#bab466");
gradient.addColorStop(1, "#bab466");
offscreenCtx1.fillStyle = gradient;

imageObj.src = "canvas.jpg";
imageObj.onload = function () {
ctx.drawImage(imageObj, 0, 0);

for (var i = 0; i < textLines.length; i++) {
ctx.fillText(textLines[i], x, y);
// Set the transformation for the TV screen projection
const srcPoints = [112, 90, 847, 96, 126, 560];
const dstPoints = [0, 0, canvas.width, 0, 0, canvas.height];
setTransform(offscreenCtx1, srcPoints, dstPoints);

// Draw the fill text first
for (let i = 0; i < textLines.length; i++) {
offscreenCtx1.fillText(textLines[i], x, y);
y += lineHeight;
}

// Reset y for shadowed stroke
y = 305; // Center Y of the TV screen
if (textLines.length > 1) {
y -= (lineHeight * textLines.length) / 2 - lineHeight;
}

const strokeAngle = -130 * (Math.PI / 180);
const strokeX1 = x + Math.cos(strokeAngle - Math.PI / 2) * length / 2;
const strokeY1 = y + Math.sin(strokeAngle - Math.PI / 2) * length / 2;
const strokeX2 = x + Math.cos(strokeAngle + Math.PI / 2) * length / 2;
const strokeY2 = y + Math.sin(strokeAngle + Math.PI / 2) * length / 2;

const strokeGradient = offscreenCtx1.createLinearGradient(strokeX1, strokeY1, strokeX2, strokeY2);
strokeGradient.addColorStop(0, "#b59514");
strokeGradient.addColorStop(0.04, "#c2c496");
strokeGradient.addColorStop(0.13, "#9e780b");
strokeGradient.addColorStop(0.25, "#cad9dc");
strokeGradient.addColorStop(0.36, "#d1e7ff");
strokeGradient.addColorStop(0.51, "#a68200");
strokeGradient.addColorStop(0.67, "#b0bdaa");
strokeGradient.addColorStop(0.88, "#bab466");
strokeGradient.addColorStop(1, "#bab466");

// Draw the shadowed stroke
offscreenCtx1.strokeStyle = strokeGradient;

offscreenCtx1.lineWidth = 2;
offscreenCtx1.shadowColor = "rgba(0, 0, 0, 0.5)";
offscreenCtx1.shadowBlur = 1;
offscreenCtx1.shadowOffsetX = 0;
offscreenCtx1.shadowOffsetY = 2;
for (let i = 0; i < textLines.length; i++) {
offscreenCtx1.strokeText(textLines[i], x, y);
y += lineHeight;
}

// Draw the offscreenCanvas1 onto offscreenCanvas2 with transformation and blur
offscreenCtx2.filter = 'blur(0.5px)';
setTransform(offscreenCtx2, srcPoints, dstPoints);
offscreenCtx2.drawImage(offscreenCanvas1, 0, 0);
offscreenCtx2.filter = 'none'; // Reset the filter

// Draw the offscreen canvas onto the main canvas
ctx.drawImage(offscreenCanvas2, 0, 0);
};
}

// Event listener to update the image based on user input
const textInput = document.querySelector("#text");
textInput.addEventListener("input", (event) => {
generateImage(event.target.value);
});

// Initial call to the function
generateImage("");
Binary file not shown.
Binary file added public/static/poppins-devanagari-700-normal.woff2
Binary file not shown.
Binary file added public/static/poppins-latin-700-normal.woff
Binary file not shown.
Binary file added public/static/poppins-latin-700-normal.woff2
Binary file not shown.
Binary file added public/static/poppins-latin-ext-700-normal.woff
Binary file not shown.
Binary file added public/static/poppins-latin-ext-700-normal.woff2
Binary file not shown.
29 changes: 29 additions & 0 deletions public/static/poppins.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* poppins-devanagari-700-normal */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-display: block;
font-weight: 700;
src: url(./poppins-devanagari-700-normal.woff2) format('woff2'), url(./poppins-devanagari-700-normal.woff) format('woff');
unicode-range: U+0900-097F, U+1CD0-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FF;
}

/* poppins-latin-ext-700-normal */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-display: block;
font-weight: 700;
src: url(./poppins-latin-ext-700-normal.woff2) format('woff2'), url(./poppins-latin-ext-700-normal.woff) format('woff');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* poppins-latin-700-normal */
@font-face {
font-family: 'Poppins';
font-style: normal;
font-display: block;
font-weight: 700;
src: url(./poppins-latin-700-normal.woff2) format('woff2'), url(./poppins-latin-700-normal.woff) format('woff');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
12 changes: 12 additions & 0 deletions public/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@import url('poppins.css');

body {
font-family: sans-serif;
}

input[type="text"] {
width: 1200px;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
}

0 comments on commit 8b2e500

Please sign in to comment.