Case Study: PPM Image Class

Now that you have seen and written a few classes, it may be helpful to see the complete code for the ImagePPM class used in Chapters 21 and 22.

Listing 24.3: ImagePPM

 1 # image.py
 2
 3 def clamp(x, a, b):
 4 return max(a, min(b, x))
 5
 6 class ImagePPM:
 7 @classmethod
 8 def new(cls, size):
 9  newimg = ImagePPM()
10  newimg.size = size
11  newimg.maxval = 255
12  newimg.data = [0] * 3 * size[0] * size[1]
13  return newimg
14
15 @classmethod
16 def open(cls, fname):
17  newimg = ImagePPM()
18  with open(fname) as f:
19    header = f.readline()
20    if not header.startswith("P3"):
21    return None
22    nextline = f.readline()
23    while nextline.startswith("#"):
24    nextline = f.readline()
25    newimg.size = tuple(map(int, nextline.split()))
26    newimg.maxval = int(f.readline())
27    newimg.data = list(map(int, f.read().split()))
28  return newimg
29
30 def index(self, coords):
31  i, j = coords
32  return 3 * (j * self.size[0] + i)
33
34 def getpixel(self, coords):
35  k = self.index(coords)
36  return tuple(self.data[k:k + 3])
37
38 def putpixel(self, coords, color):
39  k = self.index(coords)
40  for i in range(3):
41    self.data[k + i] = clamp(color[i], 0, 255)
42
43 def save(self, fname):
44  width, height = self.size
45  with open(fname, "w") as f:
46    f.write("P3
")
47    f.write(str(width) + " " + str(height) + "
")
48    f.write(str(self.maxval) + "
")
49    for i in range(3 * width * height):
50    f.write(str(self.data[i]) + "
")

The main new feature is the use of class methods instead of explicit constructors to create new image objects.

Class Methods

To this point, the term “method” has been used to refer to object methods, also known as instance methods. Recall that an object method is always called from an object:

 <object>.<method>(<arguments>)

A class method is similar except that it is usually called from the class rather than a particular object:

<ClassName>.<method>(<arguments>)

Class methods are defined with a first parameter of cls (short for “class,” which is already a keyword) instead of self, as in lines 8 and 16. The main thing to remember when writing a class method is that it does not have access to any instance variables via self. Class methods in Python are prefaced with the decorator @classmethod. The decorator indicates to the interpreter our intention to use these methods as class methods.

The two class methods open() and new() in Listing 24.3 are examples of factory methods because they create and return new ImagePPM objects.

PPM Image Formats

There are actually two types of PPM images: ASCII and raw binary.

ASCII PPM images look like this:

 P3
 # CREATOR: GIMP PNM Filter Version 1.1
 300 225
 255
 89
 157
 232
 ...

The first line must be “P3” and indicates the ASCII PPM format. Optional comment lines, beginning with a “#”, may follow the P3. The next line contains two integers: the image width and height (300 and 225 in this case). The following line contains the maximum color value for each RGB component, which is usually 255. All remaining lines contain RGB pixel data. In this case, the first pixel has color (89, 157, 232).

Because they are stored in ASCII format, ASCII PPM images may be viewed in a text editor, which is handy when tracking down bugs. However, it also means that ASCII PPM files are huge: every character requires a separate byte of storage, and no compression has been used.

Raw binary PPM images, while still uncompressed, are more efficient than ASCII PPM. They have the same header format except that the type is “P6.” However, the RGB color data is stored in binary, using one byte per component instead of one byte per character. Two bytes per component are used if the maximum color value is 65535. Because only the header lines are in ASCII, raw binary files cannot be viewed in a text editor.

Exercises

  1. Measure the difference in size between an ASCII PPM and a raw binary PPM of the same image.
  2. Explain in your own words how each of these methods works from Listing 24.3:
    1. (a) new()
    2. (b) open()
    3. (c) index()
    4. (d) getpixel()
    5. (e) putpixel()
    6. (f) save()
  3. 3. Modify Listing 24.3 to add a .copy() method to the ImagePPM class that returns an exact copy of self.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.39.16