Jump to content
cmiN

[Python] Text In Bmp (console) [cmiN]

Recommended Posts

Posted

http://codepad.org/QVfDwe9L

#! /usr/bin/env python3.1
# 05.04.2010 <> 06.04.2010 | cmiN
# Text In Bmp (console)

import sys
from hashlib import md5

class Image:

def load(self, path):
with open(path, "rb") as file:
buffer = file.read()
self.bfType = buffer[0:2]
if self.bfType != b"BM":
raise Exception("not a bitmap")
self.bfSize = buffer[2:6]
self.bfReserved1 = buffer[6:8]
self.bfReserved2 = buffer[8:10]
self.bfOffBits = buffer[10:14]
self.biSize = buffer[14:18]
self.biWidth = buffer[18:22]
self.biHeight = buffer[22:26]
self.biPlanes = buffer[26:28]
self.biBitCount = buffer[28:30]
if baconvert(self.biBitCount) != 24:
raise Exception("not 24-bit")
self.biCompression = buffer[30:34]
self.biSizeImage = buffer[34:38]
self.biXPelsPerMeter = buffer[38:42]
self.biYPelsPerMeter = buffer[42:46]
self.biClrUsed = buffer[46:50]
self.biClrImportant = buffer[50:54]
self.bHeader = buffer[:54]
self.bMatrix = list(buffer[54:])

def create(self, path, buffer):
with open(path, "wb") as file:
file.write(buffer)

def process(digsig, mode, infile, outfile=None, string=None):
bmp = Image()
bmp.load(infile)
bmp.width = baconvert(bmp.biWidth)
bmp.height = baconvert(bmp.biHeight)
bmp.index = 0
bmp.count = 0
rem = (bmp.width * 3) % 4
if rem:
bmp.padding = 4 - rem
else:
bmp.padding = 0
if mode == "write":
bits = str()
for char in md5(bytes(digsig, "ascii")).digest():
bits += bin(char).replace("0b", "").zfill(8)
bits += bin(len(string)).replace("0b", "").zfill(16)
for char in string:
bits += bin(ord(char)).replace("0b", "").zfill(8)
if len(bits) > bmp.width * bmp.height * 3:
raise Exception("string too long")
for bit in bits:
char = bin(bmp.bMatrix[bmp.index])
char = int(char[:-1] + bit, 2)
bmp.bMatrix[bmp.index] = char
bmp.index += 1
bmp.count += 1
if bmp.count == (bmp.width * 3):
bmp.count = 0
bmp.index += bmp.padding
bmp.create(outfile, bmp.bHeader + bytes(bmp.bMatrix))
elif mode == "read":
bits = bitjoin(bmp, 128)
if bytes([int(bits[i:i + 8], 2) for i in range(0, 128, 8)]) == md5(bytes(digsig, "ascii")).digest():
nr = int(bitjoin(bmp, 16), 2) * 8
bits = bitjoin(bmp, nr)
string = "".join([chr(int(bits[i:i + 8], 2)) for i in range(0, nr, 8)])
print(string)
else:
raise Exception("invalid signature")
else:
raise Exception("invalid mode")

def bitjoin(bmp, nr):
bits = str()
for i in range(nr):
bits += bin(bmp.bMatrix[bmp.index])[-1]
bmp.index += 1
bmp.count += 1
if bmp.count == (bmp.width * 3):
bmp.count = 0
bmp.index += bmp.padding
return bits

def baconvert(buffer):
return int("".join([hex(char).replace("0x", "").zfill(2) for char in reversed(buffer)]), 16)

def main(args):
usage = """\t\t Text In Bmp 1.0

\t Usage: source.ext digsig mode infile [outfile text]

Where digsig is a digital signature string
mode can be write or read
infile is a valid 24-bit bitmap image
outfile is the output image name (used with write mode)
text is the string that will be written in image (used with write mode)

\t Example: tib.py cmiN write image1.bmp image2.bmp http://rstcenter.com
\t tib.py cmiN read image2.bmp"""
try:
print("Please wait...")
if len(args) == 4:
process(args[1], args[2], args[3])
elif len(args) == 6:
process(args[1], args[2], args[3], args[4], args[5])
else:
print(usage)
except Exception as message:
print("An error occurred: {}".format(message))
except:
print("Unknown error.")
else:
print("Ready!")

if __name__ == "__main__":
main(sys.argv)

Dupa cum spune si denumirea, cu acest script poti ascunde text in imagini de tip 24-bit bmp. Voi reveni mai pe seara cu un tutorial facut frumos in flash care explica mai multe si se foloseste de acest script. Metoda folosita este LSB iar bitii provin din octeti direct din plain text, nu am folosit nicio encriptie/codare in schimb am folosit un md5(semnatura) pentru a sti daca in imaginea respectiva a fost scris ceva si daca coincide.

Ca de obicei aceeasi versiune de Python: 3.x dupa cum se vede si la inceputul script-ului.

  • Upvote 1
Posted
Nice. Niciodata nu am putut sa inteleg bmp-ul.

/me o sa citeasca pe wikipedia mai atent. ^^

pai e cel mai banal si usor de inteles format: 24bit fara compresie=un array cu elemente de 3 bytes: red green si blue, si un header inaintea lui, am uitat dimensiunea.

Posted

P.S.: Poza sa fie de minim 51 pixeli care ii folosesc pentru 152 biti (3 bytes la fiecare pixel; 1 bit la fiecare byte): 128 semnatura 16 lungimea string-ului si inca minim 8 pentru string-ul introdus minim: 1 char. Tutorialul e inca in dezvoltare :)).

Posted
P.S.: Poza sa fie de minim 152 pixeli care ii folosesc pentru 152 biti: 128 semnatura 16 lungimea string-ului si inca minim 8 pentru string-ul introdus minim: 1 char. Tutorialul e inca in dezvoltare :)).

presupun ca e recomandat o poza cat mai mare si cat mai multe detalii mici in diferite culori. Altfel ar sari in ochi "puricii" de la stringurile respective, iar la 152 ar fi inlocuita total.

Posted

Nup ... nu vezi deloc diferenta dintre poze ;). Ochiul uman nu poate sesiza nici 10 nivele de culoare dintr-un canal ... pe cand eu modific doar cu un nivel doar atunci cand este cazul.

Edit: tutorial

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...