From 376b6404b2e9a0a1d3ca6535b9c4a455ef283111 Mon Sep 17 00:00:00 2001 From: Nils Dagsson Moskopp Date: Sun, 15 May 2022 15:42:48 +0200 Subject: [PATCH] Allow RAW or RLE encoding for true-color images --- examples.lua | 8 +++++--- init.lua | 56 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/examples.lua b/examples.lua index 4d04e6e..b2d9de6 100644 --- a/examples.lua +++ b/examples.lua @@ -39,7 +39,7 @@ for x = 1,6,1 do -- left to right pixels[z][x] = color end end -tga_encoder.image(pixels):save("gradients_8bpp.tga", {colors="BW", pixel_depth=8}) +tga_encoder.image(pixels):save("gradients_8bpp_raw.tga", {colors="BW", compression="RAW", pixel_depth=8}) local pixels = {} for x = 1,16,1 do -- left to right @@ -59,8 +59,10 @@ for x = 1,16,1 do -- left to right end end local gradients = tga_encoder.image(pixels) -gradients:save("gradients_16bpp.tga", {colors="RGB", pixel_depth=16}) -gradients:save("gradients_24bpp.tga", {colors="RGB", pixel_depth=24}) +gradients:save("gradients_16bpp_raw.tga", {colors="RGB", compression="RAW", pixel_depth=16}) +gradients:save("gradients_16bpp_rle.tga", {colors="RGB", compression="RLE", pixel_depth=16}) +gradients:save("gradients_24bpp_raw.tga", {colors="RGB", compression="RAW", pixel_depth=24}) +gradients:save("gradients_24bpp_rle.tga", {colors="RGB", compression="RLE", pixel_depth=24}) local pixels = {} for x = 1,512,1 do -- left to right diff --git a/init.lua b/init.lua index a79a329..c044cda 100644 --- a/init.lua +++ b/init.lua @@ -40,15 +40,20 @@ end function image:encode_header(properties) local colors = properties.colors + local compression = properties.compression local pixel_depth = properties.pixel_depth local image_type - if "BW" == colors and 8 == pixel_depth then + if "BW" == colors and "RAW" == compression and 8 == pixel_depth then image_type = 3 -- grayscale elseif ( "RGB" == colors and 16 == pixel_depth or "RGB" == colors and 24 == pixel_depth ) then - image_type = 10 -- RLE RGB + if "RAW" == compression then + image_type = 2 -- RAW RGB + elseif "RLE" == compression then + image_type = 10 -- RLE RGB + end end self.data = self.data .. string.char(0) -- image id @@ -60,13 +65,23 @@ end function image:encode_data(properties) local colors = properties.colors + local compression = properties.compression local pixel_depth = properties.pixel_depth - if "BW" == colors and 8 == pixel_depth then + + if "BW" == colors and "RAW" == compression and 8 == pixel_depth then self:encode_data_bw8() elseif "RGB" == colors and 16 == pixel_depth then - self:encode_data_a1r5g5b5_rle() + if "RAW" == compression then + self:encode_data_a1r5g5b5_raw() + elseif "RLE" == compression then + self:encode_data_a1r5g5b5_rle() + end elseif "RGB" == colors and 24 == pixel_depth then - self:encode_data_r8g8b8_rle() + if "RAW" == compression then + self:encode_data_r8g8b8_raw() + elseif "RLE" == compression then + self:encode_data_r8g8b8_rle() + end end end @@ -81,6 +96,25 @@ function image:encode_data_bw8() self.data = self.data .. table.concat(raw_pixels) end +function image:encode_data_a1r5g5b5_raw() + local raw_pixels = {} + -- Sample depth rescaling is done according to the algorithm presented in: + -- + local max_sample_in = math.pow(2, 8) - 1 + local max_sample_out = math.pow(2, 5) - 1 + for _, row in ipairs(self.pixels) do + for _, pixel in ipairs(row) do + local colorword = 32768 + + ((math.floor((pixel[1] * max_sample_out / max_sample_in) + 0.5)) * 1024) + + ((math.floor((pixel[2] * max_sample_out / max_sample_in) + 0.5)) * 32) + + ((math.floor((pixel[3] * max_sample_out / max_sample_in) + 0.5)) * 1) + local raw_pixel = string.char(colorword % 256, math.floor(colorword / 256)) + raw_pixels[#raw_pixels + 1] = raw_pixel + end + end + self.data = self.data .. table.concat(raw_pixels) +end + function image:encode_data_a1r5g5b5_rle() local colorword = nil local previous_r = nil @@ -170,6 +204,17 @@ function image:encode_data_a1r5g5b5_rle() self.data = self.data .. table.concat(packets) end +function image:encode_data_r8g8b8_raw() + local raw_pixels = {} + for _, row in ipairs(self.pixels) do + for _, pixel in ipairs(row) do + local raw_pixel = string.char(pixel[3], pixel[2], pixel[1]) + raw_pixels[#raw_pixels + 1] = raw_pixel + end + end + self.data = self.data .. table.concat(raw_pixels) +end + function image:encode_data_r8g8b8_rle() local previous_r = nil local previous_g = nil @@ -267,6 +312,7 @@ end function image:save(filename, properties) local properties = properties or {} properties.colors = properties.colors or "RGB" + properties.compression = properties.compression or "RLE" properties.pixel_depth = properties.pixel_depth or 16 self:encode(properties)