home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pypil112.zip / PIL-1.1.2.zip / Lib / site-packages / PIL / JpegImagePlugin.py < prev    next >
Text File  |  2001-05-03  |  10KB  |  328 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # JPEG (JFIF) file handling
  6. #
  7. # See "Digital Compression and Coding of Continous-Tone Still Images,
  8. # Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
  9. #
  10. # History:
  11. # 1995-09-09 fl   Created
  12. # 1995-09-13 fl   Added full parser
  13. # 1996-03-25 fl   Added hack to use the IJG command line utilities
  14. # 1996-05-05 fl   Workaround Photoshop 2.5 CMYK polarity bug
  15. # 1996-05-28 fl   Added draft support, JFIF version (0.1)
  16. # 1996-12-30 fl   Added encoder options, added progression property (0.2)
  17. # 1997-08-27 fl   Save mode 1 images as BW (0.3)
  18. # 1998-07-12 fl   Added YCbCr to draft and save methods (0.4)
  19. # 1998-10-19 fl   Don't hang on files using 16-bit DQT's (0.4.1)
  20. #
  21. # Copyright (c) 1997-2001 by Secret Labs AB.
  22. # Copyright (c) 1995-1996 by Fredrik Lundh.
  23. #
  24. # See the README file for information on usage and redistribution.
  25. #
  26.  
  27. __version__ = "0.4.1"
  28.  
  29. import array, string
  30. import Image, ImageFile
  31.  
  32. def i16(c,o=0):
  33.     return ord(c[o+1]) + (ord(c[o])<<8)
  34.  
  35. def i32(c,o=0):
  36.     return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
  37.  
  38. #
  39. # Parser
  40.  
  41. def Skip(self, marker):
  42.     self.fp.read(i16(self.fp.read(2))-2)
  43.  
  44. def APP(self, marker):
  45.     #
  46.     # Application marker.  Store these in the APP dictionary.
  47.     # Also look for well-known application markers.
  48.  
  49.     s = self.fp.read(i16(self.fp.read(2))-2)
  50.     self.app["APP%d" % (marker&15)] = s
  51.  
  52.     if marker == 0xFFE0 and s[:4] == "JFIF":
  53.         self.info["jfif"] = i16(s[5:])
  54.     if marker == 0xFFEE and s[:5] == "Adobe":
  55.         self.info["adobe"] = i16(s[5:])
  56.         self.info["adobe_transform"] = ord(s[11])
  57.  
  58. def SOF(self, marker):
  59.     #
  60.     # Start of frame marker.  Defines the size and mode of the
  61.     # image.  JPEG is colour blind, so we use some simple
  62.     # heuristics to map the number of layers to an appropriate
  63.     # mode.  Note that this could be made a bit brighter, by
  64.     # looking for JFIF and Adobe APP markers.
  65.  
  66.     s = self.fp.read(i16(self.fp.read(2))-2)
  67.     self.size = i16(s[3:]), i16(s[1:])
  68.  
  69.     self.bits = ord(s[0])
  70.     if self.bits != 8:
  71.         raise SyntaxError, "cannot handle %d-bit layers" % self.bits
  72.  
  73.     self.layers = ord(s[5])
  74.     if self.layers == 1:
  75.         self.mode = "L"
  76.     elif self.layers == 3:
  77.         self.mode = "RGB"
  78.     elif self.layers == 4:
  79.         self.mode = "CMYK"
  80.     else:
  81.         raise SyntaxError, "cannot handle %d-layer images" % self.layers
  82.  
  83.     if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
  84.         self.info["progression"] = 1
  85.  
  86.     for i in range(6, len(s), 3):
  87.         t = s[i:i+3]
  88.         # 4-tuples: id, vsamp, hsamp, qtable
  89.         self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2])))
  90.  
  91. def DQT(self, marker):
  92.     #
  93.     # Define quantization table.  Support baseline 8-bit tables
  94.     # only.  Note that there might be more than one table in
  95.     # each marker.
  96.  
  97.     # FIXME: The quantization tables can be used to estimate the
  98.     # compression quality.
  99.  
  100.     s = self.fp.read(i16(self.fp.read(2))-2)
  101.     while len(s):
  102.         if len(s) < 65:
  103.             raise SyntaxError, "bad quantization table marker"
  104.         v = ord(s[0])
  105.         if v/16 == 0:
  106.             self.quantization[v&15] = array.array("b", s[1:65])
  107.             s = s[65:]
  108.         else:
  109.             return # FIXME: add code to read 16-bit tables!
  110.             # raise SyntaxError, "bad quantization table element size"
  111.  
  112.  
  113. #
  114. # JPEG marker table
  115.  
  116. MARKER = {
  117.     0xFFC0: ("SOF0", "Baseline DCT", SOF),
  118.     0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
  119.     0xFFC2: ("SOF2", "Progressive DCT", SOF),
  120.     0xFFC3: ("SOF3", "Spatial lossless", SOF),
  121.     0xFFC4: ("DHT", "Define Huffman table", Skip),
  122.     0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
  123.     0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
  124.     0xFFC7: ("SOF7", "Differential spatial", SOF),
  125.     0xFFC8: ("JPG", "Extension", None),
  126.     0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
  127.     0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
  128.     0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
  129.     0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
  130.     0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
  131.     0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
  132.     0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
  133.     0xFFD0: ("RST0", "Restart 0", None),
  134.     0xFFD1: ("RST1", "Restart 1", None),
  135.     0xFFD2: ("RST2", "Restart 2", None),
  136.     0xFFD3: ("RST3", "Restart 3", None),
  137.     0xFFD4: ("RST4", "Restart 4", None),
  138.     0xFFD5: ("RST5", "Restart 5", None),
  139.     0xFFD6: ("RST6", "Restart 6", None),
  140.     0xFFD7: ("RST7", "Restart 7", None),
  141.     0xFFD8: ("SOI", "Start of image", None),
  142.     0xFFD9: ("EOI", "End of image", None),
  143.     0xFFDA: ("SOS", "Start of scan", Skip),
  144.     0xFFDB: ("DQT", "Define quantization table", DQT),
  145.     0xFFDC: ("DNL", "Define number of lines", Skip),
  146.     0xFFDD: ("DRI", "Define restart interval", Skip),
  147.     0xFFDE: ("DHP", "Define hierarchical progression", SOF),
  148.     0xFFDF: ("EXP", "Expand reference component", Skip),
  149.     0xFFE0: ("APP0", "Application segment 0", APP),
  150.     0xFFE1: ("APP1", "Application segment 1", APP),
  151.     0xFFE2: ("APP2", "Application segment 2", APP),
  152.     0xFFE3: ("APP3", "Application segment 3", APP),
  153.     0xFFE4: ("APP4", "Application segment 4", APP),
  154.     0xFFE5: ("APP5", "Application segment 5", APP),
  155.     0xFFE6: ("APP6", "Application segment 6", APP),
  156.     0xFFE7: ("APP7", "Application segment 7", APP),
  157.     0xFFE8: ("APP8", "Application segment 8", APP),
  158.     0xFFE9: ("APP9", "Application segment 9", APP),
  159.     0xFFEA: ("APP10", "Application segment 10", APP),
  160.     0xFFEB: ("APP11", "Application segment 11", APP),
  161.     0xFFEC: ("APP12", "Application segment 12", APP),
  162.     0xFFED: ("APP13", "Application segment 13", APP),
  163.     0xFFEE: ("APP14", "Application segment 14", APP),
  164.     0xFFEF: ("APP15", "Application segment 15", APP),
  165.     0xFFF0: ("JPG0", "Extension 0", None),
  166.     0xFFF1: ("JPG1", "Extension 1", None),
  167.     0xFFF2: ("JPG2", "Extension 2", None),
  168.     0xFFF3: ("JPG3", "Extension 3", None),
  169.     0xFFF4: ("JPG4", "Extension 4", None),
  170.     0xFFF5: ("JPG5", "Extension 5", None),
  171.     0xFFF6: ("JPG6", "Extension 6", None),
  172.     0xFFF7: ("JPG7", "Extension 7", None),
  173.     0xFFF8: ("JPG8", "Extension 8", None),
  174.     0xFFF9: ("JPG9", "Extension 9", None),
  175.     0xFFFA: ("JPG10", "Extension 10", None),
  176.     0xFFFB: ("JPG11", "Extension 11", None),
  177.     0xFFFC: ("JPG12", "Extension 12", None),
  178.     0xFFFD: ("JPG13", "Extension 13", None),
  179.     0xFFFE: ("COM", "Comment", Skip)
  180. }
  181.  
  182.  
  183. def _accept(prefix):
  184.     return prefix[0] == "\377"
  185.  
  186. class JpegImageFile(ImageFile.ImageFile):
  187.  
  188.     format = "JPEG"
  189.     format_description = "JPEG (ISO 10918)"
  190.  
  191.     def _open(self):
  192.  
  193.         s = self.fp.read(1)
  194.  
  195.         if ord(s[0]) != 255:
  196.             raise SyntaxError, "not an JPEG file"
  197.  
  198.         # Create attributes
  199.         self.bits = self.layers = 0
  200.  
  201.         # JPEG specifics (internal)
  202.         self.layer = []
  203.         self.huffman_dc = {}
  204.         self.huffman_ac = {}
  205.         self.quantization = {}
  206.         self.app = {}
  207.  
  208.         while 1:
  209.  
  210.             s = s + self.fp.read(1)
  211.  
  212.             i = i16(s)
  213.  
  214.             if MARKER.has_key(i):
  215.                 name, description, handler = MARKER[i]
  216.                 # print hex(i), name, description
  217.                 if handler is not None:
  218.                     handler(self, i)
  219.                 if i == 0xFFDA: # start of scan
  220.                     rawmode = self.mode
  221.                     if self.mode == "CMYK" and self.info.has_key("adobe"):
  222.                         rawmode = "CMYK;I" # Photoshop 2.5 is broken!
  223.                     self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
  224.                     # self.__offset = self.fp.tell()
  225.                     break
  226.                 s = self.fp.read(1)
  227.             else:
  228.                 raise SyntaxError, "no marker found"
  229.  
  230.     def draft(self, mode, size):
  231.  
  232.         if len(self.tile) != 1:
  233.             return
  234.  
  235.         d, e, o, a = self.tile[0]
  236.         scale = 0
  237.  
  238.         if a[0] == "RGB" and mode in ["L", "YCbCr"]:
  239.             self.mode = mode
  240.             a = mode, ""
  241.  
  242.         if size:
  243.             scale = max(self.size[0] / size[0], self.size[1] / size[1])
  244.             for s in [8, 4, 2, 1]:
  245.                 if scale >= s:
  246.                     break
  247.             e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1]
  248.             self.size = ((self.size[0]+s-1)/s, (self.size[1]+s-1)/s)
  249.             scale = s
  250.  
  251.         self.tile = [(d, e, o, a)]
  252.         self.decoderconfig = (scale, 1)
  253.  
  254.         return self
  255.  
  256.     def load_djpeg(self):
  257.  
  258.         # ALTERNATIVE: handle JPEGs via the IJG command line utilities
  259.  
  260.         import tempfile, os
  261.         file = tempfile.mktemp()
  262.         os.system("djpeg %s >%s" % (self.filename, file))
  263.  
  264.         try:
  265.             self.im = Image.core.open_ppm(file)
  266.         finally:
  267.             try: os.unlink(file)
  268.             except: pass
  269.  
  270.         self.mode = self.im.mode
  271.         self.size = self.im.size
  272.  
  273.         self.tile = []
  274.  
  275.  
  276. def _fetch(dict, key, default = 0):
  277.     try:
  278.         return dict[key]
  279.     except KeyError:
  280.         return default
  281.  
  282. RAWMODE = {
  283.     "1": "L",
  284.     "L": "L",
  285.     "RGB": "RGB",
  286.     "RGBA": "RGB",
  287.     "RGBX": "RGB",
  288.     "CMYK": "CMYK",
  289.     "YCbCr": "YCbCr",
  290. }
  291.  
  292. def _save(im, fp, filename):
  293.  
  294.     try:
  295.         rawmode = RAWMODE[im.mode]
  296.     except KeyError:
  297.         raise IOError, "cannot write mode %s as JPEG" % im.mode
  298.  
  299.     # get keyword arguments
  300.     im.encoderconfig = (_fetch(im.encoderinfo, "quality", 0),
  301.                         im.encoderinfo.has_key("progressive"),
  302.                         _fetch(im.encoderinfo, "smooth", 0),
  303.                         im.encoderinfo.has_key("optimize"),
  304.                         _fetch(im.encoderinfo, "streamtype", 0))
  305.  
  306.     ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
  307.  
  308. def _save_cjpeg(im, fp, filename):
  309.     # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
  310.     import os
  311.     file = im._dump()
  312.     os.system("cjpeg %s >%s" % (file, filename))
  313.     try: os.unlink(file)
  314.     except: pass
  315.  
  316. # -------------------------------------------------------------------q-
  317. # Registry stuff
  318.  
  319. Image.register_open("JPEG", JpegImageFile, _accept)
  320. Image.register_save("JPEG", _save)
  321.  
  322. Image.register_extension("JPEG", ".jfif")
  323. Image.register_extension("JPEG", ".jpe")
  324. Image.register_extension("JPEG", ".jpg")
  325. Image.register_extension("JPEG", ".jpeg")
  326.  
  327. Image.register_mime("JPEG", "image/jpeg")
  328.