@@ -16,6 +16,11 @@ class Jpeg(Image):
1616 """
1717 Base class for JFIF and EXIF subclasses.
1818 """
19+ def __init__ (self , blob , filename , cx , cy , horz_dpi , vert_dpi ):
20+ super (Jpeg , self ).__init__ (blob , filename , cx , cy , attrs = {})
21+ self ._horz_dpi = horz_dpi
22+ self ._vert_dpi = vert_dpi
23+
1924 @property
2025 def content_type (self ):
2126 """
@@ -24,22 +29,48 @@ def content_type(self):
2429 """
2530 return MIME_TYPE .JPEG
2631
32+ @property
33+ def horz_dpi (self ):
34+ """
35+ Integer dots per inch for the width of this image. Defaults to 72
36+ when not present in the file, as is often the case.
37+ """
38+ return self ._horz_dpi
39+
40+ @property
41+ def vert_dpi (self ):
42+ """
43+ Integer dots per inch for the height of this image. Defaults to 72
44+ when not present in the file, as is often the case.
45+ """
46+ return self ._vert_dpi
47+
2748
2849class Exif (Jpeg ):
2950 """
3051 Image header parser for Exif image format
3152 """
53+ @classmethod
54+ def from_stream (cls , stream , blob , filename ):
55+ """
56+ Return |Exif| instance having header properties parsed from Exif
57+ image in *stream*.
58+ """
59+ markers = _JfifMarkers .from_stream (stream )
60+ # print('\n%s' % markers)
61+
62+ px_width = markers .sof .px_width
63+ px_height = markers .sof .px_height
64+ horz_dpi = markers .app1 .horz_dpi
65+ vert_dpi = markers .app1 .vert_dpi
66+
67+ return cls (blob , filename , px_width , px_height , horz_dpi , vert_dpi )
3268
3369
3470class Jfif (Jpeg ):
3571 """
3672 Image header parser for JFIF image format
3773 """
38- def __init__ (self , blob , filename , cx , cy , horz_dpi , vert_dpi ):
39- super (Jfif , self ).__init__ (blob , filename , cx , cy , attrs = {})
40- self ._horz_dpi = horz_dpi
41- self ._vert_dpi = vert_dpi
42-
4374 @classmethod
4475 def from_stream (cls , stream , blob , filename ):
4576 """
@@ -52,22 +83,6 @@ def from_stream(cls, stream, blob, filename):
5283 horz_dpi , vert_dpi = app0 .horz_dpi , app0 .vert_dpi
5384 return cls (blob , filename , cx , cy , horz_dpi , vert_dpi )
5485
55- @property
56- def horz_dpi (self ):
57- """
58- Integer dots per inch for the width of this image. Defaults to 72
59- when not present in the file, as is often the case.
60- """
61- return self ._horz_dpi
62-
63- @property
64- def vert_dpi (self ):
65- """
66- Integer dots per inch for the height of this image. Defaults to 72
67- when not present in the file, as is often the case.
68- """
69- return self ._vert_dpi
70-
7186
7287class _JfifMarkers (object ):
7388 """
@@ -78,6 +93,22 @@ def __init__(self, markers):
7893 super (_JfifMarkers , self ).__init__ ()
7994 self ._markers = list (markers )
8095
96+ def __str__ (self ):
97+ """
98+ Returns a tabular listing of the markers in this instance, which can
99+ be handy for debugging and perhaps other uses.
100+ """
101+ header = ' offset seglen mc name\n ======= ====== == ====='
102+ tmpl = '%7d %6d %02X %s'
103+ rows = []
104+ for marker in self ._markers :
105+ rows .append (tmpl % (
106+ marker .offset , marker .segment_length ,
107+ ord (marker .marker_code ), marker .name
108+ ))
109+ lines = [header ] + rows
110+ return '\n ' .join (lines )
111+
81112 @classmethod
82113 def from_stream (cls , stream ):
83114 """
@@ -102,6 +133,13 @@ def app0(self):
102133 return m
103134 raise KeyError ('no APP0 marker in image' )
104135
136+ @property
137+ def app1 (self ):
138+ """
139+ First APP1 marker in image markers.
140+ """
141+ raise NotImplementedError
142+
105143 @property
106144 def sof (self ):
107145 """
@@ -267,6 +305,14 @@ def marker_code(self):
267305 """
268306 return self ._marker_code
269307
308+ @property
309+ def name (self ):
310+ return JPEG_MARKER_CODE .marker_names [self ._marker_code ]
311+
312+ @property
313+ def offset (self ):
314+ return self ._offset
315+
270316 @property
271317 def segment_length (self ):
272318 """
0 commit comments