diff --git a/addons/gdgifexporter/LICENSE b/addons/gdgifexporter/LICENSE deleted file mode 100644 index ca5b2ad..0000000 --- a/addons/gdgifexporter/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Igor Santarek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/addons/gdgifexporter/converter.gd b/addons/gdgifexporter/converter.gd deleted file mode 100644 index c9f7d2f..0000000 --- a/addons/gdgifexporter/converter.gd +++ /dev/null @@ -1,58 +0,0 @@ -extends Reference - - -var _shader: Shader - - -func get_indexed_datas(image: Image, colors: Array) -> PoolByteArray: - _shader = preload("./lookup_color.shader") - return _convert(image, colors) - - -func get_similar_indexed_datas(image: Image, colors: Array) -> PoolByteArray: - _shader = preload("./lookup_similar.shader") - return _convert(image, colors) - - -func _convert(image: Image, colors: Array) -> PoolByteArray: - var vp = VisualServer.viewport_create() - var canvas = VisualServer.canvas_create() - VisualServer.viewport_attach_canvas(vp, canvas) - VisualServer.viewport_set_size(vp, image.get_width(), image.get_height()) - VisualServer.viewport_set_disable_3d(vp, true) - VisualServer.viewport_set_usage(vp, VisualServer.VIEWPORT_USAGE_2D) - VisualServer.viewport_set_hdr(vp, true) - VisualServer.viewport_set_active(vp, true) - - var ci_rid = VisualServer.canvas_item_create() - VisualServer.viewport_set_canvas_transform(vp, canvas, Transform()) - VisualServer.canvas_item_set_parent(ci_rid, canvas) - var texture = ImageTexture.new() - texture.create_from_image(image) - VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(Vector2(0, 0), image.get_size()), texture) - - var mat_rid = VisualServer.material_create() - VisualServer.material_set_shader(mat_rid, _shader.get_rid()) - var lut = Image.new() - lut.create(256, 1, false, Image.FORMAT_RGB8) - lut.fill(Color8(colors[0][0], colors[0][1], colors[0][2])) - lut.lock() - for i in colors.size(): - lut.set_pixel(i, 0, Color8(colors[i][0], colors[i][1], colors[i][2])) - var lut_tex = ImageTexture.new() - lut_tex.create_from_image(lut) - VisualServer.material_set_param(mat_rid, "lut", lut_tex) - VisualServer.canvas_item_set_material(ci_rid, mat_rid) - - VisualServer.viewport_set_update_mode(vp, VisualServer.VIEWPORT_UPDATE_ONCE) - VisualServer.viewport_set_vflip(vp, true) - VisualServer.force_draw(false) - image = VisualServer.texture_get_data(VisualServer.viewport_get_texture(vp)) - - VisualServer.free_rid(vp) - VisualServer.free_rid(canvas) - VisualServer.free_rid(ci_rid) - VisualServer.free_rid(mat_rid) - - image.convert(Image.FORMAT_R8) - return image.get_data() diff --git a/addons/gdgifexporter/gif-lzw/LICENSE b/addons/gdgifexporter/gif-lzw/LICENSE deleted file mode 100644 index ca5b2ad..0000000 --- a/addons/gdgifexporter/gif-lzw/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Igor Santarek - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/addons/gdgifexporter/gif-lzw/lsbbitpacker.gd b/addons/gdgifexporter/gif-lzw/lsbbitpacker.gd deleted file mode 100644 index 8fe3ac4..0000000 --- a/addons/gdgifexporter/gif-lzw/lsbbitpacker.gd +++ /dev/null @@ -1,31 +0,0 @@ -extends Reference - - -class LSB_LZWBitPacker: - var bit_index: int = 0 - var stream: int = 0 - - var chunks: PoolByteArray = PoolByteArray([]) - - func put_byte(): - chunks.append(stream & 0xff) - bit_index -= 8 - stream >>= 8 - - func write_bits(value: int, bits_count: int) -> void: - value &= (1 << bits_count) - 1 - value <<= bit_index - stream |= value - bit_index += bits_count - while bit_index >= 8: - self.put_byte() - - func pack() -> PoolByteArray: - if bit_index != 0: - self.put_byte() - return chunks - - func reset() -> void: - bit_index = 0 - stream = 0 - chunks = PoolByteArray([]) diff --git a/addons/gdgifexporter/gif-lzw/lsbbitunpacker.gd b/addons/gdgifexporter/gif-lzw/lsbbitunpacker.gd deleted file mode 100644 index be8e9d6..0000000 --- a/addons/gdgifexporter/gif-lzw/lsbbitunpacker.gd +++ /dev/null @@ -1,41 +0,0 @@ -extends Reference - - -class LSB_LZWBitUnpacker: - var chunk_stream: PoolByteArray - var bit_index: int = 0 - var byte: int - var byte_index: int = 0 - - func _init(_chunk_stream: PoolByteArray): - chunk_stream = _chunk_stream - self.get_byte() - - func get_bit(value: int, index: int) -> int: - return (value >> index) & 1 - - func set_bit(value: int, index: int) -> int: - return value | (1 << index) - - func get_byte(): - byte = chunk_stream[byte_index] - byte_index += 1 - bit_index = 0 - - func read_bits(bits_count: int) -> int: - var result: int = 0 - var result_bit_index: int = 0 - - for _i in range(bits_count): - if self.get_bit(byte, bit_index) == 1: - result = self.set_bit(result, result_bit_index) - result_bit_index += 1 - bit_index += 1 - - if bit_index == 8: - self.get_byte() - - return result - - func remove_bits(bits_count: int) -> void: - self.read_bits(bits_count) diff --git a/addons/gdgifexporter/gif-lzw/lzw.gd b/addons/gdgifexporter/gif-lzw/lzw.gd deleted file mode 100644 index 6cfd6f3..0000000 --- a/addons/gdgifexporter/gif-lzw/lzw.gd +++ /dev/null @@ -1,202 +0,0 @@ -extends Reference - - -var lsbbitpacker = preload('./lsbbitpacker.gd') -var lsbbitunpacker = preload('./lsbbitunpacker.gd') - -class CodeEntry: - var sequence: PoolByteArray - var raw_array: Array - - func _init(_sequence): - raw_array = _sequence - sequence = _sequence - - func add(other): - return CodeEntry.new(self.raw_array + other.raw_array) - - func to_string(): - var result: String = '' - for element in self.sequence: - result += str(element) + ', ' - return result.substr(0, result.length() - 2) - -class CodeTable: - var entries: Dictionary = {} - var counter: int = 0 - var lookup: Dictionary = {} - - func add(entry) -> int: - self.entries[self.counter] = entry - self.lookup[entry.raw_array] = self.counter - counter += 1 - return counter - - func find(entry) -> int: - return self.lookup.get(entry.raw_array, -1) - - func has(entry) -> bool: - return self.find(entry) != -1 - - func get(index) -> CodeEntry: - return self.entries.get(index, null) - - func to_string() -> String: - var result: String = 'CodeTable:\n' - for id in self.entries: - result += str(id) + ': ' + self.entries[id].to_string() + '\n' - result += 'Counter: ' + str(self.counter) + '\n' - return result - -func log2(value: float) -> float: - return log(value) / log(2.0) - -func get_bits_number_for(value: int) -> int: - if value == 0: - return 1 - return int(ceil(log2(value + 1))) - -func initialize_color_code_table(colors: PoolByteArray) -> CodeTable: - var result_code_table: CodeTable = CodeTable.new() - for color_id in colors: - # warning-ignore:return_value_discarded - result_code_table.add(CodeEntry.new([color_id])) - # move counter to the first available compression code index - var last_color_index: int = colors.size() - 1 - var clear_code_index: int = pow(2, get_bits_number_for(last_color_index)) - result_code_table.counter = clear_code_index + 2 - return result_code_table - -# compression and decompression done with source: -# http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp - -func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array: - # Initialize code table - var code_table: CodeTable = initialize_color_code_table(colors) - # Clear Code index is 2** - # is the amount of bits needed to write down all colors - # from color table. We use last color index because we can write - # all colors (for example 16 colors) with indexes from 0 to 15. - # Number 15 is in binary 0b1111, so we'll need 4 bits to write all - # colors down. - var last_color_index: int = colors.size() - 1 - var clear_code_index: int = pow(2, get_bits_number_for(last_color_index)) - var index_stream: PoolByteArray = image - var current_code_size: int = get_bits_number_for(clear_code_index) - var binary_code_stream = lsbbitpacker.LSB_LZWBitPacker.new() - - # initialize with Clear Code - binary_code_stream.write_bits(clear_code_index, current_code_size) - - # Read first index from index stream. - var index_buffer: CodeEntry = CodeEntry.new([index_stream[0]]) - var data_index: int = 1 - # - while data_index < index_stream.size(): - # Get the next index from the index stream. - var K: CodeEntry = CodeEntry.new([index_stream[data_index]]) - data_index += 1 - # Is index buffer + K in our code table? - var new_index_buffer: CodeEntry = index_buffer.add(K) - if code_table.has(new_index_buffer): # if YES - # Add K to the end of the index buffer - index_buffer = new_index_buffer - else: # if NO - # Add a row for index buffer + K into our code table - binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) - - # We don't want to add new code to code table if we've exceeded 4095 - # index. - var last_entry_index: int = code_table.counter - 1 - if last_entry_index != 4095: - # Output the code for just the index buffer to our code stream - # warning-ignore:return_value_discarded - code_table.add(new_index_buffer) - else: - # if we exceeded 4095 index (code table is full), we should - # output Clear Code and reset everything. - binary_code_stream.write_bits(clear_code_index, current_code_size) - code_table = initialize_color_code_table(colors) - # get_bits_number_for(clear_code_index) is the same as - # LZW code size + 1 - current_code_size = get_bits_number_for(clear_code_index) - - # Detect when you have to save new codes in bigger bits boxes - # change current code size when it happens because we want to save - # flexible code sized codes - var new_code_size_candidate: int = get_bits_number_for(code_table.counter - 1) - if new_code_size_candidate > current_code_size: - current_code_size = new_code_size_candidate - - # Index buffer is set to K - index_buffer = K - # Output code for contents of index buffer - binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) - - # output end with End Of Information Code - binary_code_stream.write_bits(clear_code_index + 1, current_code_size) - - var min_code_size: int = get_bits_number_for(clear_code_index) - 1 - - return [binary_code_stream.pack(), min_code_size] - -func decompress_lzw(code_stream_data: PoolByteArray, min_code_size: int, colors: PoolByteArray) -> PoolByteArray: - var code_table: CodeTable = initialize_color_code_table(colors) - var index_stream: PoolByteArray = PoolByteArray([]) - var binary_code_stream = lsbbitunpacker.LSB_LZWBitUnpacker.new(code_stream_data) - var current_code_size: int = min_code_size + 1 - var clear_code_index: int = pow(2, min_code_size) - - # CODE is an index of code table, {CODE} is sequence inside - # code table with index CODE. The same goes for PREVCODE. - - # Remove first Clear Code from stream. We don't need it. - binary_code_stream.remove_bits(current_code_size) - - # let CODE be the first code in the code stream - var code: int = binary_code_stream.read_bits(current_code_size) - # output {CODE} to index stream - index_stream.append_array(code_table.get(code).sequence) - # set PREVCODE = CODE - var prevcode: int = code - # - while true: - # let CODE be the next code in the code stream - code = binary_code_stream.read_bits(current_code_size) - # Detect Clear Code. When detected reset everything and get next code. - if code == clear_code_index: - code_table = initialize_color_code_table(colors) - current_code_size = min_code_size + 1 - code = binary_code_stream.read_bits(current_code_size) - elif code == clear_code_index + 1: # Stop when detected EOI Code. - break - # is CODE in the code table? - var code_entry: CodeEntry = code_table.get(code) - if code_entry != null: # if YES - # output {CODE} to index stream - index_stream.append_array(code_entry.sequence) - # let K be the first index in {CODE} - var K: CodeEntry = CodeEntry.new([code_entry.sequence[0]]) - # warning-ignore:return_value_discarded - # add {PREVCODE} + K to the code table - code_table.add(code_table.get(prevcode).add(K)) - # set PREVCODE = CODE - prevcode = code - else: # if NO - # let K be the first index of {PREVCODE} - var prevcode_entry: CodeEntry = code_table.get(prevcode) - var K: CodeEntry = CodeEntry.new([prevcode_entry.sequence[0]]) - # output {PREVCODE} + K to index stream - index_stream.append_array(prevcode_entry.add(K).sequence) - # add {PREVCODE} + K to code table - # warning-ignore:return_value_discarded - code_table.add(prevcode_entry.add(K)) - # set PREVCODE = CODE - prevcode = code - - # Detect when we should increase current code size and increase it. - var new_code_size_candidate: int = get_bits_number_for(code_table.counter) - if new_code_size_candidate > current_code_size: - current_code_size = new_code_size_candidate - - return index_stream diff --git a/addons/gdgifexporter/gifexporter.gd b/addons/gdgifexporter/gifexporter.gd deleted file mode 100644 index 426d8f3..0000000 --- a/addons/gdgifexporter/gifexporter.gd +++ /dev/null @@ -1,392 +0,0 @@ -extends Reference - - -var little_endian = preload('./little_endian.gd').new() -var lzw = preload('./gif-lzw/lzw.gd').new() -var used_proc_count: int = 4 - - -class GraphicControlExtension: - var extension_introducer: int = 0x21 - var graphic_control_label: int = 0xf9 - - var block_size: int = 4 - var packed_fields: int = 0b00001000 - var delay_time: int = 0 - var transparent_color_index: int = 0 - - func _init(_delay_time: int, - use_transparency: bool = false, - _transparent_color_index: int = 0): - delay_time = _delay_time - transparent_color_index = _transparent_color_index - if use_transparency: - packed_fields = 0b00001001 - - func to_bytes() -> PoolByteArray: - var little_endian = preload('./little_endian.gd').new() - var result: PoolByteArray = PoolByteArray([]) - - result.append(extension_introducer) - result.append(graphic_control_label) - - result.append(block_size) - result.append(packed_fields) - result += little_endian.int_to_2bytes(delay_time) - result.append(transparent_color_index) - - result.append(0) - - return result - -class ImageDescriptor: - var image_separator: int = 0x2c - var image_left_position: int = 0 - var image_top_position: int = 0 - var image_width: int - var image_height: int - var packed_fields: int = 0b10000000 - - func _init(_image_left_position: int, - _image_top_position: int, - _image_width: int, - _image_height: int, - size_of_local_color_table: int): - image_left_position = _image_left_position - image_top_position = _image_top_position - image_width = _image_width - image_height = _image_height - packed_fields = packed_fields | (0b111 & size_of_local_color_table) - - func to_bytes() -> PoolByteArray: - var little_endian = preload('./little_endian.gd').new() - var result: PoolByteArray = PoolByteArray([]) - - result.append(image_separator) - result += little_endian.int_to_2bytes(image_left_position) - result += little_endian.int_to_2bytes(image_top_position) - result += little_endian.int_to_2bytes(image_width) - result += little_endian.int_to_2bytes(image_height) - result.append(packed_fields) - - return result - -class LocalColorTable: - var colors: Array = [] - - func log2(value: float) -> float: - return log(value) / log(2.0) - - func get_size() -> int: - if colors.size() <= 1: - return 0 - return int(ceil(log2(colors.size()) - 1)) - - func to_bytes() -> PoolByteArray: - var result: PoolByteArray = PoolByteArray([]) - - for v in colors: - result.append(v[0]) - result.append(v[1]) - result.append(v[2]) - - if colors.size() != int(pow(2, get_size() + 1)): - for i in range(int(pow(2, get_size() + 1)) - colors.size()): - result += PoolByteArray([0, 0, 0]) - - return result - -class ApplicationExtension: - var extension_introducer: int = 0x21 - var extension_label: int = 0xff - - var block_size: int = 11 - var application_identifier: PoolByteArray - var appl_authentication_code: PoolByteArray - - var application_data: PoolByteArray - - func _init(_application_identifier: String, - _appl_authentication_code: String): - application_identifier = _application_identifier.to_ascii() - appl_authentication_code = _appl_authentication_code.to_ascii() - - func to_bytes() -> PoolByteArray: - var result: PoolByteArray = PoolByteArray([]) - - result.append(extension_introducer) - result.append(extension_label) - result.append(block_size) - result += application_identifier - result += appl_authentication_code - - result.append(application_data.size()) - result += application_data - - result.append(0) - - return result - -class ImageData: - var lzw_minimum_code_size: int - var image_data: PoolByteArray - - func to_bytes() -> PoolByteArray: - var result: PoolByteArray = PoolByteArray([]) - result.append(lzw_minimum_code_size) - - var block_size_index: int = 0 - var i: int = 0 - var data_index: int = 0 - while data_index < image_data.size(): - if i == 0: - result.append(0) - block_size_index = result.size() - 1 - result.append(image_data[data_index]) - result[block_size_index] += 1 - data_index += 1 - i += 1 - if i == 254: - i = 0 - - if not image_data.empty(): - result.append(0) - - return result - -class ConvertedImage: - var image_converted_to_codes: PoolByteArray - var color_table: Array - var transparency_color_index: int - var width: int - var height: int - -class ConvertionResult: - var converted_image: ConvertedImage = ConvertedImage.new() - var error: int = Error.OK - - func with_error_code(_error: int) -> ConvertionResult: - error = _error - return self - -class ThreadWriteFrameResult: - var frame_data: PoolByteArray = PoolByteArray([]) - var error: int = Error.OK - - func with_error_code(_error: int) -> ThreadWriteFrameResult: - error = _error - return self - -enum Error { - OK = 0, - EMPTY_IMAGE = 1, - BAD_IMAGE_FORMAT = 2 -} - -# File data and Header -var data: PoolByteArray = 'GIF'.to_ascii() + '89a'.to_ascii() - -func _init(_width: int, _height: int): - # Logical Screen Descriptor - var width: int = _width - var height: int = _height - # not Global Color Table Flag - # Color Resolution = 8 bits - # Sort Flag = 0, not sorted. - # Size of Global Color Table set to 0 - # because we'll use only Local Tables - var packed_fields: int = 0b01110000 - var background_color_index: int = 0 - var pixel_aspect_ratio: int = 0 - - data += little_endian.int_to_2bytes(width) - data += little_endian.int_to_2bytes(height) - data.append(packed_fields) - data.append(background_color_index) - data.append(pixel_aspect_ratio) - - var application_extension: ApplicationExtension = ApplicationExtension.new( - "NETSCAPE", - "2.0") - application_extension.application_data = PoolByteArray([1, 0, 0]) - data += application_extension.to_bytes() - -func calc_delay_time(frame_delay: float) -> int: - return int(ceil(frame_delay / 0.01)) - -func color_table_to_indexes(colors: Array) -> PoolByteArray: - var result: PoolByteArray = PoolByteArray([]) - for i in range(colors.size()): - result.append(i) - return result - -func find_color_table_if_has_less_than_256_colors(image: Image) -> Dictionary: - image.lock() - var result: Dictionary = {} - var image_data: PoolByteArray = image.get_data() - - for i in range(0, image_data.size(), 4): - var color: Array = [int(image_data[i]), int(image_data[i + 1]), int(image_data[i + 2]), int(image_data[i + 3])] - if not color in result: - result[color] = result.size() - if result.size() > 256: - break - - image.unlock() - return result - -func change_colors_to_codes(image: Image, - color_palette: Dictionary, - transparency_color_index: int) -> PoolByteArray: - image.lock() - var image_data: PoolByteArray = image.get_data() - var result: PoolByteArray = PoolByteArray([]) - - for i in range(0, image_data.size(), 4): - var color: Array = [int(image_data[i]), int(image_data[i + 1]), int(image_data[i + 2]), int(image_data[i + 3])] - if color in color_palette: - if color[3] == 0 and transparency_color_index != -1: - result.append(transparency_color_index) - else: - result.append(color_palette[color]) - else: - result.append(0) - push_warning('change_colors_to_codes: color not found! [%d, %d, %d, %d]' % color) - - image.unlock() - return result - -func sum_color(color: Array) -> int: - return color[0] + color[1] + color[2] + color[3] - -func find_transparency_color_index(color_table: Dictionary) -> int: - for color in color_table: - if sum_color(color) == 0: - return color_table[color] - return -1 - -func find_transparency_color_index_for_quantized_image(color_table: Array) -> int: - for i in range(color_table.size()): - if sum_color(color_table[i]) == 0: - return i - return -1 - -func make_sure_color_table_is_at_least_size_4(color_table: Array) -> Array: - var result := [] + color_table - if color_table.size() < 4: - for i in range(4 - color_table.size()): - result.append([0, 0, 0, 0]) - return result - -func convert_image(image: Image, quantizator) -> ConvertionResult: - var result := ConvertionResult.new() - - # check if image is of good format - if image.get_format() != Image.FORMAT_RGBA8: - return result.with_error_code(Error.BAD_IMAGE_FORMAT) - - # check if image isn't empty - if image.is_empty(): - return result.with_error_code(Error.EMPTY_IMAGE) - - var found_color_table: Dictionary = find_color_table_if_has_less_than_256_colors( - image) - - var image_converted_to_codes: PoolByteArray - var transparency_color_index: int = -1 - var color_table: Array - if found_color_table.size() <= 256: # we don't need to quantize the image. - # exporter images always try to include transparency because I'm lazy. - transparency_color_index = find_transparency_color_index(found_color_table) - if transparency_color_index == -1 and found_color_table.size() <= 255: - found_color_table[[0, 0, 0, 0]] = found_color_table.size() - transparency_color_index = found_color_table.size() - 1 - image_converted_to_codes = change_colors_to_codes( - image, found_color_table, transparency_color_index) - color_table = make_sure_color_table_is_at_least_size_4(found_color_table.keys()) - else: # we have to quantize the image. - var quantization_result: Array = quantizator.quantize_and_convert_to_codes(image) - image_converted_to_codes = quantization_result[0] - color_table = quantization_result[1] - # don't find transparency index if the quantization algorithm - # provides it as third return value - if quantization_result.size() == 3: - transparency_color_index = 0 if quantization_result[2] else -1 - else: - transparency_color_index = find_transparency_color_index_for_quantized_image(quantization_result[1]) - - result.converted_image.image_converted_to_codes = image_converted_to_codes - result.converted_image.color_table = color_table - result.converted_image.transparency_color_index = transparency_color_index - result.converted_image.width = image.get_width() - result.converted_image.height = image.get_height() - - return result.with_error_code(Error.OK) - -func write_frame(image: Image, frame_delay: float, quantizator) -> int: - var converted_image_result := convert_image(image, quantizator) - if converted_image_result.error != Error.OK: - return converted_image_result.error - - var converted_image := converted_image_result.converted_image - return write_frame_from_conv_image(converted_image, frame_delay) - -func write_frame_from_conv_image(converted_image: ConvertedImage, - frame_delay: float) -> int: - var delay_time := calc_delay_time(frame_delay) - - var color_table_indexes = color_table_to_indexes(converted_image.color_table) - var compressed_image_result: Array = lzw.compress_lzw( - converted_image.image_converted_to_codes, color_table_indexes) - var compressed_image_data: PoolByteArray = compressed_image_result[0] - var lzw_min_code_size: int = compressed_image_result[1] - - var table_image_data_block: ImageData = ImageData.new() - table_image_data_block.lzw_minimum_code_size = lzw_min_code_size - table_image_data_block.image_data = compressed_image_data - - var local_color_table: LocalColorTable = LocalColorTable.new() - local_color_table.colors = converted_image.color_table - - var image_descriptor: ImageDescriptor = ImageDescriptor.new(0, 0, - converted_image.width, - converted_image.height, - local_color_table.get_size()) - - var graphic_control_extension: GraphicControlExtension - if converted_image.transparency_color_index != -1: - graphic_control_extension = GraphicControlExtension.new( - delay_time, true, converted_image.transparency_color_index) - else: - graphic_control_extension = GraphicControlExtension.new( - delay_time, false, 0) - - data += graphic_control_extension.to_bytes() - data += image_descriptor.to_bytes() - data += local_color_table.to_bytes() - data += table_image_data_block.to_bytes() - - return Error.OK - -func scale_conv_image(converted_image: ConvertedImage, scale_factor: int) -> ConvertedImage: - var result = ConvertedImage.new() - - result.image_converted_to_codes = PoolByteArray([]) - result.color_table = converted_image.color_table.duplicate() - result.transparency_color_index = converted_image.transparency_color_index - result.width = converted_image.width * scale_factor - result.height = converted_image.height * scale_factor - - for y in range(converted_image.height): - var row := PoolByteArray([]) - for x in range(converted_image.width): - for i in range(scale_factor): - row.append(converted_image.image_converted_to_codes[(y * converted_image.width) + x]) - for i in range(scale_factor): - result.image_converted_to_codes += row - row = PoolByteArray([]) - - return result - -func export_file_data() -> PoolByteArray: - return data + PoolByteArray([0x3b]) diff --git a/addons/gdgifexporter/little_endian.gd b/addons/gdgifexporter/little_endian.gd deleted file mode 100644 index cb865e1..0000000 --- a/addons/gdgifexporter/little_endian.gd +++ /dev/null @@ -1,5 +0,0 @@ -extends Reference - - -func int_to_2bytes(value: int) -> PoolByteArray: - return PoolByteArray([value & 255, (value >> 8) & 255]) diff --git a/addons/gdgifexporter/lookup_color.shader b/addons/gdgifexporter/lookup_color.shader deleted file mode 100644 index 8379108..0000000 --- a/addons/gdgifexporter/lookup_color.shader +++ /dev/null @@ -1,19 +0,0 @@ -shader_type canvas_item; -render_mode unshaded; - -uniform sampler2D lut; - -void fragment() { - vec4 color = texture(TEXTURE, UV); - float index = 0.0; - if (color.a > 0.0) { - for (int i = 0; i < 256; i++) { - vec4 c = texture(lut, vec2((float(i) + 0.5) / 256.0, 0.5)); - if (c.rgb == color.rgb) { - index = float(i) / 255.0; - break; - } - } - } - COLOR = vec4(vec3(index), 1.0); -} \ No newline at end of file diff --git a/addons/gdgifexporter/lookup_similar.shader b/addons/gdgifexporter/lookup_similar.shader deleted file mode 100644 index 0614661..0000000 --- a/addons/gdgifexporter/lookup_similar.shader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; -render_mode unshaded; - -uniform sampler2D lut; - -void fragment() { - vec4 color = texture(TEXTURE, UV); - vec4 similar = texture(lut, vec2(0.5 / 256.0, 0.5)); - float index = 0.0; - if (color.a > 0.0) { - float dist = distance(color.xyz, similar.xyz); - for (int i = 1; i < 256; i++) { - vec4 c = texture(lut, vec2((float(i) + 0.5) / 256.0, 0.5)); - float d = distance(color.xyz, c.xyz); - if (d < dist) { - dist = d; - index = float(i) / 255.0; - } - } - } - COLOR = vec4(vec3(index), 1.0); -} \ No newline at end of file diff --git a/addons/gdgifexporter/quantization/median_cut.gd b/addons/gdgifexporter/quantization/median_cut.gd deleted file mode 100644 index ba81994..0000000 --- a/addons/gdgifexporter/quantization/median_cut.gd +++ /dev/null @@ -1,148 +0,0 @@ -extends Reference - - -var converter = preload('../converter.gd').new() -var color_table: Dictionary = {} -var transparency: bool = false -var tree: TreeNode -var leaf: Array = [] - - -class TreeNode: - var colors: Array - var average_color: Array - var axis: int - var median: int - var parent: TreeNode - var left: TreeNode - var right: TreeNode - - - func _init(_parent: TreeNode, _colors: Array): - self.parent = _parent - self.colors = _colors - - - func median_cut() -> void: - var start: Array = [255, 255, 255] - var end: Array = [0, 0, 0] - var delta: Array = [0, 0, 0] - - for color in colors: - for i in 3: - if color[i] < start[i]: - start[i] = color[i] - if color[i] > end[i]: - end[i] = color[i] - for i in 3: - delta[i] = end[i] - start[i] - axis = 0 - if delta[1] > delta[0]: - axis = 1 - if delta[2] > delta[axis]: - axis = 2 - - var axis_sort: Array = [] - for i in colors.size(): - axis_sort.append(colors[i][axis]) - axis_sort.sort() - var cut = colors.size() >> 1 - median = axis_sort[cut] - - var left_colors: Array = [] - var right_colors: Array = [] - for color in colors: - if color[axis] < median: - left_colors.append(color) - else: - right_colors.append(color) - left = TreeNode.new(self, left_colors) - right = TreeNode.new(self, right_colors) - colors = [] - - - func calculate_average_color(color_table: Dictionary) -> void: - average_color = [0, 0, 0] - var total: int = 0 - for color in colors: - var weight = color_table[color] - for i in 3: - average_color[i] += color[i] * weight - total += weight - for i in 3: - average_color[i] /= total - - -func fill_color_table(image: Image) -> void: - image.lock() - var data: PoolByteArray = image.get_data() - - for i in range(0, data.size(), 4): - if data[i + 3] == 0: - transparency = true - continue - var color: Array = [data[i], data[i + 1], data[i + 2]] - var count = color_table.get(color, 0) - color_table[color] = count + 1 - image.unlock() - - -func convert_image(image: Image, colors: Array) -> PoolByteArray: - image.lock() - var data: PoolByteArray = image.get_data() - var nearest_lookup: Dictionary = {} - var result: PoolByteArray = PoolByteArray() - - for i in colors.size(): - colors[i] = Vector3(colors[i][0], colors[i][1], colors[i][2]) - - for i in range(0, data.size(), 4): - if data[i + 3] == 0: - result.append(0) - continue - var current: Vector3 = Vector3(data[i], data[i + 1], data[i + 2]) - var nearest_index: int = 0 + int(transparency) - if current in nearest_lookup: - nearest_index = nearest_lookup[current] - else: - var nearest_distance: float = current.distance_squared_to(colors[nearest_index]) - for j in range(1 + int(transparency), colors.size()): - var distance: float = current.distance_squared_to(colors[j]) - if distance < nearest_distance: - nearest_index = j - nearest_distance = distance - nearest_lookup[current] = nearest_index - result.append(nearest_index) - - image.unlock() - return result - - -func quantize_and_convert_to_codes(image: Image) -> Array: - color_table.clear() - transparency = false - fill_color_table(image) - - tree = TreeNode.new(null, color_table.keys()) - leaf = [tree] - var num = 254 if transparency else 255 - while leaf.size() <= num: - var node = leaf.pop_front() - if node.colors.size() > 1: - node.median_cut() - leaf.append(node.left) - leaf.append(node.right) - if leaf.size() <= 0: - break - - var color_quantized: Dictionary = {} - for node in leaf: - node.calculate_average_color(color_table) - color_quantized[node.average_color] = color_quantized.size() - - var color_array: Array = color_quantized.keys() - if transparency: - color_array.push_front([0, 0, 0]) - - var data: PoolByteArray = converter.get_similar_indexed_datas(image, color_array) - return [data, color_array, transparency] diff --git a/src/Autoload/Export.gd b/src/Autoload/Export.gd index c2a5d81..f0cf57d 100644 --- a/src/Autoload/Export.gd +++ b/src/Autoload/Export.gd @@ -1,8 +1,5 @@ extends Node -# Gif exporter -const gifexporter = preload("res://addons/gdgifexporter/gifexporter.gd") -var quantization = preload("res://addons/gdgifexporter/quantization/median_cut.gd").new() enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 } var current_tab : int = ExportTab.FRAME @@ -36,7 +33,7 @@ var new_dir_for_each_frame_tag : bool = true # you don't need to store this afte var directory_path := "" var file_name := "untitled" var file_format : int = FileFormat.PNG -enum FileFormat { PNG = 0, GIF = 1} +enum FileFormat { PNG = 0} var was_exported : bool = false @@ -48,12 +45,6 @@ var file_exists_alert = "File %s already exists. Overwrite?" # Export progress variables var export_progress_fraction := 0.0 var export_progress := 0.0 -onready var gif_export_thread := Thread.new() - - -func _exit_tree() -> void: - if gif_export_thread.is_active(): - gif_export_thread.wait_to_finish() func external_export() -> void: @@ -176,12 +167,7 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo scale_processed_images() if current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED: - if OS.get_name() == "HTML5": - export_gif({"export_dialog": export_dialog, "export_paths": export_paths}) - else: - if gif_export_thread.is_active(): - gif_export_thread.wait_to_finish() - gif_export_thread.start(self, "export_gif", {"export_dialog": export_dialog, "export_paths": export_paths}) + pass else: for i in range(processed_images.size()): if OS.get_name() == "HTML5": @@ -200,47 +186,6 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo Global.notification_label("File(s) exported") return true - -func export_gif(args: Dictionary) -> void: - # Export progress popup - export_progress_fraction = 100 / processed_images.size() # one fraction per each frame, one fraction for write to disk - export_progress = 0.0 - args["export_dialog"].set_export_progress_bar(export_progress) - args["export_dialog"].toggle_export_progress_popup(true) - - # Export and save gif - var exporter = gifexporter.new(processed_images[0].get_width(), processed_images[0].get_height()) - match direction: - AnimationDirection.FORWARD: - for i in range(processed_images.size()): - write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"]) - AnimationDirection.BACKWARDS: - for i in range(processed_images.size() - 1, -1, -1): - write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"]) - AnimationDirection.PING_PONG: - export_progress_fraction = 100 / (processed_images.size() * 2) - for i in range(0, processed_images.size()): - write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"]) - for i in range(processed_images.size() - 2, 0, -1): - write_frame_to_gif(processed_images[i], Global.animation_timer.wait_time, exporter, args["export_dialog"]) - - if OS.get_name() == "HTML5": - Html5FileExchange.save_gif(exporter.export_file_data(), args["export_paths"][0]) - - else: - var file: File = File.new() - file.open(args["export_paths"][0], File.WRITE) - file.store_buffer(exporter.export_file_data()) - file.close() - args["export_dialog"].toggle_export_progress_popup(false) - Global.notification_label("File(s) exported") - - -func write_frame_to_gif(image: Image, wait_time: float, exporter: Reference, export_dialog: Node) -> void: - exporter.write_frame(image, wait_time, quantization) - increase_export_progress(export_dialog) - - func increase_export_progress(export_dialog: Node) -> void: export_progress += export_progress_fraction export_dialog.set_export_progress_bar(export_progress) @@ -257,8 +202,6 @@ func file_format_string(format_enum : int) -> String: match format_enum: 0: # PNG return '.png' - 1: # GIF - return '.gif' _: return '' diff --git a/src/Autoload/HTML5FileExchange.gd b/src/Autoload/HTML5FileExchange.gd index 1d5274e..78b02c1 100644 --- a/src/Autoload/HTML5FileExchange.gd +++ b/src/Autoload/HTML5FileExchange.gd @@ -201,13 +201,6 @@ func save_image(image : Image, file_name : String = "export") -> void: JavaScript.eval("download('%s', %s, 'image/png');" % [file_name, str(png_data)], true) -func save_gif(data, file_name : String = "export") -> void: - if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'): - return - - JavaScript.eval("download('%s', %s, 'image/gif');" % [file_name, str(Array(data))], true) - - func load_shader() -> void: if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'): return