En utilisant AperiSolve, on peut voir dans la vue superposée que les bits de faibles valeurs sont un peu différents, on distingue par exemple du rouge au centre du carré en haut à gauche :
On peut confirmer la chose avec un site comme StegOnline en regardant uniquement le bit 0 du canal Rouge, Vert ou Bleu :
En fait, les trois carrés contiennent des pixels différents sur leur bit 0, et ils forment un nouveau QRCode où chaque pixel de celui-ci est séparé de 4 pixels :
On peut récupérer ces pixels en python :
from base64 import b64decode
from io import BytesIO
from PIL import Image
import qreader
img = Image.open('QR.png')
def extract_qrcode(img: Image.Image, from_xy: tuple[int, int], canal: int) -> Image.Image:
qr_size = 45
qrcode = Image.new('L', (qr_size, qr_size), 0)
for y in range(qr_size):
for x in range(qr_size):
pixel = img.getpixel((from_xy[0] + x * 5, from_xy[1] + y * 5))
qrcode.putpixel((x, y), 0 if pixel[canal] & 0x1 else 255)
return qrcode.resize((qr_size*4, qr_size*4), Image.Resampling.NEAREST)
qrcode_r = extract_qrcode(img, (255, 255), 0)
qrcode_g = extract_qrcode(img, (1785, 255), 1)
qrcode_b = extract_qrcode(img, (255, 1785), 2)
On obtient les qrcodes suivants :
Si on les décode, on obtient de la base64 qui est en fait une nouvelle image :