From ed061e68ffb9eb80ac816f74eaeb1c4513511253 Mon Sep 17 00:00:00 2001 From: Nils Dagsson Moskopp Date: Mon, 16 May 2022 13:16:23 +0200 Subject: [PATCH] Allow RLE encoding for RGBA images --- examples.lua | 3 ++ init.lua | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/examples.lua b/examples.lua index 559d36ac2..6255cf539 100644 --- a/examples.lua +++ b/examples.lua @@ -73,6 +73,9 @@ for x = 1,16,1 do -- left to right end end gradients:save("gradients_32bpp_raw.tga", {color_format="B8G8R8A8", compression="RAW"}) +-- the RLE-compressed file is larger than just dumping pixels because +-- the gradients in this picture can not be compressed well using RLE +gradients:save("gradients_32bpp_rle.tga", {color_format="B8G8R8A8", compression="RLE"}) local pixels = {} for x = 1,512,1 do -- left to right diff --git a/init.lua b/init.lua index e8cc8942a..562d1e1f1 100644 --- a/init.lua +++ b/init.lua @@ -98,6 +98,8 @@ function image:encode_data(properties) elseif "B8G8R8A8" == color_format then if "RAW" == compression then self:encode_data_R8G8B8A8_as_B8G8R8A8_raw() + elseif "RLE" == compression then + self:encode_data_R8G8B8A8_as_B8G8R8A8_rle() end end local data_length_after = #self.data @@ -352,6 +354,85 @@ function image:encode_data_R8G8B8A8_as_B8G8R8A8_raw() self.data = self.data .. table.concat(raw_pixels) end +function image:encode_data_R8G8B8A8_as_B8G8R8A8_rle() + assert(32 == self.pixel_depth) + local previous_r = nil + local previous_g = nil + local previous_b = nil + local previous_a = nil + local raw_pixel = '' + local raw_pixels = {} + local count = 1 + local packets = {} + local raw_packet = '' + local rle_packet = '' + for _, row in ipairs(self.pixels) do + for _, pixel in ipairs(row) do + if pixel[1] ~= previous_r or pixel[2] ~= previous_g or pixel[3] ~= previous_b or pixel[4] ~= previous_a or count == 128 then + if nil ~= previous_r then + if 1 == count then + -- remember pixel verbatim for raw encoding + raw_pixel = string.char(previous_b, previous_g, previous_r, previous_a) + raw_pixels[#raw_pixels + 1] = raw_pixel + if 128 == #raw_pixels then + raw_packet = string.char(#raw_pixels - 1) + packets[#packets + 1] = raw_packet + for i=1, #raw_pixels do + packets[#packets +1] = raw_pixels[i] + end + raw_pixels = {} + end + else + -- encode raw pixels, if any + if #raw_pixels > 0 then + raw_packet = string.char(#raw_pixels - 1) + packets[#packets + 1] = raw_packet + for i=1, #raw_pixels do + packets[#packets +1] = raw_pixels[i] + end + raw_pixels = {} + end + -- RLE encoding + rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r, previous_a) + packets[#packets +1] = rle_packet + end + end + count = 1 + previous_r = pixel[1] + previous_g = pixel[2] + previous_b = pixel[3] + previous_a = pixel[4] + else + count = count + 1 + end + end + end + if 1 == count then + raw_pixel = string.char(previous_b, previous_g, previous_r, previous_a) + raw_pixels[#raw_pixels + 1] = raw_pixel + raw_packet = string.char(#raw_pixels - 1) + packets[#packets + 1] = raw_packet + for i=1, #raw_pixels do + packets[#packets +1] = raw_pixels[i] + end + raw_pixels = {} + else + -- encode raw pixels, if any + if #raw_pixels > 0 then + raw_packet = string.char(#raw_pixels - 1) + packets[#packets + 1] = raw_packet + for i=1, #raw_pixels do + packets[#packets +1] = raw_pixels[i] + end + raw_pixels = {} + end + -- RLE encoding + rle_packet = string.char(128 + count - 1, previous_b, previous_g, previous_r, previous_a) + packets[#packets +1] = rle_packet + end + self.data = self.data .. table.concat(packets) +end + function image:encode_footer() self.data = self.data .. string.char(0, 0, 0, 0) -- extension area offset