HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<h1>ENTROPX - a pretty limited drawing language</h1>
<p>Author: Mario Klingemann - @Quasimondo<br/><br/>
ENTROPX is a minimalistic language designed to create pixel and glitch art. Letters of the alphabet move the brush by a certain x/y offset, their distance and direction can be looked up in the grid below.</p>
<div id="holder">
<canvas id="output" width="512" height="512">
</div>
<div>Presets:
<select onchange="document.getElementById('code').value =renderer.lzw_decode(this.value.substr(1));draw(this.value)" id="presets">
<option value="$#mnmsā3meessts3t4ot17orĐ3rnęneĆbćmmęġkonooGGoa6āwĄĄvĜsĝmann5Ħ5ćsUu3ħħĦĨńeĕsŅŊoŌŊĊDołęwaodr6na4ĠŊgĨQq1ĆVvĨg11ĦŪķŝe6ċĥebċ3ċsĥŊtđĻroIŏŌtĆeķłĽĊĐsůķāĦrƎaŷōĄjaġƓm">Phone</option>
<option value="$7ses3e6ot3ăeme13muou4mam3a3nr5onaağ6ěęě3opoc18ćĉe21mLLxmmsxossgeqĠĉľĻăĞnĆļħ4nxrnnmveaœrŔiŔhrrueehuśĻrtnoţţħāšĶsĕa">Phone 2</option>
<option value="$#onnanrrornāoosme4oaāmēotss3o3Ęr3ăĄaĠğġmmsĘ3e7ĕĠaaħĩ5ĩĨČĎsaseĻ3ď4ĘtĆmj">Dog</option>
<option value="$#nonntā10nx6sus3H4nmshmneăwsosm3aćmLdąooknub3ĂQbēsbnr3ĝm5sChċaxt3ĉsěĎowi4oīĂĜĂr5nwnaĄt4sdspěĵo6nLlāŢŋţa7ełcř8Ĝ9ĞnpŜĄpŌcēa3ĞstĿożžĜŻĵumeeķĝŃrłĂijŖĬŀİmđwĖFkžxaexŖĴĄăĦro4rijƦrƟčĝăgłgŀtŏĖmaaƓĒơƭĂaĝŏrňŇscƺƍVJHĒēbĝŖ7ĜēQŖƽƉg6oĴŋƦo8ƹƹwoFf8ēodŹŽ3tŻċčŨbimēŮłŸƬIJƵndmŞŋǝm7sjėnvȁjđœǠnfDzƆłƴĝƆtĦŲāśŻĸĿŗǞǸsLDžuegǧěăvċmjmDZǍěƩhƆőŒƴƷŸŒŨǫkȔȽĜňŀƽ4ȷƱăƦGgŝāaŏĦNJnjtKƮcƣƎĂȔĒĴēĖ31ŷŨo">Cyclist</option>
<option value="$64mLLlmmeesstorFntĊećČ6Iiuāe46ċ62č33n6hĤiBm8namĬĊČ12scnisinmx21smĿeoēnnčĩĊĮĺʼnŅŀĿōŌŋŏŒŊŎŕőcoumķœŖŐŞŘgŚśŝŗšœfĆpőşŔŅřoUĆŦŠŧĮďŴpŠ3ĮooĺcŴĆsosŽĺrtnhbĿģp36nrrʼnĢs55oļ1nų7n42m7s4GčƔ10ođ11ŜuIJĞohāa5Ɣ3ƶſkƆĆq4Ʈ5seŽiƛr1ģƕƮđǐċČƪƕnuimaǍſđGƩ1ĝƣmǠnwnqŎfoĝĆarƶmŻēiſdžŜƪoǴhr9ƇŊſhćƐǷǘǣ4ņǰLJȈƋȀĆhǰȏȁm4ȅƬĤoƬsFHHhĊǃŅǹƀČĐƛĐȣ19ƀņljoȇƄƅeuņǮŽsĭȷŀǓȲĺŀȸwčgr5ŀńrȶƅDȮȳƼȁsuɇȺƈɑċŀȳoȵɒĮɔĭćnCnƅņs7ƀƆưɦsȩȫŀĮɭŋɮmtǙŏɯɶɵŏȶɮɸɻɽnɺȽɳĭʂɈŷŶʇnĉǿJngƚoV3ȝ8Ǚ27Ŋʖč8Ʈs9mD3ƩDGg6ľe70Ǚ7ơǯʐVae8Ʀtt7ǃƕʳĬaƔʸIJġčˁǕaĭ˅ǙǙʼǎʮɇƮǃtƼˏƮſǯrˆ˅ˌņȏȸĮɄ˄ȖkǽgȴɣƆƀadƇġmw6ƆłxɲĆɰĤŀƛx˭ƕ1ƺQėƦuģțŅǮƳʪeah1ʸr̂ǠćİěsB5ųdžĒ̖̕ĉĈĦ̋̋ƔŅ̝̋k̠̟ƓĦpaIJ6mjIJǪ̈̄̂2̪Ĉ4ċeĝđċİ̺sˢĬ̂̿̾ƔNj2Ġʵ̗ĉdžBUUudž3͎sŻŽʼǃƷȾɵmlɄċƆƧ̫jǵfŅʊĺjj͏tpćƺĚōŬŏvƼōʼƛsboʤ˥nkģ̪tDgŽeĬĮʼĐȪķasII˩ȈĊǼƶnjǙn˺ƪnʗěΔ˭ͽŎǚĿȇưɭ͏jŅ4ʔ͏ΧˮĆɳĮ;˲ŽbmkʔxoK͝ĭĩōŋaāɵ͏ĉΊɮ͔ƶοɻξĻǃͶɵΆDZȊŀpłĿɱƷɬʹƀrǭmģξsJ̈ʪ͏Ƭǹȷŏʗ͌āh͵ſΆ˴̴ʗ̴NjǃŬĮIJϝsNj1ˮɢͼ̞Ώ͵ēWɲ˥͝ȳāiǃ͏rϋˢʸȽcƼ͏ΊĉАoƂǙģxЌϧŎИˏȽυ̋ΔЃϧЗƢƶƼϕ̴ĮŽ˨ājŀ͝Čȟ̫дİƼrřкΗſɿŜŽгkСģǭЪķȮȈсϙ̼nЃLjοǓɢtȇǜȺſЕοQsj̋͛жΚċл̸̞tűhƼxƼƂϙǥЬpͷѬƽρ͓ōŎLJΔȽĒūu5ʔѪmѪƮģāŬĦhɥŬxˑ̝ȣоҏеѥΏѤпғġĺiуLjҜт̫ҝ̫̝ѣČpā̟ģʞ͏QQʼΆΆ͍̹̹ǐtƖʛ˨ҵ˥Ħ͝һɣƅƅҼĊҾҽӁҿӄӃӆӅƶӇӊӉӌӋӂӀӐӏӒӈӓӖӎӘӍӔӘ˥ƅǯƅţcӓӡoXϻ̝ʱōńśǶŐȳӮmϡg1ɥgJHŅѧлĵoͨƛͱmӻLdǵLƩɪʔѿƛtșҦmVhʞξƔ˭ӻſL3ĹhгЮŅĦǥğćƴ6ʛXėː˺s">Apple Mac</option>
<option value="$:[email protected]@IhrmmsĎuąunra7oP3mtmjoĈxvnn3oscđu3nčtėĤmui4ĈIĥĬioUuUmwačsğď[email protected]ĴaxĚtğpŁĦěĥanoLoĔkĚhčŕgğrĚrCC4mĻĚaĴGgĴ">Mario</option>
<option value="$#ossmnmĂlmaĄneănČaraeđunongĘmu3ęěĖn6oisĘh8āĘ5o8stĆıse4ėsrjČnHėąuĎĿĄwĮoohĶi4ĦĵcĶpŊoĵo5s5mĵŗăĵavąs">House</option>
<option value="$#9miIsi12op11ĂixĂ6oVu13oXi4soe2Č30noonĢi2Ė25smsGgoĠn26ĭs24ı0s5mrhmmJhc1ĵh15ĒjĖŅĵHnʼno">Notes</option>
<option value="$#amaāăĂĄanrna3es8tUmsmnċĔĖ5Ĉ4Ċnmmr3ntssx5nh4Ğ3seīm9Ĕ9Ğ10ĔĶĞIJmĢĪĺĔĭopnfoGo4em12soĹt5siĥo8ģ7Ŏ6ģŒňnňŎĖoĥ3oşšţottrr4ŪġŦģšĉĭ5o7np4sjėstēmİāĂğƅƈƇƆĈşċşĢţŎĮƑőŪ7Ū6ŪoIsĉşŞŮĉĨ5Ă6ƥƧżjmt6ĔśāeĞřfģİƮŀŽľhĵķƔŔtƚǀǂǁǁĔ">Intro</option>
<option="$#ogotonāorng25ntČsmssaēmneėmęuĚęněmcĒġģđğĆHn8ą7mhoowāsąĆĵĆnaĒĈĠĺĖĠrėeĺaĆoĻeēoĵsQm3ĔnĘŋĵr3ĎspsińĤĠđn5m17īćĸąĚđu9Ť9s5oPĵĂtğġĠĜmkĈmĝđ26ĹrŗŌ3ěűoŘg3Ō4ĒƊƌƎsƐēŲƓƏƑƘĊƔƖƒnDŌūĵ22sUmėo18n11Ē10Ƭ6sŊūƹn">Help</option>
<option value="$4so7nrā21spmkor23nmnooāsmt22ėėeemmae12ġa18ġnĄĘt33o1ĐmeĀe3sķ4ġ4ĄĽrĿĐŀoēāntŅńĮoWm4ĕńŐŇʼnŔŒŒ11ĕuĩ">File Index</option>
<option value="$#nooqss3oāannttoąĎeaaĆ3mLDgb14sGgĝamme3nusmnmsPsoeĂn8Ĉćjmarogĩt5s7o4āteiĂĹtĦmkorĦaća9āİ3itįŋrīŜmŜćċ4Ĉīeue8m16seģĦoa12nk4Ū7sVneŅĩĪĹruģāċĤĤĩ7ngobsiĺŜxŃĪo5n6ăģBƇeĩŰkmunKg5Ƣ7m21sŷŃćWŪ1ncĂHnĖĝPIIiŪ0ƘĪwĖĦƙQsĴCƅĎČŤĪĤīīĬžƄrƈĪeŃĺďsŜ">Book Shelf</option>
<option value="$#9stoonąnenĆnm3ngse3oĎxo5naĊosĂĝĜmĝt16sfĤČěsoĤspđġĒ1ma18nrąt7otĝağćhĩ8mk12Ĝ3mes4Ľor4īĘwĉĆrrĸn">Address</option>
<option value="$16sm15n3m9Ănmno7ċāaąm3Ă3ċsĊĘseėm4Ă4ċ7sctoočsĨPĊmmsiĕČnuīsu1Ģă5ķľČaċĻnnt11ċĉĈċe18st7ĩt6ĩoīĢoĠo6ċĆİįŞrtsr3ocĕo12č1ijāŧnjęğŅtŮŝņŏİLLGo3ňŁŅī3ijĜ34maa3ŭrrŖīĪƓƖƕƘŗƗƚƙƔƜŗrsŕn5m">Slide Show</option>
<option value="$7unn14o16se4mhoor5nammFn3mIsċJnĚe5st5oiĘsĢcgĉĉemĒBmotsīeĴĮaahnmsixľaĨm3Ē4sŅĽńĽrŋŊonlsoņdĒanrijr3őŎĘa1ņ">Bazinga</option>
<option value="$#sesQi3stssdtwmĂćĉĂeĆtLs3oręrnnr6naġ3ġĚotħħĨdm5ĈxnHHĞoVJijmQpsjĝĢrĤĜłęięġodeĨĜaoxrĚđĎmœďďĈĈĐŚŖŗĆeĖœĉjmaŔťťĂĈeœJhn3ĚĚtĨħ6ěōřeŊoohosſā5œmāāmbrdėtmkżt4ħƇƅťsĢ3mve4ŕĆFƐtĘaruƎogƆſocĉņĨntĜųėūƶŔēmžočsąmƥĜƛsxť3ĢĢġĝłQmľůĢ4LjLjNJƘŧƙƷ3ĒƷūǎŐĞNjn6űűęǦŀǦijǠa4nxoľŎrŏŇŏőƔƆŘŞIitVvĚ">Rex</option>
<option value="$#orrngtānnamesuaĊm6sIs11mHnoFoćĉċssVwĒmmLġp8sCHH3Ěn13oaot3stĈosoĚľŀĿo9ĢVďxttĺĆġ3mĊ3awŊijsrġĦsŐř8nmİhhXĔsJĉİpmswrāŏsemnrċūsahŠśġŊĝ4Ěgo4ĺdmwŲaĨŁŋŘĝeĽŰūĽƎnĴĆăĚĽŃŗşşųŴŁnĻDoĖs27m29ƚƖŠ1ƨ9Ʀ5npƵx1Ƶ">TO DO</option>
<option value="$3i9oxsp9mWuseanončotĐčdnmnrnbęscěĎĐnĖĘđosjn18ď16mUmsĘIJĘ4IJ3oIs10mHn6ďįeėijee26sttohĎchĬœmvĎsď3hjĘoŒĽoāmpsxĂţāĺĻmiŢćťŭ15ďŐŐoħeřċŻīďor28ėņř27sU3ŞovĽmhšhcďmjhćhŴŷħŭĹŷřnƎľhƑ0ům">Weekly</option>
<option value="$#uiighgăQăFFouVmhuHHn8oĔmenmsmĚĜĞĝěměsosiħsunĖaĬnĮjĖģğĢĠķĶĹĵĜee7sGoGŁĄĆĄh3āQmBUm6sDŁŁ3ŇāuĐiQŎŎĿŒG4ŖiŘŊmuŎ3stt17ĖhnŰŰĭűŵrĥseŸźĦĨżŹŻŸ1ĕĬr28ĚĞĥ2ĿVačjĂŤţhągFňŘąăgLog">Calendar</option>
<option value="$#asmne4sosunUmĉno3nwnčăPsxĎonhn4m9s3ěnrćss4oaďntĨģnĭįeģrijİĤěĴĪIJĐĥĜoěmmeĨčBčĊĿkĔĂărķbĭĬdĔ4nađĈħcŎgďćšěĈĦěģŏĨačČĔčįĈwst3ųńspŢőGěcJľĮsņiħeņťĮšQsŮųpďĈņWuĨ8o2ŘƗ5s10ăe9ăč13mā5m25nŨńƤĢorđŕaīŕĔřśćŃpĈżřƉŜĺŸƄjĂųįūųŵƇŤŢtĥđŒĭķāeĜjšsŖăţǞǂľĈmpŲįčkƂŵljůbǐgłĢmĆĈĊ">HyperCalc</option>
<option value="$16on15menmsmĈĊČċĉďčĐĎĔēmĉoiosoĂ28ěĝnoteeĘkssCă8ĊĪěeuĜdģo25Ĉm3ģstnģğses42ċģĿw26ģģ3ĊdńordčbĊĄĜĪĉKĂěbetşěğşkanćVjģ7naĊĦgopěpũċrmpĆsũŎĢėŪŀĻſŐaŐĝĜbĆƃroahČŃĜŸn3ĻrcŰŐćnijƕėwĢĂĈacŔmŘėįĉĜş3ƐưŰhěĜnƶİsrĪtĜļċkexƁƅ">Clip Art</option>
</select><input type="checkbox" checked id="showCursor" onclick="drawCodeArea()">Show Cursor <input type="checkbox" id="drawToCursor" onclick="drawCodeArea()">Draw to Cursor
<br/>
<p id="label1">ENTROPX-Code: </p>
<textarea id="code" cols="50" rows="7" oninput="drawCodeArea()" onkeydown="if (drawToCursor.checked) drawCodeArea()"></textarea>
<table id="lower">
<tr>
<td>q</td>
<td>p</td>
<td>i</td>
<td>x</td>
<td>l</td>
</tr>
<tr>
<td>b</td>
<td>e</td>
<td>s</td>
<td>t</td>
<td>d</td>
</tr>
<tr>
<td>u</td>
<td>m</td>
<td> </td>
<td>o</td>
<td>g</td>
</tr>
<tr>
<td>w</td>
<td>a</td>
<td>n</td>
<td>r</td>
<td>k</td>
</tr>
<tr>
<td>v</td>
<td>j</td>
<td>h</td>
<td>c</td>
<td>f</td>
</tr>
</table>
<p id="label2">Compressed ENTROPX-Code: </p>
<textarea id="lzw" oninput="draw(this.value)" cols="50" rows="3"></textarea>
</div>
<p><strong>Commands a-x and A-X</strong><br/>
Lowercase letters move the cursor and set a pixel, uppercase letters just move the cursor but don't draw anything. The drawing always starts with an empty 1x1 canvas and the image will recenter and resize itself automatically based on the set pixels.
<br/>
<br/><strong>Numbers 0-4096</strong><br/>
Prepending commands with a number will repeat them that many times - "8o" for example will draw an 8 pixel horizonal line. The maximum limit of 4096 is arbitrary, but put in place to prevent the creation of huge bitmaps in particular when glitching is used.
<br/>
<br/><strong>Command '@'</strong><br/>A '@' is the control code to change the current paint color. A '@' can either be followed by a letter or one or more numbers. The letters a-z and A-Z stand for the numbers 0 to 51, so the command '@d' is equivalent to '@3'. The paint color is taken from the currently selected color palette. If the number is bigger than the colors available in the chosen palette the index will wrap around. The default color black is always '@0' or '@a'<br/>
<br/><strong>Command ':'</strong><br/>A ':' is the control code to change the current color palette. Same like the color chooser a ':' can either be followed by a letter or one or more numbers. The default color palette is ':0' or ':a'
<br/><br/><strong>Command '='</strong><br/>
The '=' is a control code and will use the immediately following numbers or letter to change the cursor to a special brush. So for example the command '=1' will pick brush #1 which is a fat 2x2 pixel - alternative this can be written as '=b'. Note: switching a brush will not also draw it. Furthermore some brushes are drawing around the current pixel, others (like bigger pattern fills) will use the current pixel as the top left corner.<br/>
<br/><strong>Command '#'</strong><br/>A '#' will draw the brush at the current location. With the default 1 pixel brush this will not make any visible difference, but with the other brushes this allows for some interesting combinations.
<br/>
<br/><strong>Commands '+' and '*'</strong><br/>The characters '+' and '*' will apply a bucket fill at the current position using the current color. The '+' will not fill across diagonally connected pixels, whereas the '*' will do that. Since the canvas does not really have a boundary, the bounding box of the currrently set pixels will be the outer limit for the fill.
<br/>
<br/><strong>Command '!'</strong><br/>The character '!' has a special meaning: every occurrence of '!' will be replaced with a random letter from the range a-x,A-X, this can be used to introduce random glitches into the pixture. The replacement takes place in the ENTROPX.decode() routine so the resulting image will always be different whenever the string is decoded again.
<br/>
<br/><strong>Command '.'</strong><br/>The character '.' will move the cursor back to the starting point.
<br/>
<br/><strong>Command ';'</strong><br/>The character '|' will set the current cursor position as the center for the symmetry draw mode, the default center is at 0/0
<br/>
<br/><strong>Command '|'</strong><br/>The character '|' followed by a number will set the symmetry mode: 0 = no symmetry, 1 = horizontal, 2 = vertical, 3 = horizonal + vertical. As with the other commands, the numbers can be replaced by letters.
<br/>
<br/><strong>Command '()'/'[]'</strong><br/>Anything inside brackets will define a pattern. The pattern will be added to a temporary list of patterns and get an index based on the order of definition. The first pattern will get index 0 or 'a', the second pattern will get index 1 or 'b' and so on. Since you can use patterns inside of patterns it is theoretically possible to create infinite loops which is why there is the MAX_CODE_LENGTH limit that stops the recursion once the resulting code gets too long. Also note that if you are having leading or trailing numbers in a pattern it's a good idea to prepend or append a "_" to avoid merging neighboring numbers that might emerge from consecutive patterns. The difference between the parantheses and the square brackets is that () will not draw the pattern when it is defined whereas [] will also draw it immediately.
<br/>
<br/><strong>Command '%'</strong><br/>The '%' followed by a number or letter code will draw a previously defined pattern. If the index is higher than the number of defined patterns it will wrap around. If there are no defined patterns at all the command will be ignored. Since the processing is sequential you cannot use a pattern before it is defined e.g. "(oonnmmss)%0" will work, but "%0(oonnmmss)" will not. Note that inserting a pattern will change the cursor position depending on the relative final cursor position of the stored pattern.
<br/>
<br/><strong>Special character '_'</strong><br/>The underscore '_' can be used to separate numbers. For example when first switching a brush and then drawing it repeatedly: '03_4f'. This necessary since '034f' would mean 'use brush 34 and paint it at offset 2/2'. Don't use spaces to separate numbers since those will be cleaned from the code before the rendering.
<br/>
<br/><strong>Unknown characters</strong><br/>Unknown letters, spaces or line breaks will be simply ignored and processing skips to the next known command. There are no error messages.
<br/>
<br/><strong>Compressed ENTROPX - '$'</strong><br/>ENTROPX has also the option to use LZW compression, the LZW-compressed version starts with a "$" and can be seen in the smaller text edit box. For some unexpected glitch effects you can also directly edit inside the LZW code. Note that compression only works for the entire string, you cannot use compressed strings inside of patterns.<br/>
<br/><strong>About</strong><br/>ENTROPX is inspired by the concept of Freeman chain codes and PCC line coding as well as L-Systems but is designed to use a charset that is within the printable (and tweetable) code range and offers opportunities for introducing interesting glitches easily. It also adds the option to use colors as well as some other features that are useful for creating pixel art. Another design deliberation was to generate code that can be used to train RNNs or LSTMs for teaching machines how to draw like humans.<br><br>
When saved to a file, the desired suffix for the ENTROPX format is ".epx" which seems to be already used in the past for some 3d model files but I honestly don't care.
</p>
<div id="brushes">Brushes:</div>
<div id="palettes">Color Palettes:</div>
<footer class="footer">
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a> <span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">ENTROPX</span> by <span xmlns:cc="http://creativecommons.org/ns#"
property="cc:attributionName">Mario Klingemann</span> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
</footer>
html {
height: 100%;
box-sizing: border-box;
}
body {
position: relative;
margin: 10px;
padding-bottom: 6rem;
min-height: 100%;
font-family: "Trebuchet MS", Helvetica, sans-serif;
}
h1 {font-weight:normal}
div,p,table {font-size:0.9em;margin:3px; }
p {width:600px;}
td {width:16px;height:16px;text-align:center;}
#code {display:inline-block;}
#lower {color:white;background-color:#000;border:1px solid black;}
#label2 #label1 {display:block;}
footer {font-size:0.8em;margin-top:64px;}
.footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
padding: 1rem;
background-color: #efefef;
text-align: center;
}
textarea { display:inline-block;margin-right:3px; }
canvas {vertical-align:middle;}
#brushes { display:inline-block;height: 30px;font-size:1em;}
/*
ENTROPX by Mario Klingemann v1.0 January 2016
is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
LZW-encoder/decoder code by Julien Bouquillon
https://gist.github.com/revolunet/843889
Color palettes transcribed from Wikipedia:
https://en.wikipedia.org/wiki/List_of_software_palettes
https://en.wikipedia.org/wiki/List_of_video_game_console_palettes
*/
window["qlib"] = window.qlib || {};
(function() {
var ENTROPX = function(defaultPixelSize, numberLimit, maxCodeLength) {
this.init(defaultPixelSize, numberLimit, maxCodeLength)
}
var p = ENTROPX.prototype;
p.init = function(defaultPixelSize, numberLimit, maxCodeLength) {
if (numberLimit == undefined)
this.NUMBER_LIMIT = 4096
else
this.NUMBER_LIMIT = numberLimit
if (maxCodeLength == undefined)
this.MAX_CODE_LENGTH = 200000
else
this.MAX_CODE_LENGTH = maxCodeLength
if (defaultPixelSize == undefined)
this.DEFAULT_PIXEL_SIZE = 10
else
this.DEFAULT_PIXEL_SIZE = defaultPixelSize
this.code2step = {
'#': [0, 0],
'o': [1, 0],
'r': [1, 1],
'n': [0, 1],
'a': [-1, 1],
'm': [-1, 0],
'e': [-1, -1],
's': [0, -1],
't': [1, -1],
'g': [2, 0],
'k': [2, 1],
'f': [2, 2],
'c': [1, 2],
'h': [0, 2],
'j': [-1, 2],
'v': [-2, 2],
'w': [-2, 1],
'u': [-2, 0],
'b': [-2, -1],
'q': [-2, -2],
'p': [-1, -2],
'i': [0, -2],
'x': [1, -2],
'l': [2, -2],
'd': [2, -1],
'=': 'pick brush',
'@': 'pick color',
':': 'pick palette',
'.': 'origin',
'_': 'draw',
'+': 'bucket cross',
'*': 'bucket star',
'(': 'start pattern',
')': 'end pattern',
'[': 'start pattern and draw',
']': 'end pattern and draw',
'%': 'insert pattern',
';': 'set symm center',
'|': 'set symm mode'
}
this.palettes = [{
name: 'Default Mono',
c: [0x000000, 0xffffff]
}, {
name: '2 Bit Greyscale',
c: [0x000000, 0x8b8b8b, 0xcccccc, 0xffffff]
}, {
name: '4 Bit Greyscale',
c: [0x000000, 0x171717, 0x262626, 0x353535, 0x454545, 0x555555, 0x656565, 0x757575, 0x868686, 0x979797, 0xa8a8a8, 0xb9b9b9, 0xcacaca, 0xdbdbdb, 0xededed, 0xffffff]
}, {
name: '3 Bit RGB',
c: [0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00, 0xffffff]
}, {
name: '4 Bit RGBI',
c: [0x000000, 0x000091, 0x009100, 0x009191, 0x910000, 0x910091, 0x919100, 0xb7b7b7, 0x686868, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00, 0xffffff]
}, {
name: 'NES',
c: [0x000000, 0x101010, 0x7a7a7a, 0xbababa, 0xd6d6d6, 0xfbfbfb, 0xffffff, 0x3200ff, 0x5171fb, 0x7bb6fd, 0xbae0fc, 0x2500bd, 0x4450fb, 0x7882ff, 0xb8b5f9, 0x4625bd, 0x673eff, 0x9274fb, 0xcfb6f9, 0x7d1984, 0xb724ce, 0xdc7afb, 0xe7b7f90, 0x8c2326, 0xbf2f5a, 0xd56298, 0xe1a5bf, 0x8c2905, 0xd24c00, 0xd87e57, 0xe4d0ac, 0x712500, 0xc4650f, 0xe2a33f, 0xf1e0a3, 0x483400, 0x9b7d00, 0xe3ba00, 0xecd971, 0x437500, 0x66b400, 0xc9f700, 0xdef86e, 0x3a6600, 0x5da400, 0x8bd549, 0xcbf6b3, 0x315700, 0x5ea43d, 0x9cf590, 0xccf6d5, 0x284058, 0x4f8486, 0x87e3d5, 0x94f7fb]
}, {
name: '3 Level RGB',
c: [0x000000, 0x000091, 0x0000ff, 0x910000, 0x910091, 0x9100ff, 0xff0000, 0xff0091, 0xff00ff, 0x009100, 0x009191, 0x0091ff, 0x919100, 0x919191, 0x9191ff, 0xff9100, 0xff9191, 0xff91ff, 0x00ff000, 0x00ff91, 0x00ffff, 0x91ff00, 0x91ff91, 0x91ffff, 0xffff00, 0xffff91, 0xffffff]
}, {
name: 'C64',
c: [0x000000, 0xffffff, 0x880000, 0xaaffee, 0xcc44cc, 0x00cc55, 0x0000aa, 0xeeee77, 0xdd8855, 0x664400, 0xff7777, 0x333333, 0x777777, 0xaaff66, 0x0088ff, 0xbbbbbb]
}, {
name: 'CGA 0',
c: [0x000000, 0x00aa00, 0x55ff55, 0x55ff55, 0xff5555, 0xaa5500, 0xffff55]
}, {
name: 'CGA 1',
c: [0x000000, 0xffffff, 0x00aaaa, 0x55ffff, 0xaa00aa, 0xff55ff, 0xaaaaaa]
}, {
name: 'CGA 2',
c: [0x000000, 0xffffff, 0x00aaaa, 0x55ffff, 0xaa0000, 0xff5555, 0xaaaaaa]
}, {
name: 'Windows 16',
c: [0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xC0C0C0, 0x808080, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF]
}, {
name: 'Windows 20',
c: [0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xC0C0C0, 0xC0DCC0, 0xA6CAF0, 0xFFFBF0, 0xA0A0A4, 0x808080, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF]
}, {
name: 'Mac 16',
c: [0x000000, 0x1FB714, 0xFBF305, 0x006412, 0xFF6403, 0x562C05, 0xDD0907, 0x90713A, 0xF20884, 0xC0C0C0, 0x4700A5, 0x808080, 0x0000D3, 0x404040, 0x02ABEA, 0xFFFFFF]
}, {
name: 'RISC 16',
c: [0x000000, 0xFFFFFF, 0xDDDDDD, 0xBBBBBB, 0x999999, 0x777777, 0x555555, 0x333333, 0x004499, 0xEEEE00, 0x00CC00, 0xDD0000, 0xEEEEBB, 0x558800, 0xFFBB00, 0x00BBFF]
}, {
name: "ATARI 2600 NTSC",
c: [0x00000, 0x404040, 0x6c6c6c, 0x909090, 0xb0b0b0, 0xc8c8c8, 0xdcdcdc, 0xececec, 0x444400, 0x646410, 0x848424, 0xa0a034, 0xb8b840, 0xd0d050, 0xe8e85c, 0xfcfc68, 0x702800, 0x844414, 0x985c28, 0xac783c, 0xbc8c4c, 0xcca05c, 0xdcb468, 0xecc878, 0x841800, 0x983418, 0xac5030, 0xc06848, 0xd0805c, 0xe09470, 0xeca880, 0xfcbc94, 0x880000, 0x9c2020, 0xb03c3c, 0xc05858, 0xd07070, 0xe08888, 0xeca0a0, 0xfcb4b4, 0x78005c, 0x8c2074, 0xa03c88, 0xb0589c, 0xc070b0, 0xd084c0, 0xdc9cd0, 0xecb0e0, 0x480078, 0x602090, 0x783ca4, 0x8c58b8, 0xa070cc, 0xb484dc, 0xc49cec, 0xd4b0fc, 0x140084, 0x302098, 0x4c3cac, 0x6858c0, 0x7c70d0, 0x9488e0, 0xa8a0ec, 0xbcb4fc, 0x000088, 0x1c209c, 0x3840b0, 0x505cc0, 0x6874d0, 0x7c8ce0, 0x90a4ec, 0xa4b8fc, 0x00187c, 0x1c3890, 0x3854a8, 0x5070bc, 0x6888cc, 0x7c9cdc, 0x90b4ec, 0xa4c8fc, 0x002c5c, 0x1c4c78, 0x386890, 0x5084ac, 0x689cc0, 0x7cb4d4, 0x90cce8, 0xa4e0fc, 0x003c2c, 0x1c5c48, 0x387c64, 0x509c80, 0x68b494, 0x7cd0ac, 0x90e4c0, 0xa4fcd4, 0x003c00, 0x205c20, 0x407c40, 0x5c9c5c, 0x74b474, 0x8cd08c, 0xa4e4a4, 0xb8fcb8, 0x143800, 0x345c1c, 0x507c38, 0x6c9850, 0x84b468, 0x9ccc7c, 0xb4e490, 0xc8fca4, 0x2c3000, 0x4c501c, 0x687034, 0x848c4c, 0x9ca864, 0xb4c078, 0xccd488, 0xe0ec9c, 0x442800, 0x644818, 0x846830, 0xa08444, 0xb89c58, 0xd0b46c, 0xe8cc7c, 0xfce08c]
}, {
name: "ATARI 2600 PAL",
c: [0x000000, 0x282828, 0x505050, 0x747474, 0x949494, 0xb4b4b4, 0xd0d0d0, 0xececec, 0x805800, 0x947020, 0xa8843c, 0xbc9c58, 0xccac70, 0xdcc084, 0xecd09c, 0xfce0b0, 0x445c00, 0x5c7820, 0x74903c, 0x8cac58, 0xa0c070, 0xb0d484, 0xc4e89c, 0xd4fcb0, 0x703400, 0x885020, 0xa0683c, 0xb48458, 0xc89870, 0xdcac84, 0xecc09c, 0xfcd4b0, 0x006414, 0x208034, 0x3c9850, 0x58b06c, 0x70c484, 0x84d89c, 0x9ce8b4, 0xb0fcc8, 0x700014, 0x882034, 0xa03c50, 0xb4586c, 0xc87084, 0xdc849c, 0xec9cb4, 0xfcb0c8, 0x005c5c, 0x207474, 0x3c8c8c, 0x58a4a4, 0x70b8b8, 0x84c8c8, 0x9cdcdc, 0xb0ecec, 0x70005c, 0x842074, 0x943c88, 0xa8589c, 0xb470b0, 0xc484c0, 0xd09cd0, 0xe0b0e0, 0x003c70, 0x1c5888, 0x3874a0, 0x508cb4, 0x68a4c8, 0x7cb8dc, 0x90ccec, 0xa4e0fc, 0x580070, 0x6c2088, 0x803ca0, 0x9458b4, 0xa470c8, 0xb484dc, 0xc49cec, 0xd4b0fc, 0x002070, 0x1c3c88, 0x3858a0, 0x5074b4, 0x6888c8, 0x7ca0dc, 0x90b4ec, 0xa4c8fc, 0x3c0080, 0x542094, 0x6c3ca8, 0x8058bc, 0x9470cc, 0xa884dc, 0xb89cec, 0xc8b0fc, 0x000088, 0x20209c, 0x3c3cb0, 0x5858c0, 0x7070d0, 0x8484e0, 0x9c9cec, 0xb0b0fc]
}
]
this.brushes = [
[
[0, 0]
],
"onms",
"#sonnmmss",
"#sart",
"#eghu",
"#poornnammess",
"ggaurgau",
"3gauurggauurggauu",
"4ga3ur3ga3ur3ga3ur3ga3u",
"3Ooor3ma5o=1n3M#3M#=0knaagtorgees",
"g7O#a5M#ab4n11o4sw7m=1aGogGoh4u=0ca9O#ePs5m",
"=1r4grnmUuUuenRgGg=0fkmbumumwo3Xs3o"
]
this.emptyCanvas = {
width: 1,
height: 1,
pixels: [],
cursor: [0, 0],
color: 0
}
this.drawCommands = 'abcdefghijklmnopqrstuvwxABCDEFGHIJKLMNOPQRSTUVWX'
this.allowed = this.drawCommands + '_#yzYZ0123456789.!*+()%@:=;|[]'
for (var i = 0; i < this.brushes.length; i++) {
if (!Array.isArray(this.brushes[i])) {
this.brushes[i] = this.decode(this.brushes[i], true)
}
}
}
p.clean = function(code) {
var cleancode = ''
for (var i = 0; i < code.length; i++) {
if (this.allowed.indexOf(code[i]) > -1)
cleancode += code[i]
}
return cleancode;
}
p.decode = function(code, getRawOutput) {
if (code != undefined && code[0] == "$")
code = this.lzw_decode(code.substr(1))
if (code == "" || code == undefined || code == "$") {
return getRawOutput ? [] : this.emptyCanvas
}
var x = 0
var y = 0
var minx = 0
var miny = 0
var maxx = 0
var maxy = 0
var symx = 0
var symy = 0
var symMode = 0
var currentBrush = this.brushes[0]
var currentPalette = this.palettes[0].c
var currentColor = currentPalette[0]
var patterns = []
var patternBuildingStack = []
var patternBuildingIndex = -1
var addPattern = null;
var pixels = []
var cleancode = this.clean(code)
while (cleancode.indexOf("!") > -1)
cleancode = cleancode.replace("!", this.drawCommands[(Math.random() * 48) | 0])
code = cleancode
var p = 0
while (p < code.length) {
var mode = 'DRAW'
if (code[p] == '=') {
//change brush command
p++
if (p == code.length)
break;
if (code[p] >= 'a' && code[p] <= 'z') {
currentBrush = this.brushes[(code.charCodeAt(p) - 'a'.charCodeAt(0)) % this.brushes.length];
p++
continue;
} else if (code[p] >= 'A' && code[p] <= 'Z') {
currentBrush = this.brushes[(26 + code.charCodeAt(p) - 'A'.charCodeAt(0)) % this.brushes.length];
p++
continue;
} else if (code[p] >= '0' && code[p] <= '9') {
mode = 'CHANGE BRUSH'
} else if (code[p] == '_') {
mode = 'CHANGE BRUSH'
p++
} else {
currentBrush = this.brushes[0]
}
} else if (code[p] == '@') {
//change color command
p++
if (p == code.length)
break;
if (code[p] >= 'a' && code[p] <= 'z') {
currentColor = currentPalette[(code.charCodeAt(p) - 'a'.charCodeAt(0)) % currentPalette.length];
p++
continue;
} else if (code[p] >= 'A' && code[p] <= 'Z') {
currentColor = currentPalette[(26 + code.charCodeAt(p) - 'A'.charCodeAt(0)) % currentPalette.length];
p++
continue;
} else if (code[p] == '_') {
mode = 'CHANGE COLOR'
p++
} else if (code[p] >= '0' && code[p] <= '9') {
mode = 'CHANGE COLOR'
} else {
p -= 1;
}
} else if (code[p] == ':') {
//change palette command
p++
if (p == code.length)
break;
if (code[p] >= 'a' && code[p] <= 'z') {
currentPalette = this.palettes[(code.charCodeAt(p) - 'a'.charCodeAt(0)) % this.palettes.length].c;
currentColor = currentPalette[currentColor % currentPalette.length]
p++
continue;
} else if (code[p] >= 'A' && code[p] <= 'Z') {
currentPalette = this.palettes[(26 + code.charCodeAt(p) - 'A'.charCodeAt(0)) % this.palettes.length].c;
currentColor = currentPalette[currentColor % currentPalette.length]
p++
continue;
} else if (code[p] == '_') {
mode = 'CHANGE PALETTE'
p++
} else if (code[p] >= '0' && code[p] <= '9') {
mode = 'CHANGE PALETTE'
} else {
p -= 1;
}
} else if (code[p] == '%') {
//insert pattern command
p++
if (p == code.length)
break;
if (code[p] >= 'a' && code[p] <= 'z') {
if (patterns.length > 0) {
var insertPattern = patterns[(code.charCodeAt(p) - 'a'.charCodeAt(0)) % patterns.length];
console.log("insert",insertPattern)
console.log("code",code)
var newcode = code.slice(0, p + 1) + insertPattern + code.slice(p + 1)
if (newcode.length <= this.MAX_CODE_LENGTH)
code = newcode
console.log("code",code)
}
p++
if ( p < code.length) console.log("next is",code[p])
continue;
} else if (code[p] >= 'A' && code[p] <= 'Z') {
if (patterns.length > 0) {
var insertPattern = patterns[(26 + code.charCodeAt(p) - 'A'.charCodeAt(0)) % patterns.length];
console.log("insert",insertPattern)
console.log("code",code)
var newcode = code.slice(0, p + 1) + insertPattern + code.slice(p + 1)
if (newcode.length <= this.MAX_CODE_LENGTH)
code = newcode
console.log("code",code)
}
p++
continue;
} else if (code[p] == '_') {
mode = 'INSERT PATTERN'
p++
} else if (code[p] >= '0' && code[p] <= '9') {
mode = 'INSERT PATTERN'
} else {
p -= 1;
}
} else if (code[p] == '|') {
//set symm mode
p++
if (p == code.length)
break;
if (code[p] >= 'a' && code[p] <= 'z') {
symMode = (code.charCodeAt(p) - 'a'.charCodeAt(0)) % 4;
console.log("set symm mode",symMode)
p++
continue;
} else if (code[p] >= 'A' && code[p] <= 'Z') {
symMode = (26 + code.charCodeAt(p) - 'A'.charCodeAt(0)) % 4;
console.log("set symm mode",symMode)
p++
continue;
} else if (code[p] >= '0' && code[p] <= '9') {
mode = 'SET SYMM MODE'
} else if (code[p] == '_') {
mode = 'SET SYMM MODE'
p++
} else {
symMode = 0
}
}
var n = 0
var hasNumber = false
while (p < code.length && code[p] >= '0' && code[p] <= '9') {
n *= 10
n += code[p] | 0
p += 1
hasNumber = true
}
if ( !hasNumber ) n=1
if (mode == "CHANGE BRUSH") {
currentBrush = this.brushes[n % this.brushes.length]
continue;
} else if (mode == "CHANGE COLOR") {
currentColor = currentPalette[n % currentPalette.length]
continue;
} else if (mode == "CHANGE PALETTE") {
currentPalette = this.palettes[n % this.palettes.length].c;
currentColor = currentPalette[currentColor % currentPalette.length]
continue;
} else if (mode == "INSERT PATTERN") {
console.log("INSERT PATTERN")
if (patterns.length > 0) {
var insertPattern = patterns[n % patterns.length];
var newcode = code.slice(0, p) + insertPattern + code.slice(p)
if (newcode.length <= this.MAX_CODE_LENGTH)
code = newcode
}
continue;
} else if (mode == "SET SYMM MODE") {
symMode = n % 4;
console.log("set symm mode",symMode)
continue;
}
if (n > this.NUMBER_LIMIT)
n = this.NUMBER_LIMIT
if (n < 0)
n = 0
if (p == code.length)
break;
step = this.code2step[code[p].toLowerCase()]
for (var i = 0; i < n; i++) {
switch (step) {
case 'origin':
x = y = 0
continue;
break;
case 'set symm center':
symx = x;
symy = y;
continue;
break;
case 'end pattern':
case 'end pattern and draw':
case 'pick color':
case 'pick palette':
case 'pick brush':
case 'draw':
case undefined:
continue
break;
case 'insert pattern':
p++;
var nn = 0
while (p < code.length && (code[p] >= '0' && code[p] <= '9' || code[p]=='_')) {
if ( code[p]!='_')
{
nn *= 10
nn += code[p] | 0
}
p += 1
}
var insertPattern = patterns[nn % patterns.length];
while (i < n) {
var newcode = code.slice(0, p) + insertPattern + code.slice(p)
if (newcode.length <= this.MAX_CODE_LENGTH)
code = newcode
console.log(newcode)
i++
}
p--;
if ( p < code.length) console.log("insert pattern, next is",code[p])
continue
break;
case 'bucket cross':
this.bucketFill(pixels, x, y, minx, miny, maxx, maxy, currentColor, currentBrush, false)
continue
break;
case 'bucket star':
this.bucketFill(pixels, x, y, minx, miny, maxx, maxy, currentColor, currentBrush, true)
continue
break;
case 'start pattern':
case 'start pattern and draw':
var pattern = ''
p++;
patternBuildingIndex++;
var append = ''
while (p < code.length) {
if (code[p] != '(' && code[p] != ')' && code[p] != '[' && code[p] != ']')
pattern += '' + code[p]
else if (code[p] == ')' || code[p] == ']') {
if (patternBuildingIndex > -1) {
patterns.push(pattern)
if (code[p] == ']') append += '' + pattern
patternBuildingStack[patternBuildingIndex] = pattern
patternBuildingIndex--
}
if (patternBuildingIndex > -1) {
pattern = patternBuildingStack[patternBuildingIndex]
} else {
pattern = ''
break;
}
} else if (code[p] == '(' || code[p] == '[') {
if (patternBuildingIndex > -1) {
patternBuildingStack[patternBuildingIndex] = pattern
}
patternBuildingIndex++;
pattern = ''
}
p++
}
if (step== 'start pattern and draw')
{
console.log("append",append)
console.log("code",code)
var newcode = code.slice(0, p+1) + append + code.slice(p+1)
if (newcode.length <= this.MAX_CODE_LENGTH) code = newcode
console.log("newcode",newcode)
}
continue;
break;
default:
x += step[0]
y += step[1]
break;
}
if (code[p] == code[p].toLowerCase()) {
for (var j = 0; j < currentBrush.length; j++) {
var px = x + currentBrush[j][0]
var py = y + currentBrush[j][1]
pixels.push([px, py, currentColor])
minx = Math.min(px, minx)
miny = Math.min(py, miny)
maxx = Math.max(px, maxx)
maxy = Math.max(py, maxy)
if (symMode == 1)
{
pixels.push([symx-px, py, currentColor])
minx = Math.min(symx-px, minx)
maxx = Math.max(symx-px, maxx)
}
if (symMode == 2)
{
pixels.push([px, symy-py, currentColor])
miny = Math.min(symy-py, miny)
maxy = Math.max(symy-py, maxy)
}
if (symMode == 3)
{
pixels.push([symx-px, py, currentColor])
pixels.push([px, symy-py, currentColor])
pixels.push([symx-px, symy-py, currentColor])
minx = Math.min(symx-px, minx)
maxx = Math.max(symx-px, maxx)
miny = Math.min(symy-py, miny)
maxy = Math.max(symy-py, maxy)
}
}
}
}
p += 1
}
if (getRawOutput) {
return pixels;
}
var w = 0
var h = 0
for (p in pixels) {
pixels[p][0] -= minx
pixels[p][1] -= miny
w = Math.max(w, pixels[p][0])
h = Math.max(h, pixels[p][1])
}
w += 1
h += 1
return {
width: w,
height: h,
pixels: pixels,
cursor: [x - minx, y - miny],
color: currentColor
}
}
p.bucketFill = function(pixels, x, y, minx, miny, maxx, maxy, currentColor, currentBrush, fillDiagonally) {
if (x < minx) minx = x
if (y < miny) miny = y
if (x > maxx) maxx = x
if (y > maxy) maxy = y
var stackIndex = 0;
var stack = [
[x, y]
]
var pIndex = pixels.findIndex(function(e) {
return e[0] == x && e[1] == y
})
if (pIndex > -1)
var baseColor = pixels[pIndex][2]
else
baseColor = -1
if (baseColor == currentColor) return;
while (stackIndex < stack.length) {
var p = stack[stackIndex]
stackIndex++
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] && e[1] == p[1]
})
if (pIndex != -1) {
pixels[pIndex][2] = currentColor
} else {
pixels.push([p[0], p[1], currentColor])
}
if (p[0] - 1 >= minx && stack.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1]
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1]
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] - 1, p[1]])
}
if (p[0] + 1 <= maxx && stack.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1]
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1]
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] + 1, p[1]])
}
if (p[1] - 1 >= miny && stack.findIndex(function(e) {
return e[0] == p[0] && e[1] == p[1] - 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] && e[1] == p[1] - 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0], p[1] - 1])
}
if (p[1] + 1 <= maxy && stack.findIndex(function(e) {
return e[0] == p[0] && e[1] == p[1] + 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] && e[1] == p[1] + 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0], p[1] + 1])
}
if (fillDiagonally) {
if (p[0] - 1 >= minx && p[1] - 1 >= miny && stack.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1] - 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1] - 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] - 1, p[1] - 1])
}
if (p[0] - 1 >= minx && p[1] + 1 <= maxy && stack.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1] + 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] - 1 && e[1] == p[1] + 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] - 1, p[1] + 1])
}
if (p[0] + 1 <= maxx && p[1] + 1 <= maxy && stack.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1] + 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1] + 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] + 1, p[1] + 1])
}
if (p[0] + 1 <= maxx && p[1] - 1 >= miny && stack.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1] - 1
}) == -1) {
pIndex = pixels.findIndex(function(e) {
return e[0] == p[0] + 1 && e[1] == p[1] - 1
})
if ((pIndex == -1 && baseColor == -1) || (pIndex > -1 && pixels[pIndex][2] == baseColor))
stack.push([p[0] + 1, p[1] - 1])
}
}
}
}
p.renderToCanvas = function(epxData, scale, canvas, autoScale, padding, renderCursor) {
if (scale == undefined) scale = this.DEFAULT_PIXEL_SIZE
if (padding == undefined) padding = 0
var padx = 0
var pady = 0
if (canvas == undefined) {
var canvas = document.createElement("canvas")
canvas.width = Math.min(this.NUMBER_LIMIT, scale * epxData.width + padding * 2)
canvas.height = Math.min(this.NUMBER_LIMIT, scale * epxData.height + padding * 2)
} else {
if (autoScale) {
scale = Math.max(1, Math.min((canvas.width - 2 * padding) / epxData.width, (canvas.height - 2 * padding) / epxData.height)) | 0
}
var padx = (padding + 0.5 * (canvas.width - scale * epxData.width)) | 0
var pady = (padding + 0.5 * (canvas.height - scale * epxData.height)) | 0
}
var ctx = canvas.getContext("2d");
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#000';
var lastColor = 0
var p = epxData.pixels
for (var i in p) {
if (lastColor != p[i][2]) {
lastColor = p[i][2]
ctx.fillStyle = '#' + ("000000" + (lastColor & 0xffffff).toString(16)).slice(-6);
}
ctx.fillRect(padx + p[i][0] * scale, pady + p[i][1] * scale, scale, scale);
}
if (renderCursor) {
ctx.strokeStyle = '#000';
ctx.strokeRect(padx + epxData.cursor[0] * scale - 1.5, pady + epxData.cursor[1] * scale - 1.5, scale + 3, scale + 3)
ctx.strokeStyle = '#' + ("000000" + (epxData.color & 0xffffff).toString(16)).slice(-6);
ctx.strokeRect(padx + epxData.cursor[0] * scale, pady + epxData.cursor[1] * scale, scale, scale)
ctx.strokeStyle = '#ffffff';
ctx.strokeRect(padx + epxData.cursor[0] * scale + 1.5, pady + epxData.cursor[1] * scale + 1.5, scale - 3, scale - 3)
}
return canvas
}
p.decodeAndRender = function(code, scale, canvas, autoScale, padding, renderCursor) {
return this.renderToCanvas(this.decode(code), scale, canvas, autoScale, padding, renderCursor)
}
p.lzw_encode = function(s) {
if (s == '' || s == undefined) return ''
var dict = {};
var data = (s + "").split("");
var out = [];
var currChar;
var phrase = data[0];
var code = 256;
for (var i = 1; i < data.length; i++) {
currChar = data[i];
if (dict[phrase + currChar] != null) {
phrase += currChar;
} else {
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
dict[phrase + currChar] = code;
code++;
phrase = currChar;
}
}
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
for (var i = 0; i < out.length; i++) {
out[i] = String.fromCharCode(out[i]);
}
return out.join("");
}
p.lzw_decode = function(s) {
var dict = {};
var data = (s + "").split("");
var currChar = data[0];
var oldPhrase = currChar;
var out = [currChar];
var code = 256;
var phrase;
for (var i = 1; i < data.length; i++) {
var currCode = data[i].charCodeAt(0);
if (currCode < 256) {
phrase = data[i];
} else {
phrase = dict[currCode] ? dict[currCode] : (oldPhrase + currChar);
}
out.push(phrase);
currChar = phrase.charAt(0);
dict[code] = oldPhrase + currChar;
code++;
oldPhrase = phrase;
}
return out.join("");
}
qlib["ENTROPX"] = ENTROPX;
}());
//-----------------------------------------------------------------------------------------------
function drawCodeArea()
{
if (drawToCursor.checked)
draw(code.value.substring(0,code.selectionStart))
else
draw(code.value)
}
function draw(text) {
renderer.decodeAndRender(text, undefined, output, true, 5, showCursor.checked)
if (!drawToCursor.checked)
{
if (text[0] == "$") {
lzw_output.value = text
code.value = renderer.lzw_decode(text.substr(1))
} else {
lzw_output.value = "$" + renderer.lzw_encode(text)
code.value = text
}
}
label2.innerHTML = "Compressed ENTROPX-Code - " + lzw_output.value.length + " chars:"
label1.innerHTML = "ENTROPX-Code - " + code.value.length + " chars:"
}
var renderer = new qlib.ENTROPX()
var output = document.getElementById("output")
var lzw_output = document.getElementById("lzw")
var code = document.getElementById("code")
var label1 = document.getElementById("label1")
var label2 = document.getElementById("label2")
var brushes = document.getElementById("brushes")
var palettes = document.getElementById("palettes")
var holder = document.getElementById("holder")
var presets = document.getElementById("presets");
var showCursor = document.getElementById("showCursor");
var drawToCursor = document.getElementById("drawToCursor");
var brushesPerRow = 8
var table = document.createElement('table');
for (var i = 0; i < renderer.brushes.length; i++) {
if (i % brushesPerRow == 0) {
var row1 = table.insertRow();
var row2 = table.insertRow();
}
var cell1 = row1.insertCell()
var cell2 = row2.insertCell()
cell1.style.width = "50px"
cell2.style.width = "50px"
var p = document.createTextNode("=" + i + ":");
cell2.appendChild(p)
cell1.appendChild(renderer.decodeAndRender("=" + i + "#", 5, null, false, 3))
}
brushes.appendChild(table)
brushes.style.height = "200px"
var table = document.createElement('table');
table.style.width = "600px"
for (var i = 0; i < renderer.palettes.length; i++) {
var row = table.insertRow();
var cell = row.insertCell()
//cell.style.width = "100px"
cell.style.textAlign = "left"
var p = document.createTextNode(":" + i + " (" + renderer.palettes[i].name + "): ");
cell.appendChild(p)
cell.style.verticalAlign = "top"
var cell2 = row.insertCell()
//cell2.style.width = "300px"
cell2.style.textAlign = "left"
var swatchesPerRow = 16
var pstring = ":" + i + "_M"
for (var j = 0; j < renderer.palettes[i].c.length; j++) {
if (j % swatchesPerRow == 0 && j > 0) {
var y = (j / swatchesPerRow) | 0;
var v = "N"
if (y == 2)
v += "N"
else if (y > 2)
v = y + v
pstring += "." + v + "M"
}
pstring += "@" + j + "o"
}
var cnv = renderer.decodeAndRender(pstring, 16, null, false, 0, false)
cnv.style.border = "1px solid #000";
cnv.style.padding = "0"
//cnv.style.margin = "0"
cell2.appendChild(cnv)
}
palettes.appendChild(table)
presets.selectedIndex = 0
presets.onchange()
/*
Yes, you read correctly, this code is currently licenced under creative commons and not some kind of "do whatever you like" license. This means that if you reuse this code or language soemwhere else or make a derivate I want to see something like "using ENTROPX by Mario Klingemann" visible on that page - and no, not just somewhere hidden in the source code. Yes, I am that vain. And just so we understand each other: no commercial use wihout my written permisson.
*/
Also see: Tab Triggers