|
@@ -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}
|