101 transform_name = images_service_pb.ImagesServiceTransform.Type_Name( |
105 transform_name = images_service_pb.ImagesServiceTransform.Type_Name( |
102 transform) |
106 transform) |
103 raise BadRequestError("A '%s' transform has already been " |
107 raise BadRequestError("A '%s' transform has already been " |
104 "requested on this image." % transform_name) |
108 "requested on this image." % transform_name) |
105 self._transform_map[transform] = True |
109 self._transform_map[transform] = True |
|
110 |
|
111 def _update_dimensions(self): |
|
112 """Updates the width and height fields of the image. |
|
113 |
|
114 Raises: |
|
115 NotImageError if the image data is not an image. |
|
116 BadImageError if the image data is corrupt. |
|
117 """ |
|
118 size = len(self._image_data) |
|
119 if size >= 6 and self._image_data.startswith("GIF"): |
|
120 self._update_gif_dimensions() |
|
121 elif size >= 8 and self._image_data.startswith("\x89PNG\x0D\x0A\x1A\x0A"): |
|
122 self._update_png_dimensions() |
|
123 elif size >= 2 and self._image_data.startswith("\xff\xD8"): |
|
124 self._update_jpeg_dimensions() |
|
125 elif (size >= 8 and (self._image_data.startswith("II\x2a\x00") or |
|
126 self._image_data.startswith("MM\x00\x2a"))): |
|
127 self._update_tiff_dimensions() |
|
128 elif size >= 2 and self._image_data.startswith("BM"): |
|
129 self._update_bmp_dimensions() |
|
130 elif size >= 4 and self._image_data.startswith("\x00\x00\x01\x00"): |
|
131 self._update_ico_dimensions() |
|
132 else: |
|
133 raise NotImageError("Unrecognized image format") |
|
134 |
|
135 def _update_gif_dimensions(self): |
|
136 """Updates the width and height fields of the gif image. |
|
137 |
|
138 Raises: |
|
139 BadImageError if the image string is not a valid gif image. |
|
140 """ |
|
141 size = len(self._image_data) |
|
142 if size >= 10: |
|
143 self._width, self._height = struct.unpack("<HH", self._image_data[6:10]) |
|
144 else: |
|
145 raise BadImageError("Corrupt GIF format") |
|
146 |
|
147 def _update_png_dimensions(self): |
|
148 """Updates the width and height fields of the png image. |
|
149 |
|
150 Raises: |
|
151 BadImageError if the image string is not a valid png image. |
|
152 """ |
|
153 size = len(self._image_data) |
|
154 if size >= 24 and self._image_data[12:16] == "IHDR": |
|
155 self._width, self._height = struct.unpack(">II", self._image_data[16:24]) |
|
156 else: |
|
157 raise BadImageError("Corrupt PNG format") |
|
158 |
|
159 def _update_jpeg_dimensions(self): |
|
160 """Updates the width and height fields of the jpeg image. |
|
161 |
|
162 Raises: |
|
163 BadImageError if the image string is not a valid jpeg image. |
|
164 """ |
|
165 size = len(self._image_data) |
|
166 offset = 2 |
|
167 while offset < size: |
|
168 while offset < size and ord(self._image_data[offset]) != 0xFF: |
|
169 offset += 1 |
|
170 while offset < size and ord(self._image_data[offset]) == 0xFF: |
|
171 offset += 1 |
|
172 if (offset < size and ord(self._image_data[offset]) & 0xF0 == 0xC0 and |
|
173 ord(self._image_data[offset]) != 0xC4): |
|
174 offset += 4 |
|
175 if offset + 4 < size: |
|
176 self._height, self._width = struct.unpack( |
|
177 ">HH", |
|
178 self._image_data[offset:offset + 4]) |
|
179 break |
|
180 else: |
|
181 raise BadImageError("Corrupt JPEG format") |
|
182 elif offset + 2 <= size: |
|
183 offset += 1 |
|
184 offset += struct.unpack(">H", self._image_data[offset:offset + 2])[0] |
|
185 else: |
|
186 raise BadImageError("Corrupt JPEG format") |
|
187 if self._height is None or self._width is None: |
|
188 raise BadImageError("Corrupt JPEG format") |
|
189 |
|
190 def _update_tiff_dimensions(self): |
|
191 """Updates the width and height fields of the tiff image. |
|
192 |
|
193 Raises: |
|
194 BadImageError if the image string is not a valid tiff image. |
|
195 """ |
|
196 size = len(self._image_data) |
|
197 if self._image_data.startswith("II"): |
|
198 endianness = "<" |
|
199 else: |
|
200 endianness = ">" |
|
201 ifd_offset = struct.unpack(endianness + "I", self._image_data[4:8])[0] |
|
202 if ifd_offset < size + 14: |
|
203 ifd_size = struct.unpack( |
|
204 endianness + "H", |
|
205 self._image_data[ifd_offset:ifd_offset + 2])[0] |
|
206 ifd_offset += 2 |
|
207 for unused_i in range(0, ifd_size): |
|
208 if ifd_offset + 12 <= size: |
|
209 tag = struct.unpack( |
|
210 endianness + "H", |
|
211 self._image_data[ifd_offset:ifd_offset + 2])[0] |
|
212 if tag == 0x100 or tag == 0x101: |
|
213 value_type = struct.unpack( |
|
214 endianness + "H", |
|
215 self._image_data[ifd_offset + 2:ifd_offset + 4])[0] |
|
216 if value_type == 3: |
|
217 format = endianness + "H" |
|
218 end_offset = ifd_offset + 10 |
|
219 elif value_type == 4: |
|
220 format = endianness + "I" |
|
221 end_offset = ifd_offset + 12 |
|
222 else: |
|
223 format = endianness + "B" |
|
224 end_offset = ifd_offset + 9 |
|
225 if tag == 0x100: |
|
226 self._width = struct.unpack( |
|
227 format, |
|
228 self._image_data[ifd_offset + 8:end_offset])[0] |
|
229 if self._height is not None: |
|
230 break |
|
231 else: |
|
232 self._height = struct.unpack( |
|
233 format, |
|
234 self._image_data[ifd_offset + 8:end_offset])[0] |
|
235 if self._width is not None: |
|
236 break |
|
237 ifd_offset += 12 |
|
238 else: |
|
239 raise BadImageError("Corrupt TIFF format") |
|
240 if self._width is None or self._height is None: |
|
241 raise BadImageError("Corrupt TIFF format") |
|
242 |
|
243 def _update_bmp_dimensions(self): |
|
244 """Updates the width and height fields of the bmp image. |
|
245 |
|
246 Raises: |
|
247 BadImageError if the image string is not a valid bmp image. |
|
248 """ |
|
249 size = len(self._image_data) |
|
250 if size >= 18: |
|
251 header_length = struct.unpack("<I", self._image_data[14:18])[0] |
|
252 if ((header_length == 40 or header_length == 108 or |
|
253 header_length == 124 or header_length == 64) and size >= 26): |
|
254 self._width, self._height = struct.unpack("<II", |
|
255 self._image_data[18:26]) |
|
256 elif header_length == 12 and size >= 22: |
|
257 self._width, self._height = struct.unpack("<HH", |
|
258 self._image_data[18:22]) |
|
259 else: |
|
260 raise BadImageError("Corrupt BMP format") |
|
261 else: |
|
262 raise BadImageError("Corrupt BMP format") |
|
263 |
|
264 def _update_ico_dimensions(self): |
|
265 """Updates the width and height fields of the ico image. |
|
266 |
|
267 Raises: |
|
268 BadImageError if the image string is not a valid ico image. |
|
269 """ |
|
270 size = len(self._image_data) |
|
271 if size >= 8: |
|
272 self._width, self._height = struct.unpack("<BB", self._image_data[6:8]) |
|
273 if not self._width: |
|
274 self._width = 256 |
|
275 if not self._height: |
|
276 self._height = 256 |
|
277 else: |
|
278 raise BadImageError("Corrupt ICO format") |
106 |
279 |
107 def resize(self, width=0, height=0): |
280 def resize(self, width=0, height=0): |
108 """Resize the image maintaining the aspect ratio. |
281 """Resize the image maintaining the aspect ratio. |
109 |
282 |
110 If both width and height are specified, the more restricting of the two |
283 If both width and height are specified, the more restricting of the two |