import React, { useState } from "react"; import tinycolor from "tinycolor2"; import _ from "lodash"; import { HeaderH1, HeaderH2, Text, Space, Box, A, Container, Dropzone, Ul, Li } from "./jbx.jsx"; import Styled from "styled-components"; const Textarea = Styled.textarea({ "font-family": "monaco, monospace", border: "none", width: "100%", height: "256px", "font-size": "13px", "line-height": "1.309", padding: "16px 18px", background: "#ecf0f1", color: "#34495e", ":focus": { outline: "none", }, }); import ImageUtils from "base64-image-utils"; const base64ImageToRGBMatrix = ImageUtils.base64ImageToRGBMatrix; function compressColor(rgb) { const hex = tinycolor(rgb).toHexString(); switch ( hex // based on CSS3 supported color names http://www.w3.org/TR/css3-color/ ) { case "#c0c0c0": return "silver"; case "#808080": return "gray"; case "#800000": return "maroon"; case "#ff0000": return "red"; case "#800080": return "purple"; case "#008000": return "green"; case "#808000": return "olive"; case "#000080": return "navy"; case "#008080": return "teal"; } return hex[1] === hex[2] && hex[3] === hex[4] && hex[5] === hex[6] ? "#" + hex[1] + hex[3] + hex[5] : hex; } function resizeImage(base64Str, maxMass = 128 * 128) { return new Promise((resolve) => { let img = new Image(); img.src = base64Str; img.onload = () => { let canvas = document.createElement("canvas"); const originalWidth = img.width; const originalHeight = img.height; let width = img.width; let height = img.height; while (width * height > maxMass) { width = width / Math.sqrt(2, 2); height = height / Math.sqrt(2, 2); } width = Math.round(width); height = Math.round(height); canvas.width = width; canvas.height = height; let ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); resolve([canvas.toDataURL(), { originalWidth, originalHeight }]); }; }); } function App() { const [rgbMatrix, rgbMatrixSet] = useState(null); const [loadingImage, loadingImageSet] = useState(false); function onFileSelected(event) { event.stopPropagation(); event.preventDefault(); const dt = event.dataTransfer; const files = dt ? dt.files : event.target.files; const file = files[0]; const fr = new window.FileReader(); loadingImageSet(true); fr.onload = async (data) => { const base64src = data.currentTarget.result; const [base64] = await resizeImage(base64src); base64ImageToRGBMatrix(base64, (err, data) => { if (err) return console.error(err); rgbMatrixSet(data); loadingImageSet(false); }); }; fr.readAsDataURL(file); } function onDragOver(event) { event.stopPropagation(); event.preventDefault(); } let scale = 1; const masterShadow = _.map(rgbMatrix, (row, rowIndexSrc) => { return _.map(row, (col, colIndexSrc) => { const colIndex = colIndexSrc * scale; const rowIndex = rowIndexSrc * scale; const color = compressColor(`rgb(${col.r},${col.g},${col.b})`); const scaleCompensation = scale !== 1 ? ` 0 ${scale / 2}px` : ``; return `${color} ${colIndex ? colIndex + "px" : 0} ${rowIndex ? rowIndex + "px" : 0}${scaleCompensation}`; }).join(","); }).join(","); const handleFocus = (event) => { event.preventDefault(); event.stopPropagation(); event.target.select(); }; return ( img2css This is a tool that can convert any image into a pure css image. {loadingImage ? ( Processing... ) : (
Drop an image here or click to select
)}
I also made a per-pixel animation experiment, see morphin. {rgbMatrix && (
The result This is your pure css (and single div) image! Enjoy!