jacob schiffer
jacob schiffer

Reputation: 23

Creating a copy of image file while processing in python

I am processing a BMP file and currently I am converting it into a grayscale. I am however, using rb+ which writes to the same file and saves the original as processed. How do I process the image file which actually makes a copy of the original and processes it instead of destroying the original?

Here is the code

from io import SEEK_CUR

def main():
    filename = input("Please enter the file name: ")

    # Open as a binary file for reading and writing
    imgFile = open(filename, "rb+")

    # Extract the image information.
    fileSize = readInt(imgFile, 2)
    start = readInt(imgFile, 10)
    width = readInt(imgFile, 18)
    height = readInt(imgFile, 22)

    # Scan lines must occupy multiples of four bytes.
    scanlineSize = width * 3
    if scanlineSize % 4 == 0:
        padding = 0
    else :
        padding = 4 - scanlineSize % 4

    # Make sure this is a valid image.
    if fileSize != (start + (scanlineSize + padding) * height):
        exit("Not a 24-bit true color image file.")

    # Move to the first pixel in the image.
    imgFile.seek(start)# Process the individual pixels.
    for row in range(height): #For each scan line
        for col in range(width): #For each pixel in the line
            processPixel(imgFile)

        # Skip the padding at the end.
        imgFile.seek(padding, SEEK_CUR)

    imgFile.close()## Processes an individual pixel.#@param imgFile the binary file containing the BMP image#

def processPixel(imgFile) :
#  Read the pixel as individual bytes.
    theBytes = imgFile.read(3)
    blue = theBytes[0]
    green = theBytes[1]
    red = theBytes[2] #Read the pixel as individual bytes.
    # Process the pixel
    newBlue = 255 - blue
    newGreen = 255 - green
    newRed = 255 - red
    # Process the pixel.



    # Write the pixel.
    imgFile.seek(-3, SEEK_CUR)# Go back 3 bytes to the start of the pixel.

    imgFile.write(bytes([newBlue, newGreen, newRed]))## Gets an integer from a binary file.#@param imgFile the file#@ param offset the offset at which to read the integer#@
##  Gets an integer from a binary file.
# @param imgFile  the file
# @param offset  the offset at which to read the integer
# @return  the integer starting at the given offset
#

def readInt(imgFile, offset): #Move the file pointer to the given byte within the file.
    imgFile.seek(offset)

    # Read the 4 individual bytes and build an integer.
    theBytes = imgFile.read(4)
    result = 0
    base = 1
    for i in range(4):
        result = result + theBytes[i] * base
        base = base * 256

    return result# Start the program.
main()

Upvotes: 2

Views: 1529

Answers (1)

Colin Schoen
Colin Schoen

Reputation: 2600

I would recommend making a copy of the file first then writing to that copy.

You can use the copyfile function from the shutil module to copy a file. Here is a demo of how to copy a file:

import shutil  
shutil.copyfile('/path/to/src/file', '/path/to/dest/file')  

Upvotes: 3

Related Questions