Compress your code in an image

17

6

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.

Bálint

Posted 2016-05-17T14:36:27.120

Reputation: 1 847

7Waiting for a Piet submission... :P – Rɪᴋᴇʀ – 2016-05-17T14:38:34.593

3What 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) – James – 2016-05-17T15:26:30.507

@DrGreenEggsandHamDJ Added an extra rule – Bálint – 2016-05-17T16:17:19.847

2Still 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? – James – 2016-05-17T16:22:15.083

3Was this on the sandbox? It seems like it could've used some time there. – Morgan Thrapp – 2016-05-17T16:38:52.197

1Isn'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. – Suever – 2016-05-17T17:37:22.430

@Suever added that too – Bálint – 2016-05-17T17:59:19.483

1

Well, the ambiguity is gone, my only thought is that it's a little bit of a chameleon challenge. The challenge is about encoding ASCII into an image, but now we also have worry about finding which set of factors is closest together. You don't have to change it, just something to think about for your next challenge.

– James – 2016-05-17T19:09:10.473

@DrGreenEggsAndHamDJ I know, but as that part is hard-codable, I didn't thought it will be a problem. – Bálint – 2016-05-17T20:36:36.587

ceil(byte count / 3) - ceil or byte length have to be divadable by 3? – Qwertiy – 2016-05-17T22:12:04.957

@Suever I think I stated that – Bálint – 2016-05-18T05:15:44.683

@Qwertiy No, it doesn't – Bálint – 2016-05-18T05:16:45.217

@EᴀsᴛᴇʀʟʏIʀᴋ It's inspired by piet. – Bálint – 2016-05-18T08:58:17.813

The bit about multibyte characters could be better stated as "use the raw bytes of your program's source code in the code's text encoding". Specifying 2 bytes doesn't cover the characters in UTF-8 that span 3 or 4 bytes. – Mego – 2016-05-18T22:16:36.650

Why not allow the image file contents to be printed to stdout? – Mego – 2016-05-19T14:36:15.160

@Mego Because that's not what I originally wanted – Bálint – 2016-05-19T17:26:21.023

That would be the same as "print out the ascii values of your code" – Bálint – 2016-05-19T17:26:53.760

@Bálint And saving it to a file is different somehow? – Mego – 2016-05-19T23:26:41.197

@Mego Then you actually need to construct an image. – Bálint – 2016-05-20T05:33:37.430

@Bálint Submissions can still "construct an image" without needing to save it to a file or display it - outputting the image file contents to STDOUT is accepted by default. You override this default for no good reason. Additionally, the existence of the PPM (P6) image file format completely trivializes this challenge - a solution must simply prepend the image header P6 W H 255 to its own source code. – Mego – 2016-05-20T05:38:27.840

@Bálint Why is the Actually answer still accepted when it fails to fulfil one of your requirements? The output should be as a separate file, or in a separate window. – Adám – 2017-05-03T00:26:50.490

Answers

1

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)

Mego

Posted 2016-05-17T14:36:27.120

Reputation: 32 998

2OP: The output should be as a separate file. Doesn't this just output the file contents to STDOUT? – Adám – 2016-05-19T06:49:16.620

8

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);

Suever

Posted 2016-05-17T14:36:27.120

Reputation: 10 257

1+1 for the ans idea! – flawr – 2016-05-18T08:34:27.877

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. – Adám – 2016-05-19T06:47:00.197

2@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) – Suever – 2016-05-19T10:07:41.573

4

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

Shaun H

Posted 2016-05-17T14:36:27.120

Reputation: 732

As I didn't specified it, you don't need to make it auto run. – Bálint – 2016-05-17T20:37:39.447

Also, just insert a dummy variable instead of using empty paragraphs – Bálint – 2016-05-18T08:54:00.673

Empty paragraphs? Where? – Shaun H – 2016-05-18T11:18:11.407

f=()=>{ Here, just do f=_=>, -1 byte, just don't use it, javascript is loosely typed – Bálint – 2016-05-18T11:30:12.947

Ah parameters, current leaving the parens is cheaper than handling not evenly divisible by 3 – Shaun H – 2016-05-18T14:09:27.917

I think, you don't need to specify the width and height, if you create the image data the right size, then it resizes it. – Bálint – 2016-05-18T14:20:05.077

Creates a large(300x150) empty canvas for me – Shaun H – 2016-05-18T14:40:51.337

3

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

Dendrobium

Posted 2016-05-17T14:36:27.120

Reputation: 2 412

The last pixel is completely empty, can you make it, so it is 71 pixels in total? – Bálint – 2016-05-18T08:57:26.267

@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... – Dendrobium – 2016-05-18T16:39:14.707

2

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

TessellatingHeckler

Posted 2016-05-17T14:36:27.120

Reputation: 2 412

1

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

Mwr247

Posted 2016-05-17T14:36:27.120

Reputation: 3 494

1

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

Xanderhall

Posted 2016-05-17T14:36:27.120

Reputation: 1 236

0

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")

Adám

Posted 2016-05-17T14:36:27.120

Reputation: 37 779

What codepage does this assume? – Bálint – 2016-05-17T21:19:00.990

@Bálint See edit. – Adám – 2016-05-17T21:23:19.830

How come the resulting image is 42 pixels instead of 14? Is this because your "bytes" correspond to multi-byte characters? – Suever – 2016-05-18T02:06:31.453

@Suever Fixed. Thanks. – Adám – 2016-05-18T05:27:19.280

BTW, I think, if the version had a compiler before the challenge, then it is a legal one. – Bálint – 2016-05-18T14:28:07.153

@Bálint I looked up on Meta. You're right. Editing... – Adám – 2016-05-18T19:37:02.393

0

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

Frozn

Posted 2016-05-17T14:36:27.120

Reputation: 381

-1

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

Loovjo

Posted 2016-05-17T14:36:27.120

Reputation: 7 357

I don't see you reusing q – Maltysen – 2016-05-18T21:53:22.133

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. – Mego – 2016-05-19T02:50:32.863

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. – Fund Monica's Lawsuit – 2016-05-19T03:10:23.737

It looks like you print the file content, but OP said The output should be as a separate file. – Adám – 2016-05-19T06:50:56.230

Hello, @QPaysTaxes said print'P3\n9 3 256 '+' '.join(map(lambda x:str(ord(x)),open(__file__).read())). It's -4 bytes, tho! – Erik the Outgolfer – 2016-05-19T14:42:23.720

@Adám or in a window, but yes, you are correct. – Bálint – 2016-05-25T05:53:29.610