17
\$\begingroup\$

This is a variation.

Introduction

We all write short code, because some obscure reasons, but whatever we do, the'll take up at least 144 pixels/byte (with a 12px font). But what would happen, if we would encode our code in images? This is your task today.

Challenge

You task is to read in your own source code (non-proper quines are allowed, e.g. literally reading the source file), and create an image out of it, by setting the red, green and blue components of a pixel based on the ASCII value of the character.

Example:

We have the string "Hello world!"

Hello world!

Let's convert this to ASCII values:

72 101 108 108 111 32 119 111 114 108 100 33

Map the RGB values to it (If the source code's length is not divisible by 3, use 0s as the remaining characters):

 __________________________________________________
| R | G | B || R | G | B || R | G | B || R | G | B |
----------------------------------------------------
|72 |101|108||108|111|32 ||119|111|114||108|100|33 |
----------------------------------------------------

We then create the image with the smallest area out of it. We have 4 sets of RGB values, so the smallest image will be a 2*2 image, going from the top left pixel to the right:

enter image description here

And we get this awfully colored image (resized, so it's at least visible, also proves the fact how small it can get)

Rules/Additional information

  • There's no input
  • The output should be as a separate file, or in a separate window.
  • For multibyte characters, split the character in 2 bytes.
  • The source code must be at least 1 byte long
  • The image should be the one from the possible sizes, wich has the closest width/height ratio to 1
  • The pixel count on the image should exactly be ceil(byte count / 3), no extra pixels should be added

Scoring

This is a , so the smallest answer in bytes wins.

\$\endgroup\$
  • 7
    \$\begingroup\$ Waiting for a Piet submission... :P \$\endgroup\$ – Rɪᴋᴇʀ May 17 '16 at 14:38
  • 3
    \$\begingroup\$ What is "the smallest image"? Smallest area? Wouldn't this always be a straight line? Does the image have to be square? If so, how do we pad pixels that don't fit in the square? Could you provide some sample solutions? (Not necessarily with source code, just any string) \$\endgroup\$ – DJMcMayhem May 17 '16 at 15:26
  • 2
    \$\begingroup\$ Still not super clear. Which is more important, smallest area, or smallest width to heighth ratio? What if it was three, or any other prime number of pixels? Should I do 1x3 (smallest area) or 2x2 with a pixel missing (smallest ratio)? What should that missing pixel be? \$\endgroup\$ – DJMcMayhem May 17 '16 at 16:22
  • 3
    \$\begingroup\$ Was this on the sandbox? It seems like it could've used some time there. \$\endgroup\$ – Morgan Thrapp May 17 '16 at 16:38
  • 1
    \$\begingroup\$ Isn't the smallest width/height ratio technically going to always be height = N and width = 1? I think you mean width/height closest to 1. \$\endgroup\$ – Suever May 17 '16 at 17:37

10 Answers 10

1
\$\begingroup\$

Actually, 12 bytes

Q"P6 4 1 255

Try it online!

This program also works in Seriously.

This program outputs a PPM image, which is acceptable by default.

Output image (scaled up 50x):

output

Explanation:

Q"P6 4 1 255 
Q             push source code
 "P6 4 1 255  push header for a 4x1 raw (type P6) 8-bit PPM image (the closing " is implicitly added at EOF)
\$\endgroup\$
  • 2
    \$\begingroup\$ OP: The output should be as a separate file. Doesn't this just output the file contents to STDOUT? \$\endgroup\$ – Adám May 19 '16 at 6:49
8
\$\begingroup\$

MATLAB, 81 72 69 bytes

@()image(shiftdim(reshape(evalin('base','char(ans)'),3,1,23)/255,1.))

This creates an anonymous function which can be pasted into the command window and run using ans(). When run this creates a 23-pixel image (a prime) therefore the most square representation is a simple array of pixels.

enter image description here

Explanation

When pasted into the command window, the anonymous function will automatically assign itself to the variable ans. Then from within the anonymous function, we use:

evalin('base', 'char(ans)')

which evaluates char(ans) within the namespace of the command window rather than within the local namespace of the anonymous function. It is therefore able to convert the anonymous function itself into a string representation.

Then we have the following operations which are more straightforward:

%// Reshape the result into a 3 x 1 x 23 matrix where the first dimension is RGB
%// due to column-major ordering of MATLAB
R = reshape(string, 3, 1, 23);

%// Divide the result by 255. This implicitly converts the char to a double
%// and in order for RGB interpreted properly by MATLAB, doubles must be
%// normalized between 0 and 1.
R = R / 255;

%// Shift the dimensions to the left 1 to move the RGB channel values into
%// the third dimension. Note the extra decimal point. This is because it
%// is far shorter to lengthen the code by one byte than to pad the string
%// to give us a length divisible by 3
R = shiftdim(R, 1.);

%// Display the RGB image
image(R);
\$\endgroup\$
  • 1
    \$\begingroup\$ +1 for the ans idea! \$\endgroup\$ – flawr May 18 '16 at 8:34
  • \$\begingroup\$ Doesn't this have to be run twice to work? The first time around, I would expect it to create an image based on the value ans has until the first run is completed, which results in ans becoming the function itself. The second time around, it is using "its own" code (well actually, it is the code of a separate but identical anonymous function). That being said, I don't know MATLAB, so I may be wrong. \$\endgroup\$ – Adám May 19 '16 at 6:47
  • 2
    \$\begingroup\$ @Nᴮᶻ That's the beauty of using evalin to call char(ans) in the base workspace. The evalin is only evaluated at run-time so even though ans isn't defined when you paste it into the command window, when you call ans() to run this anonymous function, ans is defined and the evalin call inside the anonymous function can access it. So you do not have to run it twice. If I could rely on it being run twice, evalin('base', 'char(ans)') would be replaced by simply char(ans) \$\endgroup\$ – Suever May 19 '16 at 10:07
4
\$\begingroup\$

Javascript(ES6) 324 312 309 Bytes

I'm sure this could be golfed a bit:

f=()=>{s="f="+f;l=s.length/3;c=document.createElement('canvas');for(i=0;++i<l/i;l%i?0:w=i,h=l/w);c.s=c.setAttribute;c.s("width",w);c.s("height",h);(i=(t=c.getContext('2d')).createImageData(w,h)).data.map((a,b)=>i.data[b]=b%4<3?s.charCodeAt(b-~~(b/4)):255);t.putImageData(i,0,0);open(c.toDataURL('image/png'))}
  • creates a canvas
  • builds image in it
  • Opens data url for image in new tab

New lines for readability:

f=()=>{
    s="f="+f;l=s.length/3;
    c=document.createElement('canvas');
    for(i=0;++i<l/i;l%i?0:w=i,h=l/w);
    c.s=c.setAttribute;
    c.s("width",w);
    c.s("height",h);
    (i=(t=c.getContext('2d')).createImageData(w,h)).data.map((a,b)=>i.data[b]=b%4<3?s.charCodeAt(b-~~(b/4)):255);
    t.putImageData(i,0,0);
    open(c.toDataURL('image/png'))
}

Output

JavaScript

\$\endgroup\$
  • \$\begingroup\$ As I didn't specified it, you don't need to make it auto run. \$\endgroup\$ – Bálint May 17 '16 at 20:37
  • \$\begingroup\$ Also, just insert a dummy variable instead of using empty paragraphs \$\endgroup\$ – Bálint May 18 '16 at 8:54
  • \$\begingroup\$ Empty paragraphs? Where? \$\endgroup\$ – Shaun H May 18 '16 at 11:18
  • \$\begingroup\$ f=()=>{ Here, just do f=_=>, -1 byte, just don't use it, javascript is loosely typed \$\endgroup\$ – Bálint May 18 '16 at 11:30
  • \$\begingroup\$ Ah parameters, current leaving the parens is cheaper than handling not evenly divisible by 3 \$\endgroup\$ – Shaun H May 18 '16 at 14:09
3
\$\begingroup\$

Javascript ES6 - 216 bytes

f=(  )=>((d=(x=(v=document.createElement`canvas`).getContext`2d`).createImageData(v.width=9,v.height=8)).data.set([..."f="+f].reduce((p,c,i)=>(c=c.charCodeAt(0),[...p,...i%3<2?[c]:[c,255]]))),x.putImageData(d,0,0),v)

Ungolfed:

f=(  )=>(                                           // define function f (extra spaces to account for missing pixel + alpha channel calculation)
 (d=(x=(v=document.createElement`canvas`).          // assign html5 canvas to v
          getContext`2d`).                          // assign graphics context to x
          createImageData(v.width=9,v.height=8)).   // create & assign ImageData to d
                                                    //   set width and height of both d and v
 data.set([..."f="+f].                              // get f's source, convert to array of chars
   reduce((p,c,i)=>(c=c.charCodeAt(0),              // convert char array to int array
                    [...p,...i%3<2?[c]:[c,255]]))), // insert alpha values 255
 x.putImageData(d,0,0),                             // draw source RGBA array to canvas
 v)                                                 // return canvas

Note: f returns a canvas.

Example run (assumes there's a <body> to append to):

document.body.appendChild(f())

Should dump the following image to the page (enlarged):

QuineImage

\$\endgroup\$
  • \$\begingroup\$ The last pixel is completely empty, can you make it, so it is 71 pixels in total? \$\endgroup\$ – Bálint May 18 '16 at 8:57
  • \$\begingroup\$ @Bálint Whoops, didn't see the empty pixel part. Interestingly enough, if I try to make the image 71x1, that increases my byte count to 214 and incidentally, the pixel count to 72, which is 9x8, which in turn brings the byte count back to 213. It also ruins the alpha channel calculation. The current cleanest solution that meets all the reqs is to add 3 redundant chars to the solution... \$\endgroup\$ – Dendrobium May 18 '16 at 16:39
2
\$\begingroup\$

PowerShell v4, 64 bytes

"P6 11 2 255"+[char[]](gc $MyInvocation.MyCommand.Name)|sc a.ppm

It gets the content of its own filename, casts the string as a char array, adds some PPM header and sets the content to a.ppm as output. 64 bytes makes it 11x2 pixels:

PowerShell source encoded as picture

\$\endgroup\$
1
\$\begingroup\$

Node.js, 63 bytes

(F=x=>require('fs').writeFile('P6','P6 7 3 255 (F='+F+')()'))()

Outputs image into a file named P6 which is in the PPM (P6) format.

Here's a PNG rendition (7x3 pixels):

enter image description here

\$\endgroup\$
1
\$\begingroup\$

PHP, 226 bytes

Golfed

<?$b=strlen($w=join(file('p.php')));$z=imagecreatetruecolor(5,15);for($c--;++$c<$b+1|$i%3;$i%3?:$a=!imagesetpixel($z,$x%5,(int)$x++/5,$a))$a+=($c<$b?ord($w[$c]):0)*256**(2-$i++%3);header("Content-Type:image/png");imagepng($z);

Ungolfed version

<?
// Read the file into an array and join it together. Store the length of the resulting string.
$b=strlen($w=join(file('p.php')));

// Create the image. Our file is 226 bytes, 226/3 = 75 = 5 * 15
$z=imagecreatetruecolor(5,15);

// Loop through the script string, converting each character into a pixel.
// Once three characters have been converted, draw the pixel with the converted RGB value and reset the color to 0.
for($c--;++$c<$b+1|$i%3;$i%3?:$a=!imagesetpixel($z,$x%5,(int)$x++/5,$a))$a+=($c<$b?ord($w[$c]):0)*256**(2-$i++%3);

// Tell the program we're sending an image
header("Content-Type:image/png");

// And send it!
imagepng($z);

Enter this script into a file named 'p.php' and run it. You need your own method of running PHP script, because this reads from a local file.

Output image:

color coded

\$\endgroup\$
0
\$\begingroup\$

Java 511 chars

The length of the solution leads to a greater picture which is cool, because these pictures are really nice.

import java.awt.image.*;import java.io.*;import java.nio.file.*;import javax.imageio.*; public class Q{public static void main(String[]a)throws Throwable{int w=19,h=9;byte[]e=Files.readAllBytes(Paths.get("Q.java"));String t=new String(e);while(t.length()%3!=0)t+='\0';BufferedImage I=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);int r,c=r=0;for(int i=0;i<t.length();i++){I.setRGB(c,r,255<<24|t.charAt(i)<< 16|t.charAt(++i)<< 8|t.charAt(++i));if(++c==w){c=0;r++;}}ImageIO.write(I,"png",new File("Q.png"));}}

Note that there is an invisible trailing newline! It reads the source file, which has to be "Q.java" and creates a picture "Q.png" which looks like this:

The image generated by the code

or scaled 100x enter image description here

\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog), 33 bytes

Requires ⎕IO←0 which is default on many systems. Also, AutoFormat should be off to preserve the program exactly as given.

(⊂⎕NPUT⊃)'P',⍕⎕AV⍳'␍ɫ␉⍣',⊃⌽⎕NR'f'  

Hex B9 BA FD 4E 50 55 54 BB F8 0D 50 0D C2 CD FD 41 56 B2 0D 03 0B 01 FF 0D C2 BB C8 FD 4E 52 0D 16 0D
Unicode 28 2282 2395 4E 50 55 54 2283 29 27 50 27 2C 2355 2395 41 56 2373 27 0D 026B 08 2363 27 2C 2283 233D 2395 4E 52 27 66 27

Creates P: P3 11 1 255 185 186 253 78 80 85 84 187 248 13 80 13 194 205 253 65 86 178 13 3 11 1 255 13 194 187 200 253 78 82 13 22 13
Which you save and drop here to see: code image

⎕NR'f'Nested Representation of the program f

⊃⌽ pick the last (lit. first of the reversed) element (line)

'␍ɫ␉⍣', prepend the four characters (filetype, width, height, max)

⎕AV⍳ find corresponding indices in the Atomic Vector (the character set

 format as text

'P', prepend a letter

() apply the following tacit function:

 take the entire argument [and into a]

⎕NPUTNative [file,] Put [it, with a filename consisting of]

 the first character ("P")

\$\endgroup\$
  • \$\begingroup\$ What codepage does this assume? \$\endgroup\$ – Bálint May 17 '16 at 21:19
  • \$\begingroup\$ @Bálint See edit. \$\endgroup\$ – Adám May 17 '16 at 21:23
  • \$\begingroup\$ How come the resulting image is 42 pixels instead of 14? Is this because your "bytes" correspond to multi-byte characters? \$\endgroup\$ – Suever May 18 '16 at 2:06
  • \$\begingroup\$ @Suever Fixed. Thanks. \$\endgroup\$ – Adám May 18 '16 at 5:27
  • \$\begingroup\$ BTW, I think, if the version had a compiler before the challenge, then it is a legal one. \$\endgroup\$ – Bálint May 18 '16 at 14:28
-1
\$\begingroup\$

Python, 81 bytes

q=open(__file__).read()
print'P3\n9 3 256 '+' '.join(map(lambda x:str(ord(x)),q))

Output is in PPM format.

This is what the image looks like:

Image

Scaled up:

Scaled up

\$\endgroup\$
  • \$\begingroup\$ I don't see you reusing q \$\endgroup\$ – Maltysen May 18 '16 at 21:53
  • \$\begingroup\$ If you use the P6 format, you don't need to convert to ordinals. Additionally, for 8-bit RGB, 255 should be used instead of 256. \$\endgroup\$ – Mego May 19 '16 at 2:50
  • \$\begingroup\$ If you only use q once, as it seems you do, get rid of the assignment and substitute it directly -- it'll save you three bytes. \$\endgroup\$ – Fund Monica's Lawsuit May 19 '16 at 3:10
  • \$\begingroup\$ It looks like you print the file content, but OP said The output should be as a separate file. \$\endgroup\$ – Adám May 19 '16 at 6:50
  • \$\begingroup\$ Hello, @QPaysTaxes said print'P3\n9 3 256 '+' '.join(map(lambda x:str(ord(x)),open(__file__).read())). It's -4 bytes, tho! \$\endgroup\$ – Erik the Outgolfer May 19 '16 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.