Browse Source

Added helper to get image data without downloading the image

sh4nks 10 years ago
parent
commit
0011eecab9
2 changed files with 84 additions and 0 deletions
  1. 83 0
      flaskbb/utils/helpers.py
  2. 1 0
      requirements.txt

+ 83 - 0
flaskbb/utils/helpers.py

@@ -12,8 +12,11 @@ import re
 import time
 import itertools
 import operator
+import struct
+from io import BytesIO
 from datetime import datetime, timedelta
 
+import requests
 from flask import session, url_for
 from babel.dates import format_timedelta
 from flask_themes2 import render_theme_template
@@ -345,3 +348,83 @@ def format_quote(post):
                 format(post=post, profile_url=profile_url)
 
         return quote
+
+
+def get_image_info(url):
+    """Returns the content-type, image size (kb), height and width of a image
+    without fully downloading it. It will just download the first 1024 bytes.
+
+    LICENSE: New BSD License (taken from the start page of the repository)
+    https://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py
+    """
+    r = requests.get(url, stream=True)
+    image_size = r.headers.get("content-length")
+    image_size = float(image_size) / 1000  # in kilobyte
+
+    data = r.raw.read(1024)
+    size = len(data)
+    height = -1
+    width = -1
+    content_type = ''
+
+    #image_size     size = file.headers.get("content-length")
+    if size:
+        size = int(size)
+
+    # handle GIFs
+    if (size >= 10) and data[:6] in (b'GIF87a', b'GIF89a'):
+        # Check to see if content_type is correct
+        content_type = 'image/gif'
+        w, h = struct.unpack(b'<HH', data[6:10])
+        width = int(w)
+        height = int(h)
+
+    # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
+    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
+    # and finally the 4-byte width, height
+    elif ((size >= 24) and data.startswith(b'\211PNG\r\n\032\n')
+          and (data[12:16] == b'IHDR')):
+        content_type = 'image/png'
+        w, h = struct.unpack(b">LL", data[16:24])
+        width = int(w)
+        height = int(h)
+
+    # Maybe this is for an older PNG version.
+    elif (size >= 16) and data.startswith(b'\211PNG\r\n\032\n'):
+        # Check to see if we have the right content type
+        content_type = 'image/png'
+        w, h = struct.unpack(b">LL", data[8:16])
+        width = int(w)
+        height = int(h)
+
+    # handle JPEGs
+    elif (size >= 2) and data.startswith(b'\377\330'):
+        content_type = 'image/jpeg'
+        jpeg = BytesIO(data)
+        jpeg.read(2)
+        b = jpeg.read(1)
+        try:
+            while (b and ord(b) != 0xDA):
+
+                while (ord(b) != 0xFF):
+                    b = jpeg.read(1)
+
+                while (ord(b) == 0xFF):
+                    b = jpeg.read(1)
+
+                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
+                    jpeg.read(3)
+                    h, w = struct.unpack(b">HH", jpeg.read(4))
+                    break
+                else:
+                    jpeg.read(int(struct.unpack(b">H", jpeg.read(2))[0])-2)
+                b = jpeg.read(1)
+            width = int(w)
+            height = int(h)
+        except struct.error:
+            pass
+        except ValueError:
+            pass
+
+    return {"content-type": content_type, "size": image_size,
+            "width": width, "height": height}

+ 1 - 0
requirements.txt

@@ -34,6 +34,7 @@ Unidecode==0.4.17
 Werkzeug==0.9.6
 Whoosh==2.6.0
 WTForms==2.0.1
+requests==2.5.3
 https://github.com/sh4nks/flask-babelex/tarball/master#egg=Flask-BabelEx
 https://github.com/frol/postmarkup/tarball/master#egg=postmarkup
 https://github.com/jshipley/Flask-WhooshAlchemy/archive/master.zip#egg=Flask-Whooshalchemy