Merge pull request #3525 from radarhere/mimetype

Detect MIME types
This commit is contained in:
Hugo van Kemenade 2019-01-05 12:01:40 +02:00 committed by GitHub
commit 33d3bebb22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 29 additions and 7 deletions

BIN
Tests/images/balloon.jpf Normal file

Binary file not shown.

View File

@ -39,6 +39,12 @@ class TestFileJpeg2k(PillowTestCase):
self.assertEqual(im.mode, 'RGB')
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, 'JPEG2000')
self.assertEqual(im.get_format_mimetype(), 'image/jp2')
def test_jpf(self):
im = Image.open('Tests/images/balloon.jpf')
self.assertEqual(im.format, 'JPEG2000')
self.assertEqual(im.get_format_mimetype(), 'image/jpx')
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"

View File

@ -86,6 +86,7 @@ class TestFilePng(PillowTestCase):
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PNG")
self.assertEqual(im.get_format_mimetype(), 'image/png')
hopper("1").save(test_file)
Image.open(test_file)
@ -589,6 +590,8 @@ class TestFilePng(PillowTestCase):
"WebP support not installed with animation")
def test_apng(self):
im = Image.open("Tests/images/iss634.apng")
self.assertEqual(im.get_format_mimetype(), 'image/apng')
expected = Image.open("Tests/images/iss634.webp")
self.assert_image_similar(im, expected, 0.23)

View File

@ -12,6 +12,7 @@ class TestFileSgi(PillowTestCase):
im = Image.open(test_file)
self.assert_image_equal(im, hopper())
self.assertEqual(im.get_format_mimetype(), 'image/rgb')
def test_rgb16(self):
test_file = "Tests/images/hopper16.rgb"
@ -26,6 +27,7 @@ class TestFileSgi(PillowTestCase):
im = Image.open(test_file)
self.assert_image_similar(im, hopper('L'), 2)
self.assertEqual(im.get_format_mimetype(), 'image/sgi')
def test_rgba(self):
# Created with ImageMagick:
@ -35,6 +37,7 @@ class TestFileSgi(PillowTestCase):
im = Image.open(test_file)
target = Image.open('Tests/images/transparent.png')
self.assert_image_equal(im, target)
self.assertEqual(im.get_format_mimetype(), 'image/sgi')
def test_rle(self):
# Created with ImageMagick:

View File

@ -79,6 +79,8 @@ class ImageFile(Image.Image):
self._min_frame = 0
self.custom_mimetype = None
self.tile = None
self.readonly = 1 # until we know better
@ -120,7 +122,7 @@ class ImageFile(Image.Image):
def get_format_mimetype(self):
if self.format is None:
return
return Image.MIME.get(self.format.upper())
return self.custom_mimetype or Image.MIME.get(self.format.upper())
def verify(self):
"Check file integrity"

View File

@ -57,10 +57,11 @@ def _parse_codestream(fp):
def _parse_jp2_header(fp):
"""Parse the JP2 header box to extract size, component count and
color space information, returning a PIL (size, mode) tuple."""
color space information, returning a (size, mode, mimetype) tuple."""
# Find the JP2 header box
header = None
mimetype = None
while True:
lbox, tbox = struct.unpack('>I4s', fp.read(8))
if lbox == 1:
@ -75,6 +76,10 @@ def _parse_jp2_header(fp):
if tbox == b'jp2h':
header = fp.read(lbox - hlen)
break
elif tbox == b'ftyp':
if fp.read(4) == b'jpx ':
mimetype = 'image/jpx'
fp.seek(lbox - hlen - 4, os.SEEK_CUR)
else:
fp.seek(lbox - hlen, os.SEEK_CUR)
@ -145,7 +150,7 @@ def _parse_jp2_header(fp):
if size is None or mode is None:
raise SyntaxError("Malformed jp2 header")
return (size, mode)
return (size, mode, mimetype)
##
# Image plugin for JPEG2000 images.
@ -165,7 +170,8 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
if sig == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a':
self.codec = "jp2"
self._size, self.mode = _parse_jp2_header(self.fp)
header = _parse_jp2_header(self.fp)
self._size, self.mode, self.custom_mimetype = header
else:
raise SyntaxError('not a JPEG 2000 file')
@ -281,4 +287,3 @@ Image.register_extensions(Jpeg2KImageFile.format,
[".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"])
Image.register_mime(Jpeg2KImageFile.format, 'image/jp2')
Image.register_mime(Jpeg2KImageFile.format, 'image/jpx')

View File

@ -296,6 +296,7 @@ class PngStream(ChunkStream):
self.im_mode = None
self.im_tile = None
self.im_palette = None
self.im_custom_mimetype = None
self.text_memory = 0
@ -529,6 +530,7 @@ class PngStream(ChunkStream):
# APNG chunks
def chunk_acTL(self, pos, length):
s = ImageFile._safe_read(self.fp, length)
self.im_custom_mimetype = 'image/apng'
return s
def chunk_fcTL(self, pos, length):
@ -594,6 +596,7 @@ class PngImageFile(ImageFile.ImageFile):
self.info = self.png.im_info
self._text = None
self.tile = self.png.im_tile
self.custom_mimetype = self.png.im_custom_mimetype
if self.png.im_palette:
rawmode, data = self.png.im_palette
@ -908,4 +911,3 @@ Image.register_save(PngImageFile.format, _save)
Image.register_extensions(PngImageFile.format, [".png", ".apng"])
Image.register_mime(PngImageFile.format, "image/png")
Image.register_mime(PngImageFile.format, "image/apng")

View File

@ -98,6 +98,8 @@ class SgiImageFile(ImageFile.ImageFile):
self._size = xsize, ysize
self.mode = rawmode.split(";")[0]
if self.mode == 'RGB':
self.custom_mimetype = 'image/rgb'
# orientation -1 : scanlines begins at the bottom-left corner
orientation = -1
@ -220,7 +222,6 @@ Image.register_decoder("SGI16", SGI16Decoder)
Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
Image.register_save(SgiImageFile.format, _save)
Image.register_mime(SgiImageFile.format, "image/sgi")
Image.register_mime(SgiImageFile.format, "image/rgb")
Image.register_extensions(SgiImageFile.format,
[".bw", ".rgb", ".rgba", ".sgi"])