Voici ma solution, elle est assez simple puisque tout ce qui m'intéresse n'est pas nécessairement le GCD ou même des ratios précis : parce qu'alors vous obtenez des choses bizarres comme 345/113 qui ne sont pas compréhensibles pour l'homme.
En gros, je définis des ratios acceptables pour le paysage ou le portrait et leur "valeur" en tant que valeur flottante... Je compare ensuite ma version flottante du ratio à chacun d'eux et celui qui présente la plus petite différence de valeur absolue est le ratio le plus proche de l'article. De cette façon, lorsque l'utilisateur rend l'image 16:9 mais enlève ensuite 10 pixels du bas, l'image est toujours considérée comme 16:9...
accepted_ratios = {
'landscape': (
(u'5:4', 1.25),
(u'4:3', 1.33333333333),
(u'3:2', 1.5),
(u'16:10', 1.6),
(u'5:3', 1.66666666667),
(u'16:9', 1.77777777778),
(u'17:9', 1.88888888889),
(u'21:9', 2.33333333333),
(u'1:1', 1.0)
),
'portrait': (
(u'4:5', 0.8),
(u'3:4', 0.75),
(u'2:3', 0.66666666667),
(u'10:16', 0.625),
(u'3:5', 0.6),
(u'9:16', 0.5625),
(u'9:17', 0.5294117647),
(u'9:21', 0.4285714286),
(u'1:1', 1.0)
),
}
def find_closest_ratio(ratio):
lowest_diff, best_std = 9999999999, '1:1'
layout = 'portrait' if ratio < 1.0 else 'landscape'
for pretty_str, std_ratio in accepted_ratios[layout]:
diff = abs(std_ratio - ratio)
if diff < lowest_diff:
lowest_diff = diff
best_std = pretty_str
return best_std
def extract_ratio(width, height):
try:
divided = float(width)/float(height)
if divided == 1.0: return '1:1'
return find_closest_ratio(divided)
except TypeError:
return None