1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-19 17:49:47 +00:00
Pixelorama/addons/gdgifexporter/quantization/median_cut.gd
Manolis Papadeas c6b9a1fb82
Format code and add static checks (#599)
* gdformat .

* Lint code - Part 1

* Format code - Part 2

* Lint code - Part 2

Trying to fix the max allowed line length errors

* Add normal_map_invert_y to the image .import files

Because of Godot 3.4

* Do not call private methods outside of the script's scope

Lint code - Part 3

* Format code - Part 3

* Fixed more line length exceeded errors - Lint code Part 3

* Export array of licenses - Lint code part 4

* Clean hint_tooltip code from Global

Removes a lot of lines of code

* Create static-checks.yml

* Fix FreeType's license
2021-11-25 14:48:30 +02:00

164 lines
3.8 KiB
GDScript

extends Reference
var converter = preload("../converter.gd").new()
var transparency := false
func longest_axis(colors: Array) -> int:
var start := [255, 255, 255]
var end := [0, 0, 0]
for color in colors:
for i in 3:
start[i] = min(color[i], start[i])
end[i] = max(color[i], end[i])
var max_r = end[0] - start[0]
var max_g = end[1] - start[1]
var max_b = end[2] - start[2]
if max_r > max_g:
if max_r > max_b:
return 0
else:
if max_g > max_b:
return 1
return 2
func get_median(colors: Array) -> Vector3:
return colors[colors.size() >> 1]
func median_cut(colors: Array) -> Array:
var axis := longest_axis(colors)
var axis_sort := []
for color in colors:
axis_sort.append(color[axis])
axis_sort.sort()
var cut := axis_sort.size() >> 1
var median: int = axis_sort[cut]
axis_sort = []
var left_colors := []
var right_colors := []
for color in colors:
if color[axis] < median:
left_colors.append(color)
else:
right_colors.append(color)
return [left_colors, right_colors]
func average_color(bucket: Array) -> Array:
var r := 0
var g := 0
var b := 0
for color in bucket:
r += color[0]
g += color[1]
b += color[2]
return [r / bucket.size(), g / bucket.size(), b / bucket.size()]
func average_colors(buckets: Array) -> Dictionary:
var avg_colors := {}
for bucket in buckets:
if bucket.size() > 0:
avg_colors[average_color(bucket)] = avg_colors.size()
return avg_colors
func pixels_to_colors(image: Image) -> Array:
image.lock()
var result := []
var data: PoolByteArray = image.get_data()
for i in range(0, data.size(), 4):
if data[i + 3] == 0:
transparency = true
continue
result.append([data[i], data[i + 1], data[i + 2]])
image.unlock()
return result
func remove_smallest_bucket(buckets: Array) -> Array:
if buckets.size() == 0:
return buckets
var i_of_smallest_bucket := 0
for i in range(buckets.size()):
if buckets[i].size() < buckets[i_of_smallest_bucket].size():
i_of_smallest_bucket = i
buckets.remove(i_of_smallest_bucket)
return buckets
func remove_empty_buckets(buckets: Array) -> Array:
if buckets.size() == 0:
return buckets
var i := buckets.find([])
while i != -1:
buckets.remove(i)
i = buckets.find([])
return buckets
# quantizes to gif ready codes
func quantize(image: Image) -> Array:
var pixels = pixels_to_colors(image)
if pixels.size() == 0:
return pixels
var buckets := [pixels]
var done_buckets := []
# it tells how many times buckets should be divided into two
var dimensions := 8
for i in range(0, dimensions):
var new_buckets := []
for bucket in buckets:
# don't median cut if bucket is smaller than 2, because
# it won't produce two new buckets.
if bucket.size() > 1:
var res := median_cut(bucket)
# sometimes when you try to median cut a bucket, the result
# is one with size equal to 0 and other with full size as the
# source bucket. Because of that it's useless to try to divide
# it further so it's better to put it into separate list and
# process only those buckets witch divide further.
if res[0].size() == 0 or res[1].size() == 0:
done_buckets += res
else:
new_buckets += res
buckets = []
buckets = new_buckets
var all_buckets := remove_empty_buckets(done_buckets + buckets)
buckets = []
done_buckets = []
if transparency:
if all_buckets.size() == pow(2, dimensions):
all_buckets = remove_smallest_bucket(all_buckets)
# dictionaries are only for speed.
var color_array := average_colors(all_buckets).keys()
# if pixel_to_colors detected that the image has transparent pixels
# then add transparency color at the beginning so it will be properly
# exported.
if transparency:
color_array = [[0, 0, 0]] + color_array
var data: PoolByteArray = converter.get_similar_indexed_datas(image, color_array)
return [data, color_array, transparency]