WIP: Add initial meme generator! #748

Merged
skhameneh merged 16 commits from featureTesting into master 2018-11-30 03:54:55 +01:00
6 changed files with 123 additions and 39 deletions
Showing only changes of commit 529eb5b350 - Show all commits

View file

@ -26,7 +26,7 @@ export default class EditableFontface extends Component {
const textRender = fontFace.textRender || DEFAULT_TEXT_RENDER;
const textStyles = Object.assign({
minHeight: '30px',
minHeight: '20px',
WebkitFontSmoothing: 'antialiased',
MozOsxFontSmoothing: 'grayscale',
}, fontFace.text);
@ -67,5 +67,5 @@ export default class EditableFontface extends Component {
export const PRESETS = {
'Retro Rainbow': require('../FontFaces/RetroRainbow'),
'Green Machine': require('../FontFaces/GreenMachine'),
'Ocean Wave': require('../FontFaces/OceanWave'),
'vapor wave': require('../FontFaces/VaporWave'),
}

View file

@ -1,21 +0,0 @@
import React from 'react';
module.exports = {
container: {},
editorStyle: {},
text: {},
textRender: (text) => {
// TODO: Inline the path
const id = `curve-${text.replace(/[^A-Za-z0-9]/g, '')}-oceanwave`
return (
<svg viewBox="0 0 425 300" style={{ height: '10em' }}>
<path id={id} fill="transparent" d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
<text x="25">
<textPath href={`#${id}`}>
{text}
</textPath>
</text>
</svg>
);
},
};

View file

@ -3,6 +3,7 @@ module.exports = {
editorStyle: {
fontFamily: 'Arial, sans-serif',
fontWeight: 'bold',
fontSize: '1.2em',
transform: 'scale(1, 1.5)',
},
text: {
@ -10,8 +11,11 @@ module.exports = {
fontWeight: 'bold',
backgroundImage: 'linear-gradient(to right, #b306a9, #ef2667, #f42e2c, #ffa509, #fdfc00, #55ac2f, #0b13fd, #a804af)',
backgroundClip: 'text',
fontSize: '1.2em',
transform: 'scale(1, 1.5)',
color: 'transparent',
paddingBottom: '.25em',
paddingTop: '.1em',
WebkitBackgroundClip: 'text',
},
};

View file

@ -0,0 +1,37 @@
import React from 'react';
const charToFullWidth = char => {
const c = char.charCodeAt( 0 )
return c >= 33 && c <= 126
? String.fromCharCode( ( c - 33 ) + 65281 )
: char
}
const stringToFullWidth =
module.exports = {
container: {},
editorStyle: {},
text: {
fontFamily: 'Segoe UI,Helvetica,Arial',
},
textRender: (text) => {
const formattedText = text.toLowerCase().split('').map((char) => {
const c = char.charCodeAt( 0 )
return (c >= 33 && c <= 126) ? String.fromCharCode(c + 65248) : char
}).join('');
// TODO: Inline the path
const id = `curve-${text.replace(/[^A-Za-z0-9]/g, '')}-oceanwave`
return (
<svg viewBox="0 0 500 160" style={{ height: '10em' }}>
<path id={id} fill="transparent" d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
<text x="10">
<textPath href={`#${id}`}>
{formattedText}
</textPath>
</text>
</svg>
);
},
};

View file

@ -49,7 +49,7 @@ export default class RichDraggable extends Component {
return (
<Draggable bounds={bounds} offsetParent={body} cancel=".no-drag">
<div ref={me.contents} style={{ padding: '10px', position: 'absolute', border: '4px dashed #ddd', cursor: 'move' }}>
<div ref={me.contents} style={{ padding: '10px', position: 'absolute', border: '4px dashed #ddd', cursor: 'move' }} className="creatifyDecor">
<div className="no-drag" style={{ overflow: 'hidden', position: 'relative', cursor: 'auto' }}>
{props.children}
</div>

View file

@ -12,20 +12,89 @@ try {
}
} catch(e) {}
const getRasterizedCanvas = (contents, width, height) => {
return new Promise((resolve) => {
// Resolves a bug in Chrome where it renders correctly, but
// replaces the inline styles with an invalid `background-clip`.
if(/Chrome/.test(navigator.userAgent)) {
contents = contents.replace(/background\-clip:(.*)[;$]/g,
(match, group) => (`-webkit-background-clip:${group};${match}`)
);
}
// Attempt to match font kerning with the DOM.
contents = '<style>svg{font-kerning:normal}</style>' + contents;
rasterizeHTML.drawHTML(contents, document.createElement('canvas'), {
width,
height,
}).then((renderResult) => {
const pixelRatio = 2;
// Why do this? Because Firefox doesn't always give us what we expect
// `background-clip: text` is very broken and does not always render in time.
let img = document.createElement('img');
let canvas = document.createElement('canvas');
img.height = canvas.height = height * pixelRatio;
img.width = canvas.width = width * pixelRatio;
canvas.style.height = `${height}px`;
canvas.style.width = `${width}px`;
let shadowNode = document.createElement('div');
Object.assign(shadowNode.style, {
height: 0,
overflow: 'hidden',
width: 0,
});
document.body.appendChild(shadowNode);
shadowNode.appendChild(img);
//document.body.appendChild(canvas);
var svg64 = btoa(unescape(encodeURIComponent(renderResult.svg)));
var b64Start = 'data:image/svg+xml;base64,';
var image64 = b64Start + svg64;
img.addEventListener('load', () => {
window.requestAnimationFrame(() => {
// We still can't trust Firefox's %$%&* engine, add another 5ms timeout
setTimeout(() => {
let context = canvas.getContext('2d', { alpha: false });
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'white';
context.imageSmoothingEnabled = false;
context.scale(pixelRatio, pixelRatio);
context.fillRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0);
document.body.removeChild(shadowNode);
resolve(canvas);
}, 10);
});
});
img.src = image64;
});
});
};
export default class Creatify extends Component {
constructor(props) {
super(props);
const fontKeys = Object.keys(FontPresets);
this.canvas = React.createRef();
this.contents = React.createRef();
const fontOptions = fontKeys.map(
(fontName) => (
{
value: fontName,
label: <EditableFontface key={fontName} fontFace={FontPresets[fontName]} value={fontName} editable="false" />,
label: (
<div style={{ maxHeight: '150px', maxWidth: '100%', fontSize: '16px', overflow: 'hidden' }}>
<EditableFontface key={fontName} fontFace={FontPresets[fontName]} value={fontName} editable="false" />
</div>
),
fontName,
}
)
@ -49,19 +118,15 @@ export default class Creatify extends Component {
renderContents() {
const me = this;
const canvas = me.canvas.current;
let contents = me.contents.current.innerHTML;
let contents = me.contents.current.outerHTML;
// Resolves a bug in Chrome where it renders correctly, but
// replaces the inline styles with an invalid `background-clip`
contents = contents.replace(/background\-clip:(.*)[;$]/g,
(match, group) => (`-webkit-background-clip:${group};${match}`)
);
rasterizeHTML.drawHTML(contents, canvas).then((renderResult) => {
}, (error) => {
console.log(contents)
// Cheap border/handles removal
contents = `<style>.creatifyDecor{border-color:transparent!important;background-color:transparent!important}</style>` + contents;
getRasterizedCanvas(contents, 600, 500).then((element) => {
console.log(element);
document.body.appendChild(element);
});
}
@ -76,10 +141,9 @@ export default class Creatify extends Component {
<div style={{ flex: 1, display: 'flex' }}>
<div>
<button onClick={() => this.renderContents()}>Rasterize</button>
<canvas ref={me.canvas} width="200" height="200"></canvas>
<Select isSearchable={false} options={state.fontOptions} onChange={(option) => this.setFont(option.fontName)} />
</div>
<div ref={me.contents} style={{ flex: 1 }}>
<div ref={me.contents} style={{ height: '600px', width: '500px', fontSize: '22px', overflow: 'hidden', transform: 'translateZ(0)' }}>
<RichDraggable bounds={state.bounds}>
<EditableFontface fontFace={FontPresets[state.fontName]} value="Hello from LBRY" />
</RichDraggable>