# Read quantization tables from JPEG files

I'm developing an application that will hide information inside the quantization tables of JPEG files. It's called DQTsteg, if you want to know more about what I'm attempting to do.

Right now I'm developing the most basic component of this system, which is the part that reads quantization tables from files. So it'd be a good thing if this code were as fast as it can possibly be, as it'll be a very frequent operation.

Here's the whole code on GitHub, fewer than 93 lines long.

I have noticed that sometimes urllib.requests sometimes are somewhat slow (above one second).

I've seen some people on Stack Overflow saying that some servers don't support byte by byte requests through urllib.request (you either download the whole file or you don't). I don't know whether these people are right or not, but is there any case where this urllib.request could go wrong (and then I'd either be denied access to the target file or I'd loop endlessly over the first few bytes, or anything of this sort)?

Any suggestions are welcome. Here follows the code:

#!/usr/bin/env python

"""

Functions for reading quantization tables from files and URLs.

Below are some global variables defined according to the JPEG Standard.

"""

DEFINE_QUANTIZATION_TABLE = b'\xff\xdb'

"""
Loads a file from jpgpath. Direct acess not intended; use QT_get_single() or QT_get_all().
Args:
jpgpath (str): file path.
Returns:
jpgpath (object): file object.
"""
if load_file.status == "web":
import urllib.request
jpgpath = urllib.request.urlopen(jpgpath)
if load_file.status == "file":
jpgpath = open(jpgpath,"rb")
return jpgpath

def QT_get_single(jpgpath, status="file"):
"""
Reads a single quantization table from file.
Args:
jpgpath (str): file path, local or URL.
status (str): set to "file" for local files or set to "web" for URLs.
Returns:
tuple: A tuple with .tell() position for the DQT on [0] and the QT table itself on [1] as a bytearray.
"""
if QT_get_single.status != "off":
if status == "web":
elif status == "file":
while True:
while True:
if QT_buffer == DEFINE_QUANTIZATION_TABLE: break
if QT_buffer == b'':
raise EOFError("Reached end of file.")
DQT_position = jpgpath.tell()
if QT_buffer == DOUBLE_TABLE_PAYLOAD_DATA:
break
elif QT_buffer == SINGLE_TABLE_PAYLOAD_DATA:
break
else:
continue
return ( DQT_position, bytearray(QT_buffer) )

def QT_get_all(jpgpath, status="file",stop=-1):
"""
Reads multiple quantization tables from file. Reads all QTs by default.
Args:
jpgpath (str): file path, local or URL.
status (str): set to "file" for local files or set to "web" for URLs.
stop (int): Stop after retrieving the nth table. One retrieves one; two retrieves two; zero or default retrieves all.
Returns:
list: A list of QT_get_single() tuples.
"""
QT_tables = []
counter = 0

QT_get_single.jpgpath = jpgpath
QT_get_single.status = "off"

while True:
try:
QT_buffer = QT_get_single(QT_get_single.jpgpath,QT_get_single.status)
QT_tables.append(QT_buffer)
counter += 1
except: break
if counter == stop: break
return QT_tables

• It might be worth while doing from urrlib import request rather than import urrlib.request because it will probably make the other bit look nicer as you just have to call request... rather than urrlib.request... – 13ros27 Dec 21 '17 at 16:45