I am building algorithm to automatically solve / rebuild QR code from number of tiles of equal size.
My approach:
- Get one of 3 side squares : Position squares
- Get the width of outer black border somehow using ImageMagic
Which for given example is 14px x 14px (UPDATE: it might be 13px by 13px)
- Set it as a constant: BLOCK_SIZE
- Start cycle matching VALID tiles and already compiled block of QR code
VALID is : unmatched AND not any of 3 corner tiles (big black squares)
4.1. Render all possible combinations of already compiled qr block AND 1 random valid tile from until the match found
4.2 If match found (tile can be placed by one of sides of already compiled/combined block of QR code) then record match
4.3 Match conditions:
There are no BLACK areas which have width and height conform to this equation:
AREA_HEIGHT % BLOCK_SIZE == 0 && AREA_WIDTH % BLOCK_SIZE == 0
Now there are some implementation complications arise:
- How to implement algorithm which matches a tile to tile (OR already compiled/combined block of QR code)?
I think ImageMagic can solve it.
The goal is to get original QR code.
Example QR tiles in ZIP
UPDATE
As I see the solution narrows down to make ImageMagick scan and find if two tiles can be put together without breaking rules of QR code. Algorithm should try to put 2 tiles side by side and scan border areas. The trick is to measure width and height of black lines/blocks of joined tiles. How to do it?
UPDATE2
Comparison if tiles match using 2 columns of width 1px is not enough in some cases. For example, both algorithms will join this 2 tiles into:
VALID
and
INVALID
As you seen in INVALID, there is part of 2nd tile (the one on the right) was removed as denoited by red arrows, but since comparison done by 1px - algorithm doesn't care abuot this case. Hance invalid QR.
UPDATE3
http://dropcanvas.com/6bl6v
Archive containing:
invalid join.png
valid join.png
src1.png
src2-invalid.png
src2-valid.png
invalid.png
If your algorith will join src1.png
and src2-invalid.png
it fails. It's about if joined tiles will produce valid QR in the end. I hope you got my point.
UPDATE4
I will accept an answer after I test and get correct solution. It might take some time....
UPDATE 5 : TESTING
Everything seems correct with Mark's solution.
I had a try at this as follows.
Go through all PNGs and extract their North, East, South and West edges. If any PNG has two white edges, tell user it is a corner-piece. If any PNG has one white edge, tell user it is an edge-piece.
Go through all edge pieces. Convert each one into a PBM format file and strip the headers and new lines so that it will just be an 80 digit long string, each digit a zero or a one for black or white. Calculate checksum of the string and then reverse the string to account for the image being flipped or rotated and then recalculate the checksum. Print out the checksums and pipe into sort
so that matching edges come out together.
Here is the code:
#!/bin/bash
# Remove any edges generated in previous runs of this script
rm *_[NESW]*png 2> /dev/null
rm *_[NESW]*txt 2> /dev/null
DEBUG=1
# Process all PNGs
for f in *.png; do
echo "Processing $f ..."
# Get basename of image
base=$(basename -s .png "$f")
# Get width and height - not actually used at the moment
read w h <<< $(identify -format "%w %h" "$f")
[ $DEBUG -gt 0 ] && echo " width:$w"
[ $DEBUG -gt 0 ] && echo " height:$h"
# Extract North edge
convert "$f" +repage -crop x1+0+0 +repage "${base}_N.png"
[ $DEBUG -gt 0 ] && echo " North edge extracted"
# Extract East edge
convert "$f" +repage -gravity east -crop 1x+0+0 -rotate 90 +repage "${base}_E.png"
[ $DEBUG -gt 0 ] && echo " East edge extracted"
# Extract South edge
convert "$f" +repage -gravity south -crop x1+0+0 +repage "${base}_S.png"
[ $DEBUG -gt 0 ] && echo " South edge extracted"
# Extract West edge
convert "$f" +repage -gravity west -crop 1x+0+0 -rotate 90 +repage "${base}_W.png"
[ $DEBUG -gt 0 ] && echo " West edge extracted"
# Test if corner or edge piece
n=0
for edge in N E S W; do
name="${base}_${edge}.png"
min=$(identify -format "%[min]" "$name")
if [ $min -gt 0 ]; then
((n++))
e=$name
fi
done
[ $n -eq 1 ] && echo " $e is edge-piece"
[ $n -eq 2 ] && echo " $name is corner-piece"
done
EDITED FROM HERE ---
# Now convert all edges to text, forwards and backwards to allow rotation
for f in *_[NESW].png; do
base=$(basename -s png "$f")
# Convert to PBM format, remove 2 header lines and make into one line string
str=$(convert "$f" -compress none pbm: | sed "1,2d" | tr -d "\n ")
echo "$str:$f"
str=$(rev <<< $str)
echo "$str:$f (flipped)"
done | sort
Partial Output (to save space)
Processing 4555-18116-29.png ...
width:80
height:80
North edge extracted
East edge extracted
South edge extracted
West edge extracted
4555-18116-29_S.png is edge-piece
Processing 5004-10810-17642.png ...
width:80
height:80
North edge extracted
East edge extracted
South edge extracted
West edge extracted
5004-10810-17642_W.png is corner-piece
Processing 5167-27533-24066.png ...
width:80
height:80
North edge extracted
East edge extracted
South edge extracted
West edge extracted
Processing 5774-30645-16062.png ...
width:80
height:80
North edge extracted
East edge extracted
South edge extracted
West edge extracted
0a7bb6f610c0f1a6da4794ea7ae00f00:10297-13918-3702_W.png (flipped)
0a7bb6f610c0f1a6da4794ea7ae00f00:11976-7751-26756_E.png (flipped) <-- this image is identical to the one above as the md5 checksum on the left is the same
0ce419e072c7ea5d14e3525d4afe150e:11976-7751-26756_W.png (flipped)
0ce419e072c7ea5d14e3525d4afe150e:13858-18007-13070_E.png (flipped) <-- this image is identical to the one above as the md5 checksum on the left is the same
0ce419e072c7ea5d14e3525d4afe150e:20056-20936-29071_S.png
0ce419e072c7ea5d14e3525d4afe150e:24658-20374-23042_E.png (flipped)
0ce419e072c7ea5d14e3525d4afe150e:24658-20374-23042_S.png
0ce419e072c7ea5d14e3525d4afe150e:27206-10104-18226_N.png
0ce419e072c7ea5d14e3525d4afe150e:30261-16558-25650_N.png
Notes
Note that this assumes you have not tiled the images EXACTLY between the individual "fields" of the QR codes as identified by @YvesDaoust.
Also, some parts of the code are redundant, as I was developing the algorithm at the same time as the code - I think the -rotates
and +repages
are unnecessary and things could be optimised more but there was no indicated need for speed in the question. The North, East, South and West edges could be extracted in a single IM command too. The width and height that I obtained are unused so could be removed from the code.
Also, the md5 checksum is not really necessary, sort
will place 0001110001010110
next to another string the same anyway without needing to checksum them.
Per request, I am uploading the complete solution. I removed the md5 checksum stuff as it was unnecessary. You will need to scroll right to see the filenames below:
00000000000000000000000000000000000000000000000000000000000000000000000000000000:10297-13918-3702_N.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:10297-13918-3702_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:11976-7751-26756_N.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:11976-7751-26756_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:13858-18007-13070_N.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:13858-18007-13070_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:16369-21469-8252_E.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:16369-21469-8252_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:18056-16294-30425_S.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:18056-16294-30425_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:20021-11440-20836_S.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:20021-11440-20836_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:20056-20936-29071_W.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:20056-20936-29071_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:21875-14159-1067_E.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:21875-14159-1067_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:22806-3380-17484_W.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:22806-3380-17484_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24426-18830-5627_E.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24426-18830-5627_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24658-20374-23042_N.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24658-20374-23042_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24658-20374-23042_W.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:24658-20374-23042_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:27206-10104-18226_S.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:27206-10104-18226_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:27206-10104-18226_W.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:27206-10104-18226_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:30261-16558-25650_W.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:30261-16558-25650_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:31250-3578-9750_E.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:31250-3578-9750_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:31250-3578-9750_N.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:31250-3578-9750_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:4555-18116-29_S.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:4555-18116-29_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:5004-10810-17642_E.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:5004-10810-17642_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000000000000000000:5004-10810-17642_S.png
00000000000000000000000000000000000000000000000000000000000000000000000000000000:5004-10810-17642_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000111111111111100:21875-14159-1067_S.png (flipped)
00000000000000000000000000000000000000000000000000000000000000000111111111111100:5004-10810-17642_N.png (flipped)
00000000000000000000000000000000000000000000000000000000000001111111111111111111:28824-13023-24184_W.png (flipped)
00000000000000000000000000000000000000000000000000000000000001111111111111111111:5774-30645-16062_E.png (flipped)
00000000000000000000000000000000000000000000000000000000000011111111111111111111:13789-10513-4721_E.png
00000000000000000000000000000000000000000000000000000000000011111111111111111111:32078-14314-1511_W.png
00000000000000000000000000000000000000000000000000000001111111111111000000000000:11976-7751-26756_W.png
00000000000000000000000000000000000000000000000000000001111111111111000000000000:13858-18007-13070_E.png
00000000000000000000000000000000000000000000000000000001111111111111000000000000:20056-20936-29071_S.png (flipped)
00000000000000000000000000000000000000000000000000000001111111111111000000000000:24658-20374-23042_E.png
00000000000000000000000000000000000000000000000000000001111111111111000000000000:24658-20374-23042_S.png (flipped)
00000000000000000000000000000000000000000000000000000001111111111111000000000000:27206-10104-18226_N.png (flipped)
00000000000000000000000000000000000000000000000000000001111111111111000000000000:30261-16558-25650_N.png (flipped)
00000000000000000000000000000000000000000000000000000001111111111111000000000000:31250-3578-9750_W.png
00000000000000000000000000000000000000000000000000000011111111111110000000000000:16369-21469-8252_N.png
00000000000000000000000000000000000000000000000000000011111111111110000000000000:18056-16294-30425_W.png (flipped)
00000000000000000000000000000000000000000000000000000011111111111110000000000000:27206-10104-18226_E.png (flipped)
00000000000000000000000000000000000000000000000000000011111111111110000000000000:31250-3578-9750_S.png
00000000000000000000000000000000000000000000001111111111111111111111111111111111:10297-13918-3702_S.png
00000000000000000000000000000000000000000000001111111111111111111111111111111111:28824-13023-24184_N.png
00000000000000000000000000000000000001111111111111111111111111000000000000000000:20021-11440-20836_N.png (flipped)
00000000000000000000000000000000000001111111111111111111111111000000000000000000:26507-21853-11958_S.png (flipped)
00000000000000000000000000000000000001111111111111111111111111111111111111100000:15816-4564-31665_W.png
00000000000000000000000000000000000001111111111111111111111111111111111111100000:17636-24599-1877_E.png
00000000000000000000000000000000000001111111111111111111111111111111111111111111:21875-14159-1067_W.png
00000000000000000000000000000000000001111111111111111111111111111111111111111111:26507-21853-11958_E.png
00000000000000000000000000000000000011111111111111111111111110000000000000000000:13789-10513-4721_S.png
00000000000000000000000000000000000011111111111111111111111110000000000000000000:17636-24599-1877_N.png
00000000000000000000000000000001111111111111000000000000000000000000001111111111:22161-18187-20222_W.png
00000000000000000000000000000001111111111111000000000000000000000000001111111111:28824-13023-24184_E.png
00000000000000000000000000000011111111111111111111111111111111111111100000000000:15816-4564-31665_E.png (flipped)
00000000000000000000000000000011111111111111111111111111111111111111100000000000:26507-21853-11958_W.png (flipped)
00000000000000000000000000000111111111111111111111111111111111111111000000000000:20056-20936-29071_N.png (flipped)
00000000000000000000000000000111111111111111111111111111111111111111000000000000:22806-3380-17484_S.png (flipped)
00000000000000000000000000001111111111111111111111111111111111111110000000000000:18056-16294-30425_E.png (flipped)
00000000000000000000000000001111111111111111111111111111111111111110000000000000:4555-18116-29_W.png (flipped)
00000000000000000000000000111111111111100000000000001111111111111000000000000011:16369-21469-8252_S.png (flipped)
00000000000000000000000000111111111111100000000000001111111111111000000000000011:24426-18830-5627_N.png (flipped)
00000000000000000000000001111111111111111111111111111111111111110000000000000000:10297-13918-3702_W.png (flipped)
00000000000000000000000001111111111111111111111111111111111111110000000000000000:11976-7751-26756_E.png (flipped)
00000000000000000000000111111111111100000000000001111111111111111111111111111111:13789-10513-4721_N.png
00000000000000000000000111111111111100000000000001111111111111111111111111111111:5774-30645-16062_S.png
00000000000000000000111111111111100000000000000000000000000111111111111100000000:15816-4564-31665_N.png
00000000000000000000111111111111100000000000000000000000000111111111111100000000:32078-14314-1511_S.png
00000000000000000000111111111111100000000000001111111111111111111111111100000000:13789-10513-4721_W.png (flipped)
00000000000000000000111111111111100000000000001111111111111111111111111100000000:22806-3380-17484_E.png (flipped)
00000000000000000001111111111111111111111111000000000000000000000000000000000000:13789-10513-4721_S.png (flipped)
00000000000000000001111111111111111111111111000000000000000000000000000000000000:17636-24599-1877_N.png (flipped)
00000000000000000011111111111100000000000000000000000000111111111111111111111111:22161-18187-20222_S.png
00000000000000000011111111111100000000000000000000000000111111111111111111111111:5167-27533-24066_N.png
00000000000000000011111111111111111111111110000000000000000000000000000000000000:20021-11440-20836_N.png
00000000000000000011111111111111111111111110000000000000000000000000000000000000:26507-21853-11958_S.png
00000000000000001111111111111111111111111111111111111110000000000000000000000000:10297-13918-3702_W.png
00000000000000001111111111111111111111111111111111111110000000000000000000000000:11976-7751-26756_E.png
00000000000001111111111111000000000000000000000000000000000000000000000000000000:16369-21469-8252_N.png (flipped)
00000000000001111111111111000000000000000000000000000000000000000000000000000000:18056-16294-30425_W.png
00000000000001111111111111000000000000000000000000000000000000000000000000000000:27206-10104-18226_E.png
00000000000001111111111111000000000000000000000000000000000000000000000000000000:31250-3578-9750_S.png (flipped)
00000000000001111111111111000000000000011111111111110000000000000111111111111111:21875-14159-1067_N.png (flipped)
00000000000001111111111111000000000000011111111111110000000000000111111111111111:24426-18830-5627_S.png (flipped)
00000000000001111111111111000000000000011111111111111111111111111111111111111100:20021-11440-20836_W.png
00000000000001111111111111000000000000011111111111111111111111111111111111111100:4555-18116-29_E.png
00000000000001111111111111111111111111111111111111110000000000000000000000000000:18056-16294-30425_E.png
00000000000001111111111111111111111111111111111111110000000000000000000000000000:4555-18116-29_W.png
00000000000001111111111111111111111111111111111111111111111111111111111111111100:20021-11440-20836_E.png
00000000000001111111111111111111111111111111111111111111111111111111111111111100:5004-10810-17642_W.png
00000000000011111111111110000000000000000000000000000000000000000000000000000000:11976-7751-26756_W.png (flipped)
00000000000011111111111110000000000000000000000000000000000000000000000000000000:13858-18007-13070_E.png (flipped)
00000000000011111111111110000000000000000000000000000000000000000000000000000000:20056-20936-29071_S.png
00000000000011111111111110000000000000000000000000000000000000000000000000000000:24658-20374-23042_E.png (flipped)
00000000000011111111111110000000000000000000000000000000000000000000000000000000:24658-20374-23042_S.png
00000000000011111111111110000000000000000000000000000000000000000000000000000000:27206-10104-18226_N.png
00000000000011111111111110000000000000000000000000000000000000000000000000000000:30261-16558-25650_N.png
00000000000011111111111110000000000000000000000000000000000000000000000000000000:31250-3578-9750_W.png (flipped)
00000000000011111111111110000000000000111111111111111111111111111111111111111000:22806-3380-17484_N.png
00000000000011111111111110000000000000111111111111111111111111111111111111111000:30261-16558-25650_S.png
00000000000011111111111111111111111111000000000000011111111111111111111111111111:10297-13918-3702_E.png (flipped)
00000000000011111111111111111111111111000000000000011111111111111111111111111111:13858-18007-13070_W.png (flipped)
00000000000011111111111111111111111111111111111111100000000000000000000000000000:20056-20936-29071_N.png
00000000000011111111111111111111111111111111111111100000000000000000000000000000:22806-3380-17484_S.png
00000000000111111111111100000000000000000000000000000000000000111111111111100000:17636-24599-1877_W.png
00000000000111111111111100000000000000000000000000000000000000111111111111100000:20056-20936-29071_E.png
00000000000111111111111100000000000001111111111111000000000000111111111111111111:13858-18007-13070_S.png (flipped)
00000000000111111111111100000000000001111111111111000000000000111111111111111111:22161-18187-20222_N.png (flipped)
00000000000111111111111111111111111111111111111111000000000000000000000000000000:15816-4564-31665_E.png
00000000000111111111111111111111111111111111111111000000000000000000000000000000:26507-21853-11958_W.png
00000000001111111111111000000000000000000000000000000000000001111111111111000000:30261-16558-25650_E.png (flipped)
00000000001111111111111000000000000000000000000000000000000001111111111111000000:5774-30645-16062_W.png (flipped)
00000000001111111111111000000000000000000000000001111111111111111111111111000000:17636-24599-1877_S.png
00000000001111111111111000000000000000000000000001111111111111111111111111000000:18056-16294-30425_N.png
00000000001111111111111000000000000011111111111110000000000001111111111111000000:11976-7751-26756_S.png
00000000001111111111111000000000000011111111111110000000000001111111111111000000:5774-30645-16062_N.png
00000000001111111111111000000000000011111111111111111111111110000000000000111111:16369-21469-8252_W.png (flipped)
00000000001111111111111000000000000011111111111111111111111110000000000000111111:22161-18187-20222_E.png (flipped)
00000000111111111111100000000000000000000000000111111111111100000000000000000000:15816-4564-31665_N.png (flipped)
00000000111111111111100000000000000000000000000111111111111100000000000000000000:32078-14314-1511_S.png (flipped)
00000000111111111111100000000000000000000000000111111111111111111111111110000000:15816-4564-31665_S.png (flipped)
00000000111111111111100000000000000000000000000111111111111111111111111110000000:4555-18116-29_N.png (flipped)
00000000111111111111100000000000001111111111111000000000000011111111111110000000:32078-14314-1511_E.png
00000000111111111111100000000000001111111111111000000000000011111111111110000000:5167-27533-24066_W.png
00000000111111111111111111111111110000000000000000000000000000000000000001111111:28824-13023-24184_S.png (flipped)
00000000111111111111111111111111110000000000000000000000000000000000000001111111:32078-14314-1511_N.png (flipped)
00000000111111111111111111111111110000000000000111111111111100000000000000000000:13789-10513-4721_W.png
00000000111111111111111111111111110000000000000111111111111100000000000000000000:22806-3380-17484_E.png
00000001111111111111000000000000011111111111110000000000000111111111111100000000:32078-14314-1511_E.png (flipped)
00000001111111111111000000000000011111111111110000000000000111111111111100000000:5167-27533-24066_W.png (flipped)
00000001111111111111111111111111100000000000000000000000000111111111111100000000:15816-4564-31665_S.png
00000001111111111111111111111111100000000000000000000000000111111111111100000000:4555-18116-29_N.png
00000011111111111110000000000000000000000000000000000000011111111111110000000000:30261-16558-25650_E.png
00000011111111111110000000000000000000000000000000000000011111111111110000000000:5774-30645-16062_W.png
00000011111111111110000000000001111111111111000000000000011111111111110000000000:11976-7751-26756_S.png (flipped)
00000011111111111110000000000001111111111111000000000000011111111111110000000000:5774-30645-16062_N.png (flipped)
00000011111111111111111111111110000000000000000000000000011111111111110000000000:17636-24599-1877_S.png (flipped)
00000011111111111111111111111110000000000000000000000000011111111111110000000000:18056-16294-30425_N.png (flipped)
00000111111111111100000000000000000000000000000000000000111111111111100000000000:17636-24599-1877_W.png (flipped)
00000111111111111100000000000000000000000000000000000000111111111111100000000000:20056-20936-29071_E.png (flipped)
00000111111111111111111111111100000000000001111111111111111111111111111111111111:26507-21853-11958_N.png
00000111111111111111111111111100000000000001111111111111111111111111111111111111:5167-27533-24066_S.png
00000111111111111111111111111111111111111110000000000000000000000000000000000000:15816-4564-31665_W.png (flipped)
00000111111111111111111111111111111111111110000000000000000000000000000000000000:17636-24599-1877_E.png (flipped)
00011111111111111111111111111111111111111100000000000001111111111111000000000000:22806-3380-17484_N.png (flipped)
00011111111111111111111111111111111111111100000000000001111111111111000000000000:30261-16558-25650_S.png (flipped)
00111111111111100000000000000000000000000000000000000000000000000000000000000000:21875-14159-1067_S.png
00111111111111100000000000000000000000000000000000000000000000000000000000000000:5004-10810-17642_N.png
00111111111111111111111111111111111111111000000000000011111111111110000000000000:20021-11440-20836_W.png (flipped)
00111111111111111111111111111111111111111000000000000011111111111110000000000000:4555-18116-29_E.png (flipped)
00111111111111111111111111111111111111111111111111111111111111111110000000000000:20021-11440-20836_E.png (flipped)
00111111111111111111111111111111111111111111111111111111111111111110000000000000:5004-10810-17642_W.png (flipped)
11000000000000011111111111110000000000000111111111111100000000000000000000000000:16369-21469-8252_S.png
11000000000000011111111111110000000000000111111111111100000000000000000000000000:24426-18830-5627_N.png
11111100000000000001111111111111111111111111000000000000011111111111110000000000:16369-21469-8252_W.png
11111100000000000001111111111111111111111111000000000000011111111111110000000000:22161-18187-20222_E.png
11111110000000000000000000000000000000000000001111111111111111111111111100000000:28824-13023-24184_S.png
11111110000000000000000000000000000000000000001111111111111111111111111100000000:32078-14314-1511_N.png
11111110000000000000000000000000011111111111111111111111111111111111111111111111:24426-18830-5627_W.png (flipped)
11111110000000000000000000000000011111111111111111111111111111111111111111111111:5167-27533-24066_E.png (flipped)
11111111110000000000000000000000000011111111111110000000000000000000000000000000:22161-18187-20222_W.png (flipped)
11111111110000000000000000000000000011111111111110000000000000000000000000000000:28824-13023-24184_E.png (flipped)
11111111111111100000000000001111111111111000000000000011111111111110000000000000:21875-14159-1067_N.png
11111111111111100000000000001111111111111000000000000011111111111110000000000000:24426-18830-5627_S.png
11111111111111111100000000000011111111111110000000000000111111111111100000000000:13858-18007-13070_S.png
11111111111111111100000000000011111111111110000000000000111111111111100000000000:22161-18187-20222_N.png
11111111111111111110000000000000000000000000000000000000000000000000000000000000:28824-13023-24184_W.png
11111111111111111110000000000000000000000000000000000000000000000000000000000000:5774-30645-16062_E.png
11111111111111111111000000000000000000000000000000000000000000000000000000000000:13789-10513-4721_E.png (flipped)
11111111111111111111000000000000000000000000000000000000000000000000000000000000:32078-14314-1511_W.png (flipped)
11111111111111111111111100000000000000000000000000111111111111000000000000000000:22161-18187-20222_S.png (flipped)
11111111111111111111111100000000000000000000000000111111111111000000000000000000:5167-27533-24066_N.png (flipped)
11111111111111111111111111111000000000000011111111111111111111111111000000000000:10297-13918-3702_E.png
11111111111111111111111111111000000000000011111111111111111111111111000000000000:13858-18007-13070_W.png
11111111111111111111111111111110000000000000111111111111100000000000000000000000:13789-10513-4721_N.png (flipped)
11111111111111111111111111111110000000000000111111111111100000000000000000000000:5774-30645-16062_S.png (flipped)
11111111111111111111111111111111110000000000000000000000000000000000000000000000:10297-13918-3702_S.png (flipped)
11111111111111111111111111111111110000000000000000000000000000000000000000000000:28824-13023-24184_N.png (flipped)
11111111111111111111111111111111111110000000000000111111111111111111111111100000:26507-21853-11958_N.png (flipped)
11111111111111111111111111111111111110000000000000111111111111111111111111100000:5167-27533-24066_S.png (flipped)
11111111111111111111111111111111111111111110000000000000000000000000000000000000:21875-14159-1067_W.png (flipped)
11111111111111111111111111111111111111111110000000000000000000000000000000000000:26507-21853-11958_E.png (flipped)
11111111111111111111111111111111111111111111111000000000000000000000000001111111:24426-18830-5627_W.png
11111111111111111111111111111111111111111111111000000000000000000000000001111111:5167-27533-24066_E.png
Here is a better algorithm, which I scripted already:
From each tile, shave off a 1 pixel row or column from each edge, and output it to ImageMagick's special *.text
format, using names which indicate their respective left/right or top/bottom edge origin.
Convert each such column/row, create the md5sum
of its *.txt
and sort these alphabetically.
Determine which MD5 sums are identical.
Determine from the identical MD5 sums the candidates which would fit at the respective border.
Code snippet
for i in {1,2,3,4,5}*.png; do
convert ${i}[1x80+0+0] +repage left---edge-${i/.png/.text}
convert ${i}[1x80+79+0] +repage right--edge-${i/.png/.text}
convert ${i}[80x1+0+0] +repage top----edge-${i/.png/.text}
convert ${i}[80x1+0+79] +repage bottom-edge-${i/.png/.text}
done
One example how such a text file may look is this:
cat right--edge-5167-27533-24066.text
# ImageMagick pixel enumeration: 1,80,255,gray
0,0: (0,0,0) #000000 gray(0)
0,1: (0,0,0) #000000 gray(0)
0,2: (0,0,0) #000000 gray(0)
0,3: (0,0,0) #000000 gray(0)
0,4: (0,0,0) #000000 gray(0)
0,5: (0,0,0) #000000 gray(0)
0,6: (0,0,0) #000000 gray(0)
0,7: (255,255,255) #FFFFFF gray(255)
0,8: (255,255,255) #FFFFFF gray(255)
0,9: (255,255,255) #FFFFFF gray(255)
0,10: (255,255,255) #FFFFFF gray(255)
0,11: (255,255,255) #FFFFFF gray(255)
0,12: (255,255,255) #FFFFFF gray(255)
0,13: (255,255,255) #FFFFFF gray(255)
0,14: (255,255,255) #FFFFFF gray(255)
0,15: (255,255,255) #FFFFFF gray(255)
0,16: (255,255,255) #FFFFFF gray(255)
0,17: (255,255,255) #FFFFFF gray(255)
0,18: (255,255,255) #FFFFFF gray(255)
0,19: (255,255,255) #FFFFFF gray(255)
0,20: (255,255,255) #FFFFFF gray(255)
0,21: (255,255,255) #FFFFFF gray(255)
0,22: (255,255,255) #FFFFFF gray(255)
0,23: (255,255,255) #FFFFFF gray(255)
0,24: (255,255,255) #FFFFFF gray(255)
0,25: (255,255,255) #FFFFFF gray(255)
0,26: (255,255,255) #FFFFFF gray(255)
0,27: (255,255,255) #FFFFFF gray(255)
0,28: (255,255,255) #FFFFFF gray(255)
0,29: (255,255,255) #FFFFFF gray(255)
0,30: (255,255,255) #FFFFFF gray(255)
0,31: (255,255,255) #FFFFFF gray(255)
0,32: (255,255,255) #FFFFFF gray(255)
0,33: (0,0,0) #000000 gray(0)
0,34: (0,0,0) #000000 gray(0)
0,35: (0,0,0) #000000 gray(0)
0,36: (0,0,0) #000000 gray(0)
0,37: (0,0,0) #000000 gray(0)
0,38: (0,0,0) #000000 gray(0)
0,39: (0,0,0) #000000 gray(0)
0,40: (0,0,0) #000000 gray(0)
0,41: (0,0,0) #000000 gray(0)
0,42: (0,0,0) #000000 gray(0)
0,43: (0,0,0) #000000 gray(0)
0,44: (0,0,0) #000000 gray(0)
0,45: (0,0,0) #000000 gray(0)
0,46: (0,0,0) #000000 gray(0)
0,47: (0,0,0) #000000 gray(0)
0,48: (0,0,0) #000000 gray(0)
0,49: (0,0,0) #000000 gray(0)
0,50: (0,0,0) #000000 gray(0)
0,51: (0,0,0) #000000 gray(0)
0,52: (0,0,0) #000000 gray(0)
0,53: (0,0,0) #000000 gray(0)
0,54: (0,0,0) #000000 gray(0)
0,55: (0,0,0) #000000 gray(0)
0,56: (0,0,0) #000000 gray(0)
0,57: (0,0,0) #000000 gray(0)
0,58: (0,0,0) #000000 gray(0)
0,59: (0,0,0) #000000 gray(0)
0,60: (0,0,0) #000000 gray(0)
0,61: (0,0,0) #000000 gray(0)
0,62: (0,0,0) #000000 gray(0)
0,63: (0,0,0) #000000 gray(0)
0,64: (0,0,0) #000000 gray(0)
0,65: (0,0,0) #000000 gray(0)
0,66: (0,0,0) #000000 gray(0)
0,67: (0,0,0) #000000 gray(0)
0,68: (0,0,0) #000000 gray(0)
0,69: (0,0,0) #000000 gray(0)
0,70: (0,0,0) #000000 gray(0)
0,71: (0,0,0) #000000 gray(0)
0,72: (0,0,0) #000000 gray(0)
0,73: (0,0,0) #000000 gray(0)
0,74: (0,0,0) #000000 gray(0)
0,75: (0,0,0) #000000 gray(0)
0,76: (0,0,0) #000000 gray(0)
0,77: (0,0,0) #000000 gray(0)
0,78: (0,0,0) #000000 gray(0)
0,79: (0,0,0) #000000 gray(0)
As you can see, it is a textual description for each pixel's color of the extracted column (where the pixel coordinates are given in the first field of each line of text). The first line indicates which color space is used.
*Sort MD5 sums alphabetically
When sorting the MD5 sums of these text files alphabetically, it should be immediately obvious where there are identical pixel color rows and columns:
md5sum *.text | sort
Results:
(I manually added a few comments at the end of some lines.)
09c0670b59c03fb3d6f8116ee0fe35a2 bottom-edge-10297-13918-3702.text
09c0670b59c03fb3d6f8116ee0fe35a2 top----edge-28824-13023-24184.text
10be914aa8b6aaa8c0e35a4a93421f3a left---edge-20056-20936-29071.text #left edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a left---edge-22806-3380-17484.text #left edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a left---edge-24658-20374-23042.text #left edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a left---edge-27206-10104-18226.text #left edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a left---edge-30261-16558-25650.text #left edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a right--edge-16369-21469-8252.text #right edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a right--edge-21875-14159-1067.text #right edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a right--edge-24426-18830-5627.text #right edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a right--edge-31250-3578-9750.text #right edge of QR
10be914aa8b6aaa8c0e35a4a93421f3a right--edge-5004-10810-17642.text #right edge of QR
217c799ce772d99e11b7ba2a04f42bb7 bottom-edge-11976-7751-26756.text
217c799ce772d99e11b7ba2a04f42bb7 top----edge-5774-30645-16062.text
2c96cebc6cc175b54cae54f1a27771fa bottom-edge-24426-18830-5627.text
2c96cebc6cc175b54cae54f1a27771fa top----edge-21875-14159-1067.text
3088414b0fe1190bbd4ed9315d86a0ac left---edge-13789-10513-4721.text
3088414b0fe1190bbd4ed9315d86a0ac right--edge-22806-3380-17484.text
3755d45bb6ad21b70f545f39c5550eda left---edge-17636-24599-1877.text
3755d45bb6ad21b70f545f39c5550eda right--edge-20056-20936-29071.text
41fc32b4b70622b4aff7d9e81f81daad left---edge-13858-18007-13070.text
41fc32b4b70622b4aff7d9e81f81daad right--edge-10297-13918-3702.text
480bed740a716fa10593ba061c5b6df5 left---edge-5004-10810-17642.text
480bed740a716fa10593ba061c5b6df5 right--edge-20021-11440-20836.text
55cc4713ee13ebbeb5c2e212e430da94 bottom-edge-28824-13023-24184.text
55cc4713ee13ebbeb5c2e212e430da94 top----edge-32078-14314-1511.text
62fecd6971445d4176a842727767d3f7 left---edge-4555-18116-29.text
62fecd6971445d4176a842727767d3f7 right--edge-18056-16294-30425.text
69565761226f122f98267862108119a6 left---edge-21875-14159-1067.text
69565761226f122f98267862108119a6 right--edge-26507-21853-11958.text
72cec2b0a518c2cce7204188923d9f79 left---edge-26507-21853-11958.text
72cec2b0a518c2cce7204188923d9f79 right--edge-15816-4564-31665.text
7343348f1b10e47b33e0bde47b455c2b left---edge-16369-21469-8252.text
7343348f1b10e47b33e0bde47b455c2b right--edge-22161-18187-20222.text
7661c257d28e1916208ed2a70989e42d bottom-edge-13789-10513-4721.text
7661c257d28e1916208ed2a70989e42d top----edge-17636-24599-1877.text
7d2a0d7aae6dc017ffa7af7180b1c017 left---edge-5167-27533-24066.text
7d2a0d7aae6dc017ffa7af7180b1c017 right--edge-32078-14314-1511.text
85b744d1774cd4ebe50f0cc40d10b491 left---edge-18056-16294-30425.text
85b744d1774cd4ebe50f0cc40d10b491 right--edge-27206-10104-18226.text
88942ff37ce0e884d1995a6dd11708d6 left---edge-10297-13918-3702.text
88942ff37ce0e884d1995a6dd11708d6 right--edge-11976-7751-26756.text
9185daee4fdcea482c9fa805bba40346 bottom-edge-31250-3578-9750.text
9185daee4fdcea482c9fa805bba40346 top----edge-16369-21469-8252.text
9b8a7f18e4ebbc7249e5f26ac18190a8 left---edge-28824-13023-24184.text
9b8a7f18e4ebbc7249e5f26ac18190a8 right--edge-5774-30645-16062.text
9bd8f7a474229aefd988c4231f3b26f4 bottom-edge-21875-14159-1067.text
9bd8f7a474229aefd988c4231f3b26f4 top----edge-5004-10810-17642.text
a1778c1a468c122bf408a9c2bec9135c bottom-edge-13858-18007-13070.text
a1778c1a468c122bf408a9c2bec9135c top----edge-22161-18187-20222.text
a4f3eee0e523f1b343d292987da297b3 bottom-edge-20056-20936-29071.text
a4f3eee0e523f1b343d292987da297b3 bottom-edge-24658-20374-23042.text
a4f3eee0e523f1b343d292987da297b3 top----edge-27206-10104-18226.text
a4f3eee0e523f1b343d292987da297b3 top----edge-30261-16558-25650.text
af851da184ea6d6586c64aaefdc6875b bottom-edge-22806-3380-17484.text
af851da184ea6d6586c64aaefdc6875b top----edge-20056-20936-29071.text
b4047de9fb6458ebfde5b3a11b40241a left---edge-5774-30645-16062.text
b4047de9fb6458ebfde5b3a11b40241a right--edge-30261-16558-25650.text
b58fe9214967f6d2311e11cb0bf1acc4 left---edge-15816-4564-31665.text
b58fe9214967f6d2311e11cb0bf1acc4 right--edge-17636-24599-1877.text
bef4d7004da4f5de4ca5beeabc1222e8 bottom-edge-5774-30645-16062.text
bef4d7004da4f5de4ca5beeabc1222e8 top----edge-13789-10513-4721.text
c042d1cd3dfb339177e8da3c2907d58e bottom-edge-15816-4564-31665.text
c042d1cd3dfb339177e8da3c2907d58e top----edge-4555-18116-29.text
c5f38ebda77190495d77df1fb7002d1e bottom-edge-32078-14314-1511.text
c5f38ebda77190495d77df1fb7002d1e top----edge-15816-4564-31665.text
c61f738453fa3a86b52b2de5c0d43530 left---edge-20021-11440-20836.text
c61f738453fa3a86b52b2de5c0d43530 right--edge-4555-18116-29.text
c772762652d22cbf228e57f0dcf1a3b4 bottom-edge-22161-18187-20222.text
c772762652d22cbf228e57f0dcf1a3b4 top----edge-5167-27533-24066.text
cfaa399406e0be3d07297f23c684e7c3 left---edge-11976-7751-26756.text
cfaa399406e0be3d07297f23c684e7c3 left---edge-31250-3578-9750.text
cfaa399406e0be3d07297f23c684e7c3 right--edge-13858-18007-13070.text
cfaa399406e0be3d07297f23c684e7c3 right--edge-24658-20374-23042.text
d39c2a0c14c20b66b441d368c164171d bottom-edge-18056-16294-30425.text #bottom edge of QR
d39c2a0c14c20b66b441d368c164171d bottom-edge-20021-11440-20836.text #bottom edge of QR
d39c2a0c14c20b66b441d368c164171d bottom-edge-27206-10104-18226.text #bottom edge of QR
d39c2a0c14c20b66b441d368c164171d bottom-edge-4555-18116-29.text #bottom edge of QR
d39c2a0c14c20b66b441d368c164171d bottom-edge-5004-10810-17642.text #bottom edge of QR
d39c2a0c14c20b66b441d368c164171d top----edge-10297-13918-3702.text #top edge of QR
d39c2a0c14c20b66b441d368c164171d top----edge-11976-7751-26756.text #top edge of QR
d39c2a0c14c20b66b441d368c164171d top----edge-13858-18007-13070.text #top edge of QR
d39c2a0c14c20b66b441d368c164171d top----edge-24658-20374-23042.text #top edge of QR
d39c2a0c14c20b66b441d368c164171d top----edge-31250-3578-9750.text #top edge of QR
d71e7b561d2cc251c962a843daff53bb bottom-edge-5167-27533-24066.text
d71e7b561d2cc251c962a843daff53bb top----edge-26507-21853-11958.text
d7ffe4aaf744387e7fa9db32271247e0 bottom-edge-26507-21853-11958.text
d7ffe4aaf744387e7fa9db32271247e0 top----edge-20021-11440-20836.text
da2aa01201b3da20a970928bc2bdef36 bottom-edge-30261-16558-25650.text
da2aa01201b3da20a970928bc2bdef36 top----edge-22806-3380-17484.text
dd86f02cfc0e260463c75ae5b8709f33 bottom-edge-16369-21469-8252.text
dd86f02cfc0e260463c75ae5b8709f33 top----edge-24426-18830-5627.text
dfdaa88ebf33284ac0367f92060cd060 bottom-edge-17636-24599-1877.text
dfdaa88ebf33284ac0367f92060cd060 top----edge-18056-16294-30425.text
f8e2f384f2269e086dc00fb6ff0b3f41 left---edge-32078-14314-1511.text
f8e2f384f2269e086dc00fb6ff0b3f41 right--edge-13789-10513-4721.text
fa59372704f3b48912a33f3780e9dce7 left---edge-22161-18187-20222.text
fa59372704f3b48912a33f3780e9dce7 right--edge-28824-13023-24184.text
fff7e26c6f9852fcfa51e79d154dc58a left---edge-24426-18830-5627.text
fff7e26c6f9852fcfa51e79d154dc58a right--edge-5167-27533-24066.text
One can immediately identify the following pattern:
- 10 identical MD5 sums of
d39c2a0c14c20b66b441d368c164171d
- 10 identical MD5 sums of
10be914aa8b6aaa8c0e35a4a93421f3a
- 20 pairs of identical MD5 sums for left/right edges
- 20 pairs of identical MD5 sums for top/bottom edges
In the case of '1.' and '2.' it is easy to see that these are all-white edges, representing left/right/top/bottom pieces of the complete QR.
The rest of the matches, '3.' and '4.' make it easy to fit each individual tile to a left or right "partner" in a deterministic way.
Update
I've not seen Mark's answer until now. But I see his approach is similar to mine.
I'm not willing to add my complete script to produce the final re-composed QR code though.
So if Mark's solution includes this, he should get the approvement for the correct answer.
This one was easy, if one uses all the info available in the individual tile PNGs:
The QR reader says: http://www.oracle.com/javaone/index.html
It took me less than 3 minutes to come up with the solution -- mainly because I had to type the respective command with one hand while being on the phone at the same time....
How did you produce the tiles?
Update
Now that @RCola has finally answered my question ("How did you produce the tiles?"), I'll reveal how I came up so fast with the correct QR code image.
I did not use an algorithm as he had asked for. I used a "side-channel" attack, by-passing any need to think about such an algorithm.
This side-channel used an "information leak" which was contained in the tile images provided in @RCola's ZIP file. This info is leaked when running a simple identify
command. Here I run it not as a 'simple' command, but -- to make the leaked information more obvious -- as a command that forces a specific output format:
identify -format "%f : %g\n" {1,2,3,4,5}*.png
10297-13918-3702.png : 400x400+160+0
11976-7751-26756.png : 400x400+80+0
13789-10513-4721.png : 400x400+80+160
13858-18007-13070.png : 400x400+240+0
15816-4564-31665.png : 400x400+160+240
16369-21469-8252.png : 400x400+320+80
17636-24599-1877.png : 400x400+80+240
18056-16294-30425.png : 400x400+80+320
20021-11440-20836.png : 400x400+240+320
20056-20936-29071.png : 400x400+0+240
21875-14159-1067.png : 400x400+320+240
22161-18187-20222.png : 400x400+240+80
22806-3380-17484.png : 400x400+0+160
24426-18830-5627.png : 400x400+320+160
24658-20374-23042.png : 400x400+0+0
26507-21853-11958.png : 400x400+240+240
27206-10104-18226.png : 400x400+0+320
28824-13023-24184.png : 400x400+160+80
30261-16558-25650.png : 400x400+0+80
31250-3578-9750.png : 400x400+320+0
32078-14314-1511.png : 400x400+160+160
4555-18116-29.png : 400x400+160+320
5004-10810-17642.png : 400x400+320+320
5167-27533-24066.png : 400x400+240+160
5774-30645-16062.png : 400x400+80+80
(The same information would be contained in the output of identify {1,2,3,4,5}*.png
-- it would just not jump out so obviously.)
What does this show? The %g
percent-escape prints the geometry information about the canvas associated with the PNG tile:
400x400
is the overall size of this tile's canvas. It is obvious, that this was the size of the original PNG representing the complete QR code.
+X+Y
is the offset associated with this tile on the complete canvas.
Using this info makes it extremely easy to directly know which PNG tile has to be placed on which location of the puzzle:
+0+0
obviously has to go to the top left corner
+0+80
obviously goes just below that
+80+0
obviously goes just right of the top left corner
- ...and so on and so forth, until
+320+320
goes into bottom right corner
The OP could have avoided that side-channel info leak (which in this case gives the complete game away) by adding the +repage
parameter to the IM command he used to produce the tiles.
In order to "repair" the leaky tiles he provided and produce more challenging ones I did this:
mkdir challenge
for i in {1,2,3,4,5}*.png; do
convert $i +repage challenge/$i
done
Update 2
(In answer to the comment which despaired about the failure to "see" the info with the help of a hex editor...)
The same info as identify
reveals could be obtained with the help of exiftool
too (albeit in a less "accessible" form):
exiftool 11976-7751-26756.png | grep -E '(Virtual Image|Width|Height|Offset)'
Image Width : 80
Image Height : 80
Image Offset : 80, 0 (pixels)
Virtual Image Width : 400
Virtual Image Height : 400