The other day I wanted to adapt (well, err, fundamentally: to copy!) the neat javascript trick in diotalevi's home node to my blog. Except that I wanted to roll it on my own image.

Thus I first found the png I wanted; then as a side note I tried to compress it as much as possible: not everybody knows that while png is a well defined standard, much freedom is left to the encoding program; those interested in these topics may find some relevant info in a few bookmarks I gathered.

Next step is to translate the binary data in the image's content into a JS literal string. (To be precise, following diotalevi's example again, in JS code consisting of the concatenation of several literal strings.)

Eventually, it turns out that the neat trick doesn't work any more: with FF3, that is... Whatever, this left me with the quick script I concocted up to do the conversion to JS literal strings, which I'm pasting hereafter. Since JS literal strings are not too different from Perl literal strings, and also independently of this detail, I thought of sharing it:

#!/usr/bin/perl use strict; use warnings; use 5.010; # JS String literals specs from # http://developer.mozilla.org/En/Core_JavaScript_1.5_Guide:Literals#S +tring_Literals { my %subst = ( "\b" => '\\b', "\f" => '\\f', "\n" => '\\n', "\r" => '\\r', "\t" => '\\t', "\cK" => '\\v', q{"} => q{\\"}, q{'} => q{\\'}, q{\\} => q{\\\\}, map { $_ => $_ } 0..7 ); my $lastisnum; sub subst { my $s=$subst{local $_=shift}; ( ($lastisnum, undef) = /\d/ && $lastisnum || !defined $s ? (1, sprintf '\\%o', ord) : (0, $s) )[1]; } } ( my $s = do { use open IN => ':raw'; local $/; scalar <>; } ) =~ s { ([\"\'\\[:^print:]0-7]) }{ subst $1 }gsex; while (defined $s) { my ($c, $t); say +( ($c,$t) = $s =~ /(^.{60,}?)([\D].*)/ ) ? qq|'$c'+| : qq|'$s'|; $s=$t; } __END__

Example output:

'\211PNG\r\n\32\n\0\0\0\rIHDR\0\0\1\364\0\0\1M\b\3\0\0\0\301\315'+ 'm\5\0\0\0\3sBIT\b\b\b\333\341O\340\0\0\0\tpHYs\0\0\4\235\0\0'+ '\4\235\1|\64k\241\0\0\0\31tEXtSoftware\0www.inkscape.org\233'+ '\356<\32\0\0\2\240PLTE\330\356\343\351\241\246\0\222F\316+\67'+ '\316,\67\316-\67\317-\66\317.\67\317/\67\317\60\66\317\60\67'+ '\317\61\66\320\61\66\320\62\66\320\63\66\320\63\67\320\64\66'+ '\320\65\66\320\66\66\320\67\65\3208\66\321\65\66\321\66\66\3218'+ '\66\3219\65\321:\66\321;\65\322;\65\322<\65\322=\65\322=\66\322'+ '>\65\322?\65\323?\65\323@\65\323A\64\323A\65\323B\65\323C\65'+ '\324C\65\324D\65\324E\64\324F\64\324G\64\325G\64\325H\64\325'+ 'I\64\325J\64\326L\64\326M\64\326N\63\326N\64\326O\63\326P\63'+ '\326P\64\326Q\63\326Q\64\327R\63\327S\63\327T\62\327T\63\327'+ 'U\63\330V\63\330W\62\330W\63\330Y\62\331Z\62\331Z\63\331\\2\332'+ ']\62\332^\62\332_\62\332`\62\332a\62\333a\62\333b\61\333c\61'+ '\333d\61\333e\61\333h\61\334g\61\334i\61\334j\61\334k\61\334'+ 'l\60\335n\60\335o\60\336p\60\336q\60\336r\60\336s\60\337t\60'+ '\337v\60\337w/\337x/\340w\60\340x/\340y/\340z/\340|/\340}/\341'+ '}/\341\177/\341\200.\341\200/\341\201.\341\201/\342\202.\342'+ '\203.\342\204.\343\206.\343\207.\343\211.\344\213-\344\214-\345'+ '\215-\345\216-\345\217-\345\220-\345\222-\345\223-\346\223-\346'+ '\224-\346\225-\346\226,\346\227,\347\230,\347\231,\347\232,\347'+ '\233,\350\234,\350\235+\350\235,\350\236,\350\237+\351\237,\351'+ '\242+\351\243+\351\245+\352\243+\352\245+\352\246+\352\247*\352'+ '\247+\352\250+\352\251+\353\252*\353\253*\353\254*\353\256*\354'+ '\257*\354\260)\354\260*\354\261)\354\261*\355\263)\355\263*\355'+ '\264)\355\265)\355\266)\356\266)\356\267)\356\267*\356\270)\356'+ '\271)\356\272)\357\272)\357\273(\357\273)\357\274)\357\275)\357'+ '\276(\357\277(\357\300(\360\300(\360\301(\360\302(\360\303(\360'+ '\304(\361\304(\361\305(\361\306(\361\307(\361\310\'\362\310\'+ ''\362\311\'\362\312\'\362\312(\362\313\'\362\314\'\363\314\''+ '\363\315\'\363\316&\363\316\'\363\317\'\363\320\'\364\320\'\364'+ '\321&\364\322&\364\322\'\364\323&\364\325&\364\326&\365\323&'+ '\365\324\'\365\325&\365\326&\365\327&\365\330%\365\330&\365\331'+ '%\365\331&\365\332&\366\332&\366\333%\366\333&\366\334%\366\335'+ '%\366\336&\367\336%\367\337%\367\337&\367\340%\377\377\377K,'+ '(c\0\0\0\2tRNS\306\306\231\64\332u\0\0\6\375IDATx\332\355\335'+ '\367{\324d\0\300q\64E\252\210\342B\5\334\342@m\35(\212\33\367'+ '@\305\211\342B\334(Kp\3\342\36(nq\357\275\7\342@q\2418\260\342'+ '`\330\63\376+\266M\322\273k\357Z\344\361\7\337\334\347\373S/'+ 'y\357)O?\334%y/\311\365X\275\273z\374\335M\253E\n\253\36\320'+ '\241C\207\16\35:t\350\320\241\v\272\240\v\272\240\v\272\240\'+ 'v\272\240\v\272\376\227\350\365\273\325\371\313\327\334+}\307'+ '\373\247\356\351o_ko\357\275\247\305s\'\354\340\317_c\333\364'+ '\223\232\342\346[w\2P[;r;\275\35\307\205\333\33\21\324\324\336'+ '{\237\33\343\26\366\273w\205PS\207l\247\375\321\302\336<\271'+ '\67\206Z:N\37\276\244E=~\177\30\207Z\232\234\331oq\253za\252'+ '\27{\r\241GC\26\265\252\307s\275\330k\b=j\374\252M}\351\b\26'+ '\265\203\36\3558\277M\275\371t\309D\357\331\253\362\362m?jS\217'+ '/\241\221;\364\272\233\226\275:s\314A\33u^\323\320\224\250_\351'+ 'c\230\274\241OKd\v\363\356\276\374\230\376\345\253NHV\305\67'+ '\360\310\27\372Uq\261\257\6wX9%]q\36\220<\241O.\61\377\256\241'+ '\343\332^\217\'kV\34@$?\350\343K\314\177\252\60\333>`A\262\356'+ '\313\201H\362\202~Q\211\371\17{W\32\261_!Y\373d/&\371@?\257\304'+ '\374\227\375+\217\271\65]?\225I.\320G\227\230\377~p\225A\333'+ '-OG\354\16%\7\350\247\26\212\346\313\16\253:\354\332t\310l(\341'+ '\243\237\330\\4_ql\365q\3\227\244\7\362N\246\t\36\375\270\25'+ 'E\363\277\216\357j\344\304t\324\355T\2G?\262\304<\216\247u\65'+ '\321\272i\272\31(\f\306\22\64\372\241\313\342\262f\366\354b\360'+ '\263\351\240\33\261\204\214~\320oq\207nY\243\372\350\213\263'+ '-\377\0.\341\242\17k*\341\276\63\335bW\237}i\314\206\216\344'+ '\222\17\364\313\242K\223\37fUWO?X\217\257\347\22\360\333\373'+ '\201\355o\357\23[\36]\221\374xo}\265\341\323\323\301\357r\311'+ '\303\216\\2\271:#y\360\300\232UF_\226\375\27\261Q\317\301!\333'+ 'u\311\203\236w%\246\17\257]y\360\250\f\375\4\60\301O\316\314'+ '\314\16\317\353\37JP\37\355Sq\354\341\31\372\65`\202Fo\231\206'+ '\275\255xp\336\347\271\364\23\324\276\225\206\356\232\241\277'+ '\16&l\364\350\220\322C\363\365\337HX\237\253p\202d\264u\206\376'+ '\31\230\300\321\313\353\377A\342\372\322\372]\34\250\177\r&W'+ '\350\321\66\237\'\260\257n\330y\2/C_\4&_\350\321.\v\23\331\67'+ '\67\351\270fD\206\336\4&g\350\321\220t\242\356\355\376\325\16'+ '\331\376\0\223\67\364\350\300\337\23\333\367\266(_>!Co\6\223'+ ';\364\350\350\364S\366\17\266,[\374p\373L\275\v\234\362\207\36'+ '\235\234\236\60\61o\233\222\205u?\267\243\327\223\311\37ztN\252'+ '\373\351\366\25\216\330\342\357\301\344\21=\32\227\372~^<9\252'+ 'x\252\364\213`r\211\36MM\201\277\3309[\362|\361\374\32\60\371'+ 'D\217f\246\302\337\244\347<\357Vz\306\205\362\211\276\306\254'+ '\224xarE\343\364\"\372\241`r\212\36\325g\207h?\16iy\324oI\273'+ '\371\222\265\300\4\216\276\331\231\325\f\327\315\266\342\213'+ '\207F\321\35\305\27\372}\\\2G\257\177\66^pv\25\366\r\336\314'+ '\256_\336\267\364\312\326\63\270\4\216\336vab\65\366\201\37\246'+ '\316\277\226\\\t\263x=.\1\243\367\233rev<^\205}\320\202\270S'+ '\223\260\204\214~\177\251\345\202\363\267\250\60\244\341\333'+ '\216\346K\335\202$h\364\344f\220\247NJ9\v\317\214\351\354\276'+ 'wS\7\364)T\202FO\366\316\33\242\221\355\27=\24\236:w\263\362'+ '-\300\250\227\313\315?\352C%h\3649m\214gE\321\36\363KX\277||'+ '\306\205#\32\7\f\36v\324)c\357[\336\361\335}8\224\240\321OO>'+ '@m\235p\333tN\274rMf\22\62\372\266\255\273q\313\37\230=\276\355'+ 'Q\335\231M+c\376\264\323\'BF?\373\267\16\27(\rzl%\320\233G\61'+ '\t\26\275\367\315m\206\17\226.\253\33\275\260{\365\302h(\201'+ '\242o\365JBxT\371\342\276\343\276\357\236}\f\225 \321w\370:\361'+ '\233\333i\v\335ob\367\233\366\261X\2D\257{*\345\253\364\305,'+ '\353\234\362D\241\202\364kG<\322\376\363E\\\302C\277 \305\233'+ 'S\345\227\16\32\367X\371\35\210\26]\335rs\320\276/\264?\36\7'+ '&\64\364\1K\323=\361.\356\375X\277\317\330kg\277\360\311\307'+ '\357\274\62\347\352\323\366H\316x\336\360\255\f}>\230\320\320'+ '\217[\325[\vl>/}\346\307`BCO\277\305a\326\277\277ba\373/\222'+ '\247\36\17&\64\364\344~A\323Wen\255\361\307\326\247\336\303%8'+ '\364\255[\316\202\371\344\374U\373\367\fm\212\377\234\350\333'+ '\35\2\334{\337x\344\360U\236Bo8i/*a\316\310\t\272\240\v\272\240'+ '\v\272\240\v\272\240\v\272\240\v:t\350\320\241C\207\16\35:tA'+ '\27tA\27tA\27tA\27tA\27tA\27t\350\320\241C\207\16\35:t\350\320'+ '\241\v\272\240\v\272\240\v\272\240\v\272\240\v\272\240\v:t\350'+ '\320\241C\207\16\35:t\350\320\5]\320\5]\320\5]\320\5]\320\5]'+ '\320\5]\320\241C\207\16\35:t\350\320\241\v\272\240\v\272\240'+ '\v\272\240\v\272\240\v\272\240\v\272\240C\207\16\35:t\350\320'+ '\241C\27tA\27tA\27tA\27tA\27tA\27tA\207\16\35:t\350\320\241C'+ '\207.\350\202.\350\202.\350\202.\350\202.\350\202.\350\202\16'+ '\35:t\350\320\241C\207\16\35:tA\27tA\27tA\27tA\27tA\27tA\207'+ '\16\35:t\350\320\241C\207\16\35\272\240\v\272\240\v\272\240\'+ 'v\272\240\v\272\240\v\272\240\v:t\350\320\241C\207\16\35:tA\27'+ 'tA\27tA\27tA\27tA\27tA\27t\350\320\241C\207\16\35:t\350\202.'+ '\350\202.\350\202.\350\202.\350\202.\350\202.\350\320\241C\207'+ '\16\35:t\350\320\5]\320\5]\320\5]\320\5]\320\5]\320\5]\320\241'+ 'C\207\16\35:t\350\320\241C\207.\350\202.\350\202.\350\202.\350'+ '\202.\350\202.\350\320\241C\207\16\35:t\350\320\241C\27tA\27'+ 'tA\27tA\27tA\27tA\27tA\207\16\35:t\350\320\241C\207.\350\202'+ '.\350\202.\350\202\256\377\266\177\0\227h\376\312\300\24!\1\0'+ '\0\0\0IEND\256B`\202'

Update: added defined in the while clause as per ikegami's remark.

--
If you can't understand the incipit, then please check the IPB Campaign.

Replies are listed 'Best First'.
Re: Simple binary data to JS string literal converter
by ikegami (Patriarch) on Sep 16, 2008 at 08:58 UTC

    while ($s)
    should be
    while (length($s))

    It would also be nice if the wrapping occurs after at most 60 characters, instead of after at least 60 characters (with no maximum!)

      while ($s)
      should be
      while (length($s))

      I personally believe that you're partially right: after all I may end up with $s eq "0"! D'oh! But then length would leave me with an uninitialized warning on the last iteration. Thus I'd use defined instead: worse luck, if it were not for 0 being a valid octal digit, I wouldn't have needed it in !defined $s above, either!

      It would also be nice if the wrapping occurs after at most 60 characters, instead of after at least 60 characters (with no maximum!)

      You're probably right: but to be fair, the splitting was more of an afterthought than anything else. I was primarily concerned with the conversion, and I hope not to have left errors there. (Now, if I had some spare time, I would make this into a Perl string literal converter, and then use eval to check... Perhaps, after lunch I'll do! ;)

      --
      If you can't understand the incipit, then please check the IPB Campaign.
Re: Simple binary data to JS string literal converter
by ambrus (Abbot) on Sep 16, 2008 at 14:23 UTC

    Would Lehman's JSON::XS module work? Any advantages or drawbacks over yours?

      I personally believe that judging from its description (I only gave a glance to it) it would indeed work: I saw UTF-8 mentioned and I hope it's customizable, because I clearly need to work on a byte oriented string instead. However an obvious advantage of the module over my poor piece of code is that the former is reasonably tested and thus more likely to be correct: as I already wrote I didn't use a module mainly out of not having thought of doing so...

      --
      If you can't understand the incipit, then please check the IPB Campaign.
Re: Simple binary data to JS string literal converter
by Anonymous Monk on Sep 16, 2008 at 05:14 UTC
    You probably could have used JSON::Any Wrapper Class for the various JSON (JavaScript Object Notation encoder/decoder) classes. or Data::JavaScript

      I personally believe you're forgetting the fun ;) of reinventing the wheel: honestly I just didn't think of it and beforehand I wouldn't even have known which module to search, except that javascript may have been a good start. Since it was just a quick hack, it would have been perfectly sensible. However, reinventing the wheel (if so!) did turn out to be both fun and instructive: there have been more subtleties than I would have naively assumed!

      --
      If you can't understand the incipit, then please check the IPB Campaign.