forked from VoxeLibre/VoxeLibre
Allow encoding with A1R5G5B5 colormap
This commit is contained in:
parent
e83894fcfa
commit
45e405982a
|
@ -125,4 +125,6 @@ local pixels = {
|
||||||
}
|
}
|
||||||
-- note that the uncompressed colormapped TGA file written in this
|
-- note that the uncompressed colormapped TGA file written in this
|
||||||
-- example is 108 bytes – but an optimized PNG file is 121 bytes …
|
-- example is 108 bytes – but an optimized PNG file is 121 bytes …
|
||||||
tga_encoder.image(pixels):save("colormapped_8bpp.tga", {colormap=colormap})
|
tga_encoder.image(pixels):save("colormapped_B8G8R8.tga", {colormap=colormap})
|
||||||
|
-- encoding as A1R5G5B5 saves 1 byte per palette entry → 103 bytes
|
||||||
|
tga_encoder.image(pixels):save("colormapped_A1R5G5B5.tga", {colormap=colormap, color_format="A1R5G5B5"})
|
||||||
|
|
52
init.lua
52
init.lua
|
@ -14,11 +14,20 @@ function image:constructor(pixels)
|
||||||
self.height = #pixels
|
self.height = #pixels
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local pixel_depth_by_color_format = {
|
||||||
|
["Y8"] = 8,
|
||||||
|
["A1R5G5B5"] = 16,
|
||||||
|
["B8G8R8"] = 24,
|
||||||
|
["B8G8R8A8"] = 32,
|
||||||
|
}
|
||||||
|
|
||||||
function image:encode_colormap_spec(properties)
|
function image:encode_colormap_spec(properties)
|
||||||
local colormap = properties.colormap
|
local colormap = properties.colormap
|
||||||
local colormap_pixel_depth = 0
|
local colormap_pixel_depth = 0
|
||||||
if 0 ~= #colormap then
|
if 0 ~= #colormap then
|
||||||
colormap_pixel_depth = #colormap[1] * 8
|
colormap_pixel_depth = pixel_depth_by_color_format[
|
||||||
|
properties.color_format
|
||||||
|
]
|
||||||
end
|
end
|
||||||
local colormap_spec =
|
local colormap_spec =
|
||||||
string.char(0, 0) .. -- first entry index
|
string.char(0, 0) .. -- first entry index
|
||||||
|
@ -35,12 +44,6 @@ function image:encode_image_spec(properties)
|
||||||
"B8G8R8" == color_format or -- (B8G8R8 = 3 bytes = 24 bits)
|
"B8G8R8" == color_format or -- (B8G8R8 = 3 bytes = 24 bits)
|
||||||
"B8G8R8A8" == color_format -- (B8G8R8A8 = 4 bytes = 32 bits)
|
"B8G8R8A8" == color_format -- (B8G8R8A8 = 4 bytes = 32 bits)
|
||||||
)
|
)
|
||||||
pixel_depth_by_color_format = {
|
|
||||||
["Y8"] = 8,
|
|
||||||
["A1R5G5B5"] = 16,
|
|
||||||
["B8G8R8"] = 24,
|
|
||||||
["B8G8R8A8"] = 32,
|
|
||||||
}
|
|
||||||
local pixel_depth
|
local pixel_depth
|
||||||
if 0 ~= #properties.colormap then
|
if 0 ~= #properties.colormap then
|
||||||
pixel_depth = self.pixel_depth
|
pixel_depth = self.pixel_depth
|
||||||
|
@ -62,10 +65,30 @@ function image:encode_colormap(properties)
|
||||||
if 0 == #colormap then
|
if 0 == #colormap then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local colormap_pixel_depth = #colormap[1] * 8
|
local color_format = properties.color_format
|
||||||
assert( 24 == colormap_pixel_depth )
|
assert (
|
||||||
|
"A1R5G5B5" == color_format or
|
||||||
|
"B8G8R8" == color_format
|
||||||
|
)
|
||||||
local colors = {}
|
local colors = {}
|
||||||
if 24 == colormap_pixel_depth then
|
if "A1R5G5B5" == color_format then
|
||||||
|
-- Sample depth rescaling is done according to the algorithm presented in:
|
||||||
|
-- <https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling>
|
||||||
|
local max_sample_in = math.pow(2, 8) - 1
|
||||||
|
local max_sample_out = math.pow(2, 5) - 1
|
||||||
|
for i = 1,#colormap,1 do
|
||||||
|
local color = colormap[i]
|
||||||
|
local colorword = 32768 +
|
||||||
|
((math.floor((color[1] * max_sample_out / max_sample_in) + 0.5)) * 1024) +
|
||||||
|
((math.floor((color[2] * max_sample_out / max_sample_in) + 0.5)) * 32) +
|
||||||
|
((math.floor((color[3] * max_sample_out / max_sample_in) + 0.5)) * 1)
|
||||||
|
local color_bytes = string.char(
|
||||||
|
colorword % 256,
|
||||||
|
math.floor(colorword / 256)
|
||||||
|
)
|
||||||
|
colors[#colors + 1] = color_bytes
|
||||||
|
end
|
||||||
|
elseif "B8G8R8" == color_format then
|
||||||
for i = 1,#colormap,1 do
|
for i = 1,#colormap,1 do
|
||||||
local color = colormap[i]
|
local color = colormap[i]
|
||||||
local color_bytes = string.char(
|
local color_bytes = string.char(
|
||||||
|
@ -76,6 +99,7 @@ function image:encode_colormap(properties)
|
||||||
colors[#colors + 1] = color_bytes
|
colors[#colors + 1] = color_bytes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
assert( 0 ~= #colors )
|
||||||
self.data = self.data .. table.concat(colors)
|
self.data = self.data .. table.concat(colors)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -130,11 +154,19 @@ function image:encode_data(properties)
|
||||||
self:encode_data_R8G8B8_as_Y8_raw()
|
self:encode_data_R8G8B8_as_Y8_raw()
|
||||||
end
|
end
|
||||||
elseif "A1R5G5B5" == color_format then
|
elseif "A1R5G5B5" == color_format then
|
||||||
|
if 0 ~= #colormap then
|
||||||
|
if "RAW" == compression then
|
||||||
|
if 8 == self.pixel_depth then
|
||||||
|
self:encode_data_Y8_as_Y8_raw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
if "RAW" == compression then
|
if "RAW" == compression then
|
||||||
self:encode_data_R8G8B8_as_A1R5G5B5_raw()
|
self:encode_data_R8G8B8_as_A1R5G5B5_raw()
|
||||||
elseif "RLE" == compression then
|
elseif "RLE" == compression then
|
||||||
self:encode_data_R8G8B8_as_A1R5G5B5_rle()
|
self:encode_data_R8G8B8_as_A1R5G5B5_rle()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
elseif "B8G8R8" == color_format then
|
elseif "B8G8R8" == color_format then
|
||||||
if 0 ~= #colormap then
|
if 0 ~= #colormap then
|
||||||
if "RAW" == compression then
|
if "RAW" == compression then
|
||||||
|
|
Loading…
Reference in New Issue