JPEG文件格式解析及字节写入位置错误问题咨询
Hey Stefan, I’ve dealt with this exact issue before—JPEGs aren’t just raw byte dumps, so it makes sense that random byte writes are messing things up. Let’s break down how JPEGs work and how to fix this.
JPEG files are built from a sequence of marker segments, not a continuous stream of pixel data. Every marker starts with 0xFF followed by a 1-byte code that defines its purpose:
0xFFD8: SOI (Start of Image) – the very first marker of the file0xFFE1(and others like0xFFE0): APP segments – hold metadata like EXIF, thumbnails, etc.0xFFDA: SOS (Start of Scan) – this marks the beginning of the actual compressed pixel data0xFFD9: EOI (End of Image) – the final marker that closes the image
If you’re writing bytes into the APP metadata segments or before the SOS marker, the image itself won’t change at all. Only the data between SOS and EOI affects the visible image.
To write bytes to the correct location (so they affect the image), follow these steps:
- Locate the SOS marker: Scan the file for
0xFFDA. After this marker, there’s a 2-byte parameter length (tells you how long the SOS header is) – skip this header to get to the start of the compressed pixel data. - Find the EOI marker: Scan from the end of the SOS header onward to find
0xFFD9– this is where the compressed data ends. - Write your bytes in the safe zone: Insert or modify bytes between the end of the SOS header and the EOI marker.
Important: If you want to add data without breaking the image (but not affect the visible content), you can write bytes after the EOI marker—most image viewers will ignore this trailing data.
Here’s a quick script to locate the correct region and write your bytes (replace your_image.jpg and your_bytes with your actual file and data):
with open("your_image.jpg", "rb+") as img_file: # Read the entire file into a mutable byte array file_data = bytearray(img_file.read()) # Locate the SOS marker (0xFFDA) sos_marker = b'\xFF\xDA' sos_position = file_data.find(sos_marker) if sos_position == -1: raise ValueError("Invalid JPEG: Could not find SOS marker") # Skip the SOS parameter length (2 bytes) and the parameter content param_length = (file_data[sos_position + 2] << 8) | file_data[sos_position + 3] compressed_data_start = sos_position + 2 + param_length # Locate the EOI marker (0xFFD9) starting from the compressed data eoi_marker = b'\xFF\xD9' eoi_position = file_data.find(eoi_marker, compressed_data_start) if eoi_position == -1: raise ValueError("Invalid JPEG: Could not find EOI marker") # Replace a chunk of the compressed data with your bytes your_bytes = b'\x01\x02\x03\x04\x05' # Replace with your actual byte data if len(your_bytes) <= (eoi_position - compressed_data_start): # Overwrite the first N bytes of the compressed data file_data[compressed_data_start:compressed_data_start + len(your_bytes)] = your_bytes # Write the modified data back to the file img_file.seek(0) img_file.write(file_data) print("Bytes written successfully to image data region") else: print("Error: Your byte data is too long for the available compressed data space")
- Expect image artifacts: JPEG uses lossy Huffman coding, so modifying the compressed data will almost certainly cause visual glitches (like blocky areas). If you need to modify pixels without artifacts, you’ll have to decode the JPEG to a raw bitmap (e.g., using PIL/Pillow), edit the bitmap, then re-encode it to JPEG.
- Don’t touch markers: Never modify or overwrite the
0xFFmarker sequences—this will make the file unrecognizable as a valid JPEG. - Trailing data is safe: If you just need to store extra bytes with the image (not affect the visual part), appending after
0xFFD9is a risk-free approach.
内容的提问来源于stack exchange,提问作者Stefan

