Skip to content

Commit dc604cf

Browse files
committed
Add HEIF file support for MacOS. libheif is required.
1 parent 41e0253 commit dc604cf

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

duplicate_finder.py

100644100755
Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from tempfile import TemporaryDirectory
3939
import webbrowser
4040

41-
from flask import Flask
41+
from flask import Flask, Response
4242
from flask_cors import CORS
4343
import imagehash
4444
from jinja2 import FileSystemLoader, Environment
@@ -47,6 +47,8 @@
4747
import pymongo
4848
from termcolor import cprint
4949
import pybktree
50+
import io
51+
import pyheif
5052

5153
@contextmanager
5254
def connect_to_db(db_conn_string='./db'):
@@ -101,7 +103,7 @@ def get_image_files(path):
101103
def is_image(file_name):
102104
# List mime types fully supported by Pillow
103105
full_supported_formats = ['gif', 'jp2', 'jpeg', 'pcx', 'png', 'tiff', 'x-ms-bmp',
104-
'x-portable-pixmap', 'x-xbitmap']
106+
'x-portable-pixmap', 'x-xbitmap', 'heic']
105107
try:
106108
mime = magic.from_file(file_name, mime=True)
107109
return mime.rsplit('/', 1)[1] in full_supported_formats
@@ -115,25 +117,35 @@ def is_image(file_name):
115117
if is_image(file):
116118
yield file
117119

120+
def hash_image(img):
121+
image_size = get_image_size(img)
122+
capture_time = get_capture_time(img)
123+
124+
hashes = []
125+
# hash the image 4 times and rotate it by 90 degrees each time
126+
for angle in [ 0, 90, 180, 270 ]:
127+
if angle > 0:
128+
turned_img = img.rotate(angle, expand=True)
129+
else:
130+
turned_img = img
131+
hashes.append(str(imagehash.phash(turned_img)))
132+
133+
hashes = ''.join(sorted(hashes))
134+
return hashes, image_size, capture_time
118135

119136
def hash_file(file):
120137
try:
121-
hashes = []
122-
img = Image.open(file)
138+
mime = magic.from_file(file, mime=True)
139+
if mime.rsplit('/', 1)[1] == 'heic':
140+
heif = pyheif.read_heif(open(file, 'rb'))
141+
img = Image.frombytes(
142+
mode=heif.mode, size=heif.size, data=heif.data)
143+
else:
144+
img = Image.open(file)
123145

124146
file_size = get_file_size(file)
125-
image_size = get_image_size(img)
126-
capture_time = get_capture_time(img)
127147

128-
# hash the image 4 times and rotate it by 90 degrees each time
129-
for angle in [ 0, 90, 180, 270 ]:
130-
if angle > 0:
131-
turned_img = img.rotate(angle, expand=True)
132-
else:
133-
turned_img = img
134-
hashes.append(str(imagehash.phash(turned_img)))
135-
136-
hashes = ''.join(sorted(hashes))
148+
hashes, image_size, capture_time = hash_image(img)
137149

138150
cprint("\tHashed {}".format(file), "blue")
139151
return file, hashes, file_size, image_size, capture_time
@@ -346,6 +358,16 @@ def render(duplicates, current, total):
346358
def delete_picture_(file_name, trash=trash):
347359
return str(delete_picture(file_name, db, trash))
348360

361+
@app.route('/heic-transform/<everything:file_name>', methods=['GET'])
362+
def transcode_heic_(file_name):
363+
heif_image = pyheif.read_heif(open(file_name, 'rb'))
364+
365+
image = Image.frombytes(
366+
mode=heif_image.mode, size=heif_image.size, data=heif_image.data)
367+
encoded = io.BytesIO()
368+
image.save(encoded, format='JPEG')
369+
return Response(encoded.getvalue(), mimetype='image/jpeg')
370+
349371
app.run()
350372

351373

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ termcolor==1.1.0
1010
Werkzeug==0.14.1
1111
Flask-Cors==3.0.3
1212
dnspython>=1.15.0
13-
pybktree==1.1
13+
pybktree==1.1
14+
pyheif==0.3.3

template/index.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@
1010
{% macro image(img, size) -%}
1111
<div class="col-xs-{{ size }}">
1212
<div class="thumbnail">
13-
<a href="{{ img['file_name'] }}" target='_blank'>
14-
<img class="img-responsive" src="{{ img['file_name'] }}" alt="{{ img['file_name'] }}">
15-
</a>
13+
{% if '.heic' in img['file_name'] %}
14+
<a href="http://127.0.0.1:5000/heic-transform/{{ img['file_name'] }}" target='_blank'>
15+
<img class="img-responsive" src="http://127.0.0.1:5000/heic-transform/{{ img['file_name'] }}" alt="{{ img['file_name'] }}">
16+
</a>
17+
{% else %}
18+
<a href="{{ img['file_name'] }}" target='_blank'>
19+
<img class="img-responsive" src="{{ img['file_name'] }}" alt="{{ img['file_name'] }}">
20+
</a>
21+
{% endif %}
1622
<div class="caption">
1723
<h5 class="name">{{ img['file_name'] }}</h5>
1824
<div class="file-size">{{ img['file_size'] | filesizeformat }}</div>

0 commit comments

Comments
 (0)