JavaScript — Генерация изображения в чистом JS без холста 🌇

BMP dataURI

Вы можете генерировать BMP (битовый массив) dataURI, используя функцию ниже. RAW BMP с 32-битным (но альфа-версия игнорируется браузером, потому что BMP не поддерживает его) — 16×16 RGBA преобразуется в 3249 байтов dataURI

 /** * Generate dataURI raw BMP image * * @param width - image width (num of pixels) * @param pixels - 1D array of RGBA pixels (pixel = 4 numbers in * range 0-255; staring from left bottom corner) * @return dataURI string */ function genBMPUri(width, pixels) { let LE= n={amp}gt;(n 2**32).toString(16).match(/B../g).reverse().join``; let head=`424d${LE(54 pixels.length)}000000003600000028000000${LE(width)}${LE(pixels.length/width/4)}010020${'0'.repeat(50)}`; return "data:image/bmp,"   [...head.match(/../g),...pixels.map(x={amp}gt; x.toString(16).padStart(2,'0'))].map(x={amp}gt;'%' x).join``; } // TEST // 16x16 pixels - 1D Array of pixels (start from bottom-left corner) // where one pixel has 4 color component (each 0-255) RGBA // (but during rendering browser ignore alpha channel - BMP not support alpha) imgagePixels=[0,0,0,255,8,90,114,255,0,0,0,255,0,0,0,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,0,0,0,255,0,0,0,255,0,0,0,255,42,129,252,255,0,0,0,255,8,90,114,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,90,114,255,8,90,114,255,42,129,252,255,42,129,252,255,42,129,252,255,0,0,0,255,8,31,205,255,8,31,205,255,8,90,114,255,8,31,205,255,8,31,205,255,42,129,252,255,8,31,205,255,8,31,205,255,42,129,252,255,8,31,205,255,8,90,114,255,8,90,114,255,42,129,252,255,42,129,252,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,0,0,0,255,0,0,0,255,8,90,114,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,0,0,0,255,0,0,0,255,8,90,114,255,0,0,0,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,90,114,255,8,90,114,255,8,90,114,255,8,31,205,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,42,129,252,255,42,129,252,255,42,129,252,255,42,129,252,255,42,129,252,255,42,129,252,255,42,129,252,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,8,90,114,255,42,129,252,255,42,129,252,255,42,129,252,255,42,129,252,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,42,129,252,255,8,90,114,255,8,90,114,255,42,129,252,255,42,129,252,255,42,129,252,255,8,90,114,255,42,129,252,255,42,129,252,255,42,129,252,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,42,129,252,255,8,90,114,255,42,129,252,255,42,129,252,255,42,129,252,255,8,90,114,255,42,129,252,255,42,129,252,255,8,90,114,255,8,90,114,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,42,129,252,255,42,129,252,255,8,90,114,255,42,129,252,255,0,0,0,255,8,90,114,255,8,90,114,255,8,90,114,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,42,129,252,255,42,129,252,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,8,31,205,255,0,0,0,255,0,0,0,255,42,129,252,255,42,129,252,255,42,129,252,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,42,129,252,255,42,129,252,255,42,129,252,255] uri = genBMPUri(16, imgagePixels); msg.innerHTML = uri; pic.src= uri; 
 img{image-rendering: pixelated;width:128px;height:128px} pre{word-break: break-all;white-space: pre-wrap;} 
 {amp}lt;img id="pic"{amp}gt; {amp}lt;pre id="msg"{amp}gt;Copy below dataURI to browser url top bar or src attrib in img tag{amp}lt;br{amp}gt;{amp}lt;br{amp}gt;{amp}lt;/pre{amp}gt; 

2464 бит 16×16 RGB в кодировке Base64 преобразуется в 1118 байт (примерно в 3 раза меньше, чем RAW)

 /** * Generate dataURI base64 BMP image * * @param width - image width (num of pixels) * @param pixels - 1D array of RGB pixels (pixel = 3 numbers in * range 0-255; staring from left bottom corner) * @return dataURI string */ function genBMPUri(width, pixels) { let LE= n={amp}gt;(n 2**32).toString(16).match(/B../g).reverse().join``; let head=`424d${LE(54 pixels.length)}000000003600000028000000` LE(width)  LE(pixels.length/width/3) `010018` '0'.repeat(50); return "data:image/bmp;base64,"   btoa(String.fromCharCode(...head.match(/../g).map(x={amp}gt;  `0x${x}`)))   btoa(pixels.map(p={amp}gt;String.fromCharCode(p)).join``); } // TEST // 16x16 pixels - 1D Array of pixels (start from bottom-left corner) // where one pixel has 3 color component (each 0-255) RGB imgagePixels=[0,0,0,8,90,114,0,0,0,0,0,0,8,31,205,8,31,205,8,31,205,8,31,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,8,90,114,8,90,114,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,8,90,114,8,90,114,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,0,0,0,0,0,0,0,0,0,42,129,252,0,0,0,8,90,114,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,90,114,8,90,114,42,129,252,42,129,252,42,129,252,0,0,0,8,31,205,8,31,205,8,90,114,8,31,205,8,31,205,42,129,252,8,31,205,8,31,205,42,129,252,8,31,205,8,90,114,8,90,114,42,129,252,42,129,252,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,0,0,0,0,0,0,8,90,114,0,0,0,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,31,205,8,90,114,8,90,114,8,90,114,8,31,205,0,0,0,0,0,0,8,90,114,0,0,0,0,0,0,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,8,31,205,8,90,114,8,90,114,8,90,114,8,31,205,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,129,252,42,129,252,42,129,252,42,129,252,42,129,252,42,129,252,42,129,252,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,8,90,114,42,129,252,42,129,252,42,129,252,42,129,252,8,90,114,8,90,114,8,90,114,8,90,114,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,42,129,252,8,90,114,8,90,114,42,129,252,42,129,252,42,129,252,8,90,114,42,129,252,42,129,252,42,129,252,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,42,129,252,8,90,114,42,129,252,42,129,252,42,129,252,8,90,114,42,129,252,42,129,252,8,90,114,8,90,114,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,90,114,8,90,114,8,90,114,42,129,252,42,129,252,8,90,114,42,129,252,0,0,0,8,90,114,8,90,114,8,90,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,42,129,252,42,129,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,31,205,8,31,205,8,31,205,8,31,205,8,31,205,0,0,0,0,0,0,42,129,252,42,129,252,42,129,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,129,252,42,129,252,42,129,252] uri = genBMPUri(16, imgagePixels); msg.innerHTML = uri; pic.src= uri; 
 img{image-rendering: pixelated;width:128px;height:128px} pre{word-break: break-all;white-space: pre-wrap;} 
 {amp}lt;img id="pic"{amp}gt; {amp}lt;pre id="msg"{amp}gt;Copy below dataURI to browser url top bar or src attrib in img tag{amp}lt;br{amp}gt;{amp}lt;br{amp}gt;{amp}lt;/pre{amp}gt; 

БОНУС

  • Вы не можете использовать нотацию String.fromCharCode(...array) с большими массивами (например, 256 * 256 * 4), это вызовет исключение (вам нужно выполнить преобразование один за другим, как в фрагменте base64 выше).
  • Детали для заголовка BMP примера изображения ( процедура порядка байтов , которая пришла отсюда )
 // hex values, offsets and sizes in little endian head = [ //header (before 16x16 RGBA(32bit) pixels = 1024 bytes raw pixels data) "42", "4d", // "BM" bitmap signature "36", "04", "00", "00", // 0x436 = 1078dec = 16*16*4 54 bytes, total size of header and pixels "00", "00", "00", "00", // reserved "36", "00", "00", "00", // 0x36=54 bytes, header size (pixels raw data start offset) "28", "00", "00", "00", // 0x28=40 bytes, Size of DIB header (type signature) - here: BITMAPINFOHEADER "10", "00", "00", "00", // 0x10=16 pixel, width INT (little endian) "10", "00", "00", "00", // 0x10=16 pixel, height INT (little endian) "01", "00", // reserved "18", "00", // bit per pixel 0x18=24 (1,4,8,16=0x10,24=0x18,32=0x20) "00", "00", "00", "00", // compresion method (0=none) "00", "00", "00", "00", // image size (zero can be given for non-compressed) "00", "00", "00", "00", // horizontal ppm (no matter here) "00", "00", "00", "00", // vertical ppm (no matter here) "00", "00", "00", "00", // number of colors in palette (no palete here) "00", "00", "00", "00", // number of important colors (doesn't matter here) ]; // Conversion to little endian example (padding to 32bit) // 0x45678 -{amp}gt; 0x00045678 -{amp}gt; 0x78560400 LE = (0x45678   2**32).toString(16).match(/B../g).reverse().join``; console.log(LE); 
  • пример кода-фрактала с гольфом (после генерации ~ 5s вы можете щелкнуть по картинке на изображении, скопировать ее адрес и вставить в адресную строку браузера)
 c=256;M=i={amp}gt;{j=x=y=0;while(x*x y*y{amp}lt;4{amp}amp;{amp}amp;  jc)[x,y]=[x*xy*y i%c/64-2,2*x*y i/c/64-2];return ('' 9*j).padEnd(4,7)};s=k='';for(;  k{amp}lt;c*c;)s =M(k); document.write(`{amp}lt;img src=data:image/bmp;base64,Qk02AAMAAAAAADYAAAAoAAAAAAEAAAABAAABABg${'A'.repeat(33) s}{amp}gt;`) 
Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector