Output 2015 as QR code

15

1

Mission is simple. Just output number 2015 as QR code and write it to file named newyear.png in PNG format. Code must be valid any day, so maybe you shall not use current year.

QR code as text looks like this:

# # # # # # #   # # # #     # # # # # # #
#           #           #   #           #
#   # # #   #   # #     #   #   # # #   #
#   # # #   #       #   #   #   # # #   #
#   # # #   #       #   #   #   # # #   #
#           #               #           #
# # # # # # #   #   #   #   # # # # # # #
                #   # #
#   #     # #     # #     # #       #   #
  # # #   #   #   #   # #   #     #   # #
#   # #   # # #   # # # # # #   #       #
# # #         # #         # # # #
# # # # #   #   #     #     #   #     #
                      # # # #
# # # # # # #       #   # #   # #   #   #
#           #   #         # # # #
#   # # #   #         #     #   #     #
#   # # #   #     #     # # # # #
#   # # #   #   #   #   # #   # #   #   #
#           #     # #       # # #   # # #
# # # # # # #   #           #   #   #   #

The result written in newyear.png must contain that QR code with white 5 pixel borders and one pixel sized dots. It must not contain anything else than QR code.

Hannes Karppila

Posted 2014-12-29T11:05:38.213

Reputation: 3 090

1can it be hardcoded, or must you generate the qr code? – undergroundmonorail – 2014-12-29T11:14:07.457

7Much more answers will come if this is ascii art output based and not image output. – Optimizer – 2014-12-29T11:37:46.330

6

Does the code have to be exactly correct with no errors, or is it enough that it scans correctly? (QR codes have a lot of deliberate redundancy and error correction, so you can flip a lot of pixels and they'll still work.) Also, does it have to be PNG, or can we use other image formats (I'm thinking particularly about PBM here)?

– Ilmari Karonen – 2014-12-30T01:49:33.837

Answers

13

Raw file, 184 bytes = 173-byte file + 11-byte filename

I hope this does not break any standard loopholes. But the output "has a high and the shortest way to produce it would (most likely) be to just print it literally...".

newyear.png

Base 64 of the file:

iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfAQAAAAA31SuUAAAAdElEQVR4XnXOMQ5BQRRA0euVRFgGCq1ubIyJpSh11I
qJWIjo+fnt/JnJe55WornlycXMVAB+Qp49A7U/J8rqlIQReG5Quz6Rx8eA6VaF5R7a5arooXg2LaKvd8KGRyBPJLoy
D640pxZ3pay/creL5KnEvwcfvE46ggJMibIAAAAASUVORK5CYII=

Instead of golfing a program I golfed the resulting PNG image. QR code is a very flexible format, there are many parameters that can be fiddled: the encoding of the input, the error correction level, and the masking image. These will all generate different symbols and thus compressed to files of different sizes.

So I have written a program to generate all these combinations (resulting 6720 files), and then use PNGOUT to pick the one which compressed to the smallest file. It turns out to be a file that:

  • First write "20" in alphanumeric mode
  • Then write "1" in numeric mode
  • Then write "5" in numeric mode
  • Use the "H" (High) error correction level
  • Use the "110" data masking

This is called test-3-1-H-Diamonds.bmp if you used the program below. This image is 175-byte long after running PNGOUT. With "high" error correction level in "version 1" QR code, we can modify up to 8 pixels in the data part without ruining the data. With a bit of manual trial-and-error I can reduce it further to 173 bytes presented above. It can probably be smaller but exhausting all combinations requires 208C8 ~ 7.5 × 1013 checks which I'm not going to do ;)


The Rust (0.13.0-nightly (5ba610265)) program that generates all combinations:

/* 

Also put these into your Cargo.toml: 

[dependencies]
qrcode = "0.0.3"
bmp = "0.0.3"

*/

extern crate qrcode;
extern crate bmp;

use qrcode::bits::Bits;
use qrcode::optimize::Segment;
use qrcode::types::{Version, EcLevel, Mode};
use qrcode::ec::construct_codewords;
use qrcode::canvas::{Canvas, MaskPattern, Module};

use bmp::{Image, Pixel};

use std::num::Int;

const BLACK: Pixel = Pixel { r: 0, g: 0, b: 0};
const WHITE: Pixel = Pixel { r: 255, g: 255, b: 255 };

static SEGMENT_SEPARATIONS: [&'static [(uint, uint)]; 8] = [
    &[(0, 1), (1, 2), (2, 3), (3, 4)],
    &[(0, 1), (1, 2), (2, 4)],
    &[(0, 1), (1, 3), (3, 4)],
    &[(0, 2), (2, 3), (3, 4)],
    &[(0, 1), (1, 4)],
    &[(0, 2), (2, 4)],
    &[(0, 3), (3, 4)],
    &[(0, 4)],
];

const ALL_EC_LEVELS: &'static [EcLevel] = &[EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H];
const ALL_MODES: &'static [Mode] = &[Mode::Numeric, Mode::Alphanumeric, Mode::Byte];
const ALL_MASK_PATTERNS: &'static [MaskPattern] = &[
    MaskPattern::Checkerboard,
    MaskPattern::HorizontalLines,
    MaskPattern::VerticalLines,
    MaskPattern::DiagonalLines,
    MaskPattern::LargeCheckerboard,
    MaskPattern::Fields,
    MaskPattern::Diamonds,
    MaskPattern::Meadow,
];

fn run(ec_level: EcLevel, mask_pattern: MaskPattern, segments: &[Segment], filename: &str) {
    let version = Version::Normal(1);
    let mut bits = Bits::new(version);
    if bits.push_segments(b"2015", segments.iter().map(|s| *s)).is_err() {
        return;
    }
    if bits.push_terminator(ec_level).is_err() {
        return;
    }
    let data = bits.into_bytes();
    let (encoded_data, ec_data) = construct_codewords(&*data, version, ec_level).unwrap();
    let mut canvas = Canvas::new(version, ec_level);
    canvas.draw_all_functional_patterns();
    canvas.draw_data(&*encoded_data, &*ec_data);
    canvas.apply_mask(mask_pattern);
    let canvas = canvas;

    let width = version.width();
    let real_image_size = (width + 10) as uint;
    let mut image = Image::new(real_image_size, real_image_size);
    for i in range(0, real_image_size) {
        for j in range(0, real_image_size) {
            image.set_pixel(i, j, WHITE);
        }
    }
    for i in range(0, width) {
        for j in range(0, width) {
            if canvas.get(i, j) == Module::Dark {
                image.set_pixel((i + 5) as uint, real_image_size - (j + 6) as uint, BLACK);
            }
        }
    }
    image.save(filename);
}

fn main() {
    for (z, separations) in SEGMENT_SEPARATIONS.iter().enumerate() {
        let mut segments = separations.iter().map(|&(b, e)| Segment {
            mode: Mode::Numeric, begin: b, end: e
        }).collect::<Vec<_>>();

        let variations_count = ALL_MODES.len().pow(segments.len());
        for i in range(0, variations_count) {
            let mut var = i;
            for r in segments.iter_mut() {
                r.mode = ALL_MODES[var % ALL_MODES.len()];
                var /= ALL_MODES.len();
            }
            for ec_level in ALL_EC_LEVELS.iter() {
                for mask_pattern in ALL_MASK_PATTERNS.iter() {
                    let filename = format!("results/test-{}-{}-{}-{}.bmp", z, i, *ec_level, *mask_pattern);
                    run(*ec_level, *mask_pattern, &*segments, &*filename);
                }
            }
        }
        println!("processed {}/{}", z, 8u);
    }
}

kennytm

Posted 2014-12-29T11:05:38.213

Reputation: 6 847

1

The main problem I see here, is that your submission itself is not written in a programming language.

– Martin Ender – 2014-12-30T00:12:22.070

4@MartinBüttner That's a subjective opinion of a selected few people. That being said, the way the file was obtained was programmed so I'd say this is a completely valid submission. Also, this is a frigging awesome approach. – Nit – 2014-12-30T01:21:46.090

1@Nit It's a meta post without downvotes, which is basically how community consensus works on SE (at least on PPCG). If you disagree, you could downvote that answer or provide an alternative. That being said, I'll probably make a separate meta post, specifically about kolmogorov complexity challenges, as this is coming up a lot. – Martin Ender – 2014-12-30T09:58:54.730

@Nit Done. Feel free to come discuss this on meta.

– Martin Ender – 2014-12-30T10:33:07.463

Converting from gif seemed shorter. – jimmy23013 – 2014-12-31T10:09:05.493

The question doesn't ask for any QR code which expands to the correct string: it asks for a specific one. – Peter Taylor – 2015-01-01T14:13:23.063

@PeterTaylor: It's not really clear from the question if that's the case or not (the ASCII art could be just one example of a valid output); hence my earlier comment above. Anyway, +1 for effort and cleverness, whether this falls strictly within the rules or not. – Ilmari Karonen – 2015-01-05T20:04:53.253

5

Mathematica, 217 177 176 166 bytes

Here is a start:

"newyear.png"~Export~ImagePad[Image[IntegerDigits[36^^fl6ibg25c8z00uef53p4657dgd6hjzg41e5joead1qgz0l2xchqgso5r1a51v5no4zkw9v22okk‌​lg0cymmy2,2,441]~Partition~21],5,1]

Less golf:

"newyear.png"~Export~ImagePad[
 Image[
  IntegerDigits[
    36^^fl6ibg25c8z00uef53p4657dgd6hjzg41e5joead1qgz0l2xchqgso5r1a51v5no4zkw9v22okk‌​lg0cymmy2,
    2,
    441
  ]~Partition~21
 ],
 5,
 1
]

The QR code is encoded in a base 36 number. Of course, I could encode it in extended ASCII (base 256), but that would only shorten the string by 30 bytes, and I'm not sure I can do the conversion at the cost of much less than that.

Of course, this is Mathematica, so there's also the 63-byte

"newyear.png"~Export~ImagePad[BarcodeImage["2015","QR",21],5,1]

but I guess that's a standard loophole. ;) (This produces a different QR code than the one in the challenge, so I guess the QR code isn't unique?)

Martin Ender

Posted 2014-12-29T11:05:38.213

Reputation: 184 808

1Yes there are multiple ways to encode the same string in QR code, e.g. using different levels of error checking, encoding scheme, masking image, etc. Not considering compression OP's code is one of the smallest ("version 1") nevertheless. – kennytm – 2014-12-29T13:11:58.427

FromDigits? You could use 36^^fl6ibg25c8z00uef53p4657dgd6hjzg41e5joead1qgz0l2xchqgso5r1a51v5no4zkw9v22okklg0cymmy2 instead. – kennytm – 2014-12-30T00:06:29.997

@KennyTM oh wow, neat trick. Thank you :) I think with that, base 256 is really not worth it (I'd need both ToCharacterCode and FromDigits then.) – Martin Ender – 2014-12-30T00:09:35.313

3

Matlab 545 Bytes

newyear

Hardcoded in painstaking manual work and without any fancy builtin string compression/conversation. I know it still is not as good as the other answers but I am still happy=)

b=[[61:67,69,71:73,75:81,92,98]+100,
    1,3:4,6,12,23,25:27,29,31:35,37,39:41,43,54,56:58,60,63:64,66,68,70:72,74,85,87:89,91,97,99]+200,
    [1:3,5,16,22,24:26,30,36,47:53,55,57,59,61:67,87:89]+300,
    [9,11,15:16,20:21,24,27,29,40,42,48:50,57,59,71,74:75,77:79,81,85,89:90]+400,
    [2,9,11:12,14:15,18,34:37,39,42:43,46:47,50:51,72,74:75,77:79,81:82,95:99]+500,
    [0:1,3:8,10:12,14:15,26,32,37,40:41,43:45,57,59:61,63,67:69,71:77,88,90:92,94,97]+600,
    [19,21:23,25,27,33,37:39,50,56,59,62,66,69,81:87,89:91,95,99:101]+700];
z=zeros(31);z(b)= 1;imwrite(~z,'newyear.png')

More unreadable (the actual 545 version):

z=zeros(31);
z([
    [61:67, 69, 71:73, 75:81, 92, 98] + 100,
    [1, 3:4, 6, 12, 23, 25:27, 29, 31:35, 37, 39:41, 43, 54, 56:58, 60, 63:64, 66, 68, 70:72, 74, 85, 87:89, 91, 97, 99] + 200,
    [1:3, 5, 16, 22, 24:26, 30, 36, 47:53, 55, 57, 59, 61:67, 87:89] + 300,
    [9, 11, 15:16, 20:21, 24, 27, 29, 40, 42, 48:50, 57, 59, 71, 74:75, 77:79, 81, 85, 89:90] + 400,
    [2, 9, 11:12, 14:15, 18, 34:37, 39, 42:43, 46:47, 50:51, 72, 74:75, 77:79, 81:82, 95:99] + 500,
    [0:1, 3:8, 10:12, 14:15, 26, 32, 37, 40:41, 43:45, 57, 59:61, 63, 67:69, 71:77, 88, 90:92, 94, 97] + 600,
    [19, 21:23, 25,27, 33, 37:39, 50, 56, 59, 62, 66, 69, 81:87, 89:91, 95, 99:101] + 700
])= 1;
imwrite(~z,'newyear.png')

We create a 31 x 31 zero matrix, but access it as vector to set all cells with the indices of b to 1. The tricks I used were the notation of consecutive integers (like [1,2,3,4] = 1:4) and removing one the 100-digit by adding a scalar to every value of the vector.

Let's see if anyone can beat that=)

flawr

Posted 2014-12-29T11:05:38.213

Reputation: 40 560

so i didnt read the word unreadable correctly... definitely read readable. saw that right after suggesting it and was hoping whoever read my edit rejected it, but they missed it too apparently. sorry about the bad edit... – pseudonym117 – 2014-12-29T18:42:21.583

Does not relly matter IMHO, just wanted to include the first version because it is easier to refer to in the explaination. – flawr – 2014-12-29T19:35:01.723

2

Bash, 206 252 257 Bytes

Using the convert command bundled in imagemagick saves 46 more bytes.

base64 -d<<<UDQKMzAgMzAKAAAAAAAAAAAAAAAAAAAAAAAAAAAH9L+ABBkggAXULoAF2S6ABdOugAQeoIAH+r+AB9zVAABIlwABHU6AAsIaAAFXS4AAD+QAB/ywAAQT5QAF3pIABd6SAAXdTgAEHBsAB/1OAAAAAAAAAAAAAAAAAAAAAAAAAAAA|convert - newyear.png

Converts the base64-encoded pbm image to a png image with imagemagick's convert.

You may need to adjust the decode (-d) parameter to your specific base64 binary. Tested on my Ubuntu 14.04 LTS.

Saved 5 bytes by using <<</here-string.

base64 -d>newyear.png<<<iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeAQMAAAAB/jzhAAAABlBMVEX///8AAABVwtN+AAAAX0lEQVQI12PACdi/7G9gYJFUaGBgvaIHJG6CiMvrgGJyCxoY2H/tBxJ3rgIVekxnYGCU9WtgYDokBWSFezcwMPA/ARrwZwMDA4vwUwYG1nuTYMRdP6CYjDRQ9q8fbrsBLRkaYOOP83wAAAAASUVORK5CYII=

Old version (257 bytes):
echo iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeAQMAAAAB/jzhAAAABlBMVEX///8AAABVwtN+AAAAX0lEQVQI12PACdi/7G9gYJFUaGBgvaIHJG6CiMvrgGJyCxoY2H/tBxJ3rgIVekxnYGCU9WtgYDokBWSFezcwMPA/ARrwZwMDA4vwUwYG1nuTYMRdP6CYjDRQ9q8fbrsBLRkaYOOP83wAAAAASUVORK5CYII=|base64 -d > newyear.png

Just a simple shell command chain that writes the base64 encoded png file into stdin of base64 that decodes it because of the -d flag and writes its stdout to newyear.png.

GiantTree

Posted 2014-12-29T11:05:38.213

Reputation: 885

can probably save characters with something like base64 -d>newyear.png<<<[the long string] but i'm not at a linux machine rn and i don't know which whitespace is mandatory – undergroundmonorail – 2014-12-29T16:32:09.453

Confirmed to work with base64 -d>newyear.png<<<[base64 string] on Ubuntu 14.04. – PurkkaKoodari – 2014-12-29T16:54:10.843

If you are going to use the suggested code, just edit the answer heading to something specific like Bash, Ksh or Zsh. Shell in general (like POSIX compatible Sh, Ash or Dash) does not support the here-string syntax.

– manatwork – 2014-12-29T17:00:56.050

If we can use netpbm routines, we can feed the compressed bitmap and lose 40 bytes: echo UDQKMzEgMzEKAAAAAAAAAAAAAAAAAAAAAAAAAAAH95/ABBBQQAXWV0AF0VdABdFXQAQQEEAH9V/ AAAWAAAUzMUADqtLABbv0QAcMPAAH1JSAAADwAAfxbUAEFDwABdCUgAXSfAAF1W1ABBMdwAf0FUAAAAA AAAAAAAAAAAAAAAAAAAAAAA==|base64 -d|pnmtopng>newyear.png – swstephe – 2014-12-29T17:14:54.927

@manatwork Just edited, should work on Bash as I tested it on my Android phone. – GiantTree – 2014-12-29T17:27:56.917

Saved 5 bytes. Thanks @undergroundmonorail for the tip with here-strings. – GiantTree – 2014-12-29T18:22:48.167

On OS X it needs to be base64 -D instead of base64 -d (-d means debug on OS X...) – kennytm – 2014-12-29T18:50:03.247

@KennyTM It works on my Ubuntu machine, so I assume it's a correct answer. – GiantTree – 2014-12-29T18:54:21.940

Uses imagemagick now for some "image magic". Converts a base64-encoded pbm image to a png image. – GiantTree – 2014-12-29T19:00:42.063

@GiantTree: Yes it's correct. – kennytm – 2014-12-29T19:11:57.653

1

Python 2 + PIL, 216 215

Basically a port of the Mathematica solution.

from PIL import*
b=Image.new("1",[21]*2)
b.putdata(map(int,'0'*7+bin(int('FL6IBG25C8Z00UEF53P4657DGD6HJZG41E5JOEAD1QGZ0L2XCHQGSO5R1A51V5NO4ZKW9V22OKKLG0CYMMY2',36))[2:]))
ImageOps.expand(b,5,255).save("newyear.png")

PurkkaKoodari

Posted 2014-12-29T11:05:38.213

Reputation: 16 699

0

Common Shell tools + Imagemagick, 215

(echo "P1
21 21"
base64 -d<<<H95/ggoN1lduirt0VdggIP9V/ALAFMzFdVpdu/R4YeH1JSAB4H8W1goeF0JSuk+F1W1gmO/9BVA=|xxd -c99 -p|tr a-f A-F|dc -e2o16i?p|tr -d '\n\\'|fold -21)|convert -border 5 -bordercolor white - newyear.png

A bit convoluted, but shorter than the other shell answer.

  • Base64 converts from base64 to base 256 (extended ASCII)
  • xxd converts to hex
  • tr makes hex uppercase, suitable for dc
  • dc reads hex and prints binary string of 1s and 0s
  • tr removes \ and whitespace
  • fold makes lines 21 chars (21 pixels) long
  • This output, along with P1\n21 21 is the PBM P1 format
  • convert (Imagemagick) converts this to .png with a 5 pixel border:

enter image description here

Digital Trauma

Posted 2014-12-29T11:05:38.213

Reputation: 64 644