1- import React , { useState } from "react" ;
1+ import React , { Fragment , useState } from "react" ;
22import tinycolor from "tinycolor2" ;
33import _ from "lodash" ;
44
55import {
66 HeaderH1 ,
7- HeaderH2 ,
87 Text ,
98 Space ,
109 Box ,
@@ -13,11 +12,14 @@ import {
1312 Dropzone ,
1413 Ul ,
1514 Li ,
16- } from "./jbx.jsx" ;
15+ Tabs ,
16+ Tab ,
17+ Inline ,
18+ } from "jbx" ;
1719
1820import Styled from "styled-components" ;
1921
20- import { imageToRGBMatrix } from "canvas-image-utils" ;
22+ import { imageToRGBMatrix , imageToRawData } from "canvas-image-utils" ;
2123
2224const Textarea = Styled . textarea ( {
2325 fontFamily : "monaco, monospace" ,
@@ -65,6 +67,9 @@ function compressColor(rgb) {
6567}
6668
6769function App ( ) {
70+ const [ outputType , outputTypeSet ] = useState ( "SHADOW" ) ;
71+ const [ originalSize , originalSizeSet ] = useState ( 0 ) ;
72+ const [ base64Data , base64DataSet ] = useState ( "" ) ;
6873 const [ rgbMatrix , rgbMatrixSet ] = useState ( null ) ;
6974 const [ loadingImage , loadingImageSet ] = useState ( false ) ;
7075
@@ -76,14 +81,21 @@ function App() {
7681 const files = dt ? dt . files : event . target . files ;
7782 const file = files [ 0 ] ;
7883
84+ originalSizeSet ( file . size ) ;
85+
7986 const fr = new window . FileReader ( ) ;
8087
8188 loadingImageSet ( true ) ;
8289
8390 fr . onload = async ( data ) => {
8491 const base64src = data . currentTarget . result ;
85- const dataMatrix = await imageToRGBMatrix ( base64src , { size : 150 } ) ;
92+ const dataMatrix = await imageToRGBMatrix ( base64src , { size : 200 } ) ;
93+ const canvasRawData = await imageToRawData ( base64src , {
94+ size : 1080 ,
95+ crop : false ,
96+ } ) ;
8697
98+ base64DataSet ( canvasRawData . ctx . canvas . toDataURL ( "image/jpeg" , 0.66 ) ) ;
8799 rgbMatrixSet ( dataMatrix ) ;
88100 loadingImageSet ( false ) ;
89101 } ;
@@ -168,35 +180,104 @@ function App() {
168180 </ Text >
169181
170182 { rgbMatrix && (
171- < div >
183+ < Fragment >
172184 < Space h = { 2 } />
173- < HeaderH2 > The result</ HeaderH2 >
174- < Space h = { 1 } />
175- < Text > This is your pure css (and single div) image! Enjoy!</ Text >
176- < Space h = { 1 } />
177- < div
178- style = { {
179- height : 1 ,
180- width : 1 ,
181- boxShadow : masterShadow ,
182- marginBottom : rgbMatrix [ 0 ] . length * scale ,
183- marginRight : rgbMatrix . length * scale ,
184- } }
185- />
185+ < Tabs >
186+ < Inline >
187+ < Tab
188+ active = { outputType === "SHADOW" }
189+ key = { "SHADOW" }
190+ onClick = { ( ) => {
191+ outputTypeSet ( "SHADOW" ) ;
192+ } } >
193+ < Text > { "Pure CSS" } </ Text >
194+ </ Tab >
195+ < Tab
196+ active = { outputType === "BASE64" }
197+ key = { "BASE64" }
198+ onClick = { ( ) => {
199+ outputTypeSet ( "BASE64" ) ;
200+ } } >
201+ < Text > { "Base64" } </ Text >
202+ </ Tab >
203+ </ Inline >
204+ </ Tabs >
186205 < Space h = { 1 } />
187- < Textarea
188- onFocus = { handleFocus }
189- onChange = { ( ) => { } }
190- className = "code"
191- value = { `<div style="margin-right: ${
192- rgbMatrix [ 0 ] . length * scale
193- } px; margin-bottom: ${
194- rgbMatrix . length * scale
195- } px; height: 1px; width: 1px; box-shadow: ${ masterShadow } "></div>`}
196- />
197- < Space h = { 1 } />
198- < Text > Size: { masterShadow . length . toLocaleString ( ) } b</ Text >
199- </ div >
206+
207+ { outputType === "BASE64" && (
208+ < Fragment >
209+ < Text >
210+ < strong > The result (base64).</ strong > { " " }
211+ {
212+ "This is your image tag a base64 output. The entire image file is embedded inside the `<img>` tag using base64, so no need external hosting is needed."
213+ }
214+ </ Text >
215+ < Space h = { 1 } />
216+
217+ < img
218+ src = { base64Data }
219+ style = { { maxWidth : "100%" , height : "auto" , display : "block" } }
220+ />
221+
222+ < Space h = { 1 } />
223+
224+ < Textarea
225+ onFocus = { handleFocus }
226+ onChange = { ( ) => { } }
227+ className = "code"
228+ value = { `<img src="${ base64Data } " />` }
229+ />
230+ < Space h = { 1 } />
231+ < Text >
232+ Output size (resized): { base64Data . length . toLocaleString ( ) } b
233+ </ Text >
234+ < Text >
235+ Original size: { Number ( originalSize ) . toLocaleString ( ) } b
236+ </ Text >
237+ </ Fragment >
238+ ) }
239+
240+ { outputType === "SHADOW" && (
241+ < Fragment >
242+ < Text >
243+ < strong > The result (pure CSS).</ strong > This is your pure CSS
244+ (and single div) image, enjoy! This output was created by
245+ resizing and setting each pixel as a box-shadow of a single pixel div, so
246+ no `img` tag or `background-image` is needed. This can result
247+ in huge outputs, and the use of this output is not recommended
248+ for production unless there is no other option.
249+ </ Text >
250+ < Space h = { 1 } />
251+ < div
252+ style = { {
253+ height : 1 ,
254+ width : 1 ,
255+ boxShadow : masterShadow ,
256+ marginBottom : rgbMatrix [ 0 ] . length * scale ,
257+ marginRight : rgbMatrix . length * scale ,
258+ } }
259+ />
260+ < Space h = { 1 } />
261+ < Textarea
262+ onFocus = { handleFocus }
263+ onChange = { ( ) => { } }
264+ className = "code"
265+ value = { `<div style="margin-right: ${
266+ rgbMatrix [ 0 ] . length * scale
267+ } px; margin-bottom: ${
268+ rgbMatrix . length * scale
269+ } px; height: 1px; width: 1px; box-shadow: ${ masterShadow } "></div>`}
270+ />
271+ < Space h = { 1 } />
272+ < Text >
273+ Output size (resized): { masterShadow . length . toLocaleString ( ) } b
274+ </ Text >
275+ < Text >
276+ Original size: { Number ( originalSize ) . toLocaleString ( ) } b
277+ </ Text >
278+ </ Fragment >
279+ ) }
280+ </ Fragment >
200281 ) }
201282
202283 < Space h = { 2 } />
0 commit comments