forked from VoxeLibre/VoxeLibre
Allow color-mapped encoding for RGB images
This commit is contained in:
parent
ed061e68ff
commit
9f9b78eed9
26
examples.lua
26
examples.lua
|
@ -100,3 +100,29 @@ end
|
||||||
tga_encoder.image(pixels):save("fractal_8bpp.tga", {color_format="Y8"})
|
tga_encoder.image(pixels):save("fractal_8bpp.tga", {color_format="Y8"})
|
||||||
tga_encoder.image(pixels):save("fractal_16bpp.tga", {color_format="A1R5G5B5"})
|
tga_encoder.image(pixels):save("fractal_16bpp.tga", {color_format="A1R5G5B5"})
|
||||||
tga_encoder.image(pixels):save("fractal_24bpp.tga", {color_format="B8G8R8"})
|
tga_encoder.image(pixels):save("fractal_24bpp.tga", {color_format="B8G8R8"})
|
||||||
|
|
||||||
|
-- encode a colormapped bitmap
|
||||||
|
local K = { 0 }
|
||||||
|
local B = { 1 }
|
||||||
|
local R = { 2 }
|
||||||
|
local G = { 3 }
|
||||||
|
local W = { 4 }
|
||||||
|
local colormap = {
|
||||||
|
{ 1, 2, 3 }, -- K
|
||||||
|
{ 0, 0, 255 }, -- B
|
||||||
|
{ 255, 0, 0 }, -- R
|
||||||
|
{ 0, 255, 0 }, -- G
|
||||||
|
{ 253, 254, 255 }, -- W
|
||||||
|
}
|
||||||
|
local pixels = {
|
||||||
|
{ W, K, W, K, W, K, W },
|
||||||
|
{ R, G, B, R, G, B, K },
|
||||||
|
{ K, W, K, W, K, W, K },
|
||||||
|
{ G, B, R, G, B, R, W },
|
||||||
|
{ W, W, W, K, K, K, W },
|
||||||
|
{ B, R, G, B, R, G, K },
|
||||||
|
{ B, R, G, B, R, G, W },
|
||||||
|
}
|
||||||
|
-- note that the uncompressed colormapped TGA file written in this
|
||||||
|
-- example is 108 bytes – but an optimized PNG file is 121 bytes …
|
||||||
|
tga_encoder.image(pixels):save("colormapped_8bpp.tga", {colormap=colormap})
|
||||||
|
|
94
init.lua
94
init.lua
|
@ -14,11 +14,21 @@ function image:constructor(pixels)
|
||||||
self.height = #pixels
|
self.height = #pixels
|
||||||
end
|
end
|
||||||
|
|
||||||
function image:encode_colormap_spec()
|
function image:encode_colormap_spec(properties)
|
||||||
self.data = self.data
|
local colormap_spec
|
||||||
.. string.char(0, 0) -- first entry index
|
if nil ~= properties.colormap then
|
||||||
.. string.char(0, 0) -- number of entries
|
local color_count = #properties.colormap
|
||||||
.. string.char(0) -- bits per pixel
|
colormap_spec =
|
||||||
|
string.char(0, 0) .. -- first entry index
|
||||||
|
string.char(color_count % 256, math.floor(color_count / 256)) .. -- number of entries
|
||||||
|
string.char(#properties.colormap[1] * 8) -- bits per pixel
|
||||||
|
else -- no colormap
|
||||||
|
colormap_spec =
|
||||||
|
string.char(0, 0) .. -- first entry index
|
||||||
|
string.char(0, 0) .. -- number of entries
|
||||||
|
string.char(0) -- bits per pixel
|
||||||
|
end
|
||||||
|
self.data = self.data .. colormap_spec
|
||||||
end
|
end
|
||||||
|
|
||||||
function image:encode_image_spec(properties)
|
function image:encode_image_spec(properties)
|
||||||
|
@ -35,7 +45,12 @@ function image:encode_image_spec(properties)
|
||||||
["B8G8R8"] = 24,
|
["B8G8R8"] = 24,
|
||||||
["B8G8R8A8"] = 32,
|
["B8G8R8A8"] = 32,
|
||||||
}
|
}
|
||||||
local pixel_depth = pixel_depth_by_color_format[color_format]
|
local pixel_depth
|
||||||
|
if nil ~= properties.colormap then
|
||||||
|
pixel_depth = self.pixel_depth
|
||||||
|
else
|
||||||
|
pixel_depth = pixel_depth_by_color_format[color_format]
|
||||||
|
end
|
||||||
assert( nil ~= pixel_depth)
|
assert( nil ~= pixel_depth)
|
||||||
self.data = self.data
|
self.data = self.data
|
||||||
.. string.char(0, 0) -- X-origin
|
.. string.char(0, 0) -- X-origin
|
||||||
|
@ -46,8 +61,31 @@ function image:encode_image_spec(properties)
|
||||||
.. string.char(0) -- image descriptor
|
.. string.char(0) -- image descriptor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function image:encode_colormap(properties)
|
||||||
|
local colormap = properties.colormap
|
||||||
|
if nil == colormap then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local colormap_pixel_depth = #colormap[1] * 8
|
||||||
|
assert( 24 == colormap_pixel_depth )
|
||||||
|
local colors = {}
|
||||||
|
if 24 == colormap_pixel_depth then
|
||||||
|
for i = 1,#colormap,1 do
|
||||||
|
local color = colormap[i]
|
||||||
|
local color_bytes = string.char(
|
||||||
|
color[3], -- B
|
||||||
|
color[2], -- G
|
||||||
|
color[1] -- R
|
||||||
|
)
|
||||||
|
colors[#colors + 1] = color_bytes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.data = self.data .. table.concat(colors)
|
||||||
|
end
|
||||||
|
|
||||||
function image:encode_header(properties)
|
function image:encode_header(properties)
|
||||||
local color_format = properties.color_format
|
local color_format = properties.color_format
|
||||||
|
local colormap = properties.colormap
|
||||||
local compression = properties.compression
|
local compression = properties.compression
|
||||||
local image_type
|
local image_type
|
||||||
if "Y8" == color_format and "RAW" == compression then
|
if "Y8" == color_format and "RAW" == compression then
|
||||||
|
@ -58,22 +96,32 @@ function image:encode_header(properties)
|
||||||
"B8G8R8A8" == color_format
|
"B8G8R8A8" == color_format
|
||||||
) then
|
) then
|
||||||
if "RAW" == compression then
|
if "RAW" == compression then
|
||||||
|
if nil ~= colormap then
|
||||||
|
image_type = 1 -- colormapped RGB(A)
|
||||||
|
else
|
||||||
image_type = 2 -- RAW RGB(A)
|
image_type = 2 -- RAW RGB(A)
|
||||||
|
end
|
||||||
elseif "RLE" == compression then
|
elseif "RLE" == compression then
|
||||||
image_type = 10 -- RLE RGB
|
image_type = 10 -- RLE RGB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert( nil ~= image_type )
|
assert( nil ~= image_type )
|
||||||
|
local colormap_type = 0
|
||||||
|
if nil ~= colormap then
|
||||||
|
colormap_type = 1
|
||||||
|
end
|
||||||
self.data = self.data
|
self.data = self.data
|
||||||
.. string.char(0) -- image id
|
.. string.char(0) -- image id
|
||||||
.. string.char(0) -- color map type
|
.. string.char(colormap_type)
|
||||||
.. string.char(image_type)
|
.. string.char(image_type)
|
||||||
self:encode_colormap_spec() -- color map specification
|
self:encode_colormap_spec(properties) -- color map specification
|
||||||
self:encode_image_spec(properties) -- image specification
|
self:encode_image_spec(properties) -- image specification
|
||||||
|
self:encode_colormap(properties)
|
||||||
end
|
end
|
||||||
|
|
||||||
function image:encode_data(properties)
|
function image:encode_data(properties)
|
||||||
local color_format = properties.color_format
|
local color_format = properties.color_format
|
||||||
|
local colormap = properties.colormap
|
||||||
local compression = properties.compression
|
local compression = properties.compression
|
||||||
|
|
||||||
local data_length_before = #self.data
|
local data_length_before = #self.data
|
||||||
|
@ -90,11 +138,19 @@ function image:encode_data(properties)
|
||||||
self:encode_data_R8G8B8_as_A1R5G5B5_rle()
|
self:encode_data_R8G8B8_as_A1R5G5B5_rle()
|
||||||
end
|
end
|
||||||
elseif "B8G8R8" == color_format then
|
elseif "B8G8R8" == color_format then
|
||||||
|
if nil ~= 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_B8G8R8_raw()
|
self:encode_data_R8G8B8_as_B8G8R8_raw()
|
||||||
elseif "RLE" == compression then
|
elseif "RLE" == compression then
|
||||||
self:encode_data_R8G8B8_as_B8G8R8_rle()
|
self:encode_data_R8G8B8_as_B8G8R8_rle()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
elseif "B8G8R8A8" == color_format then
|
elseif "B8G8R8A8" == color_format then
|
||||||
if "RAW" == compression then
|
if "RAW" == compression then
|
||||||
self:encode_data_R8G8B8A8_as_B8G8R8A8_raw()
|
self:encode_data_R8G8B8A8_as_B8G8R8A8_raw()
|
||||||
|
@ -456,13 +512,23 @@ function image:save(filename, properties)
|
||||||
properties.compression = properties.compression or "RAW"
|
properties.compression = properties.compression or "RAW"
|
||||||
|
|
||||||
self.pixel_depth = #self.pixels[1][1] * 8
|
self.pixel_depth = #self.pixels[1][1] * 8
|
||||||
|
|
||||||
|
local color_format_defaults_by_pixel_depth = {
|
||||||
|
[8] = "Y8",
|
||||||
|
[24] = "B8G8R8",
|
||||||
|
[32] = "B8G8R8A8",
|
||||||
|
}
|
||||||
if nil == properties.color_format then
|
if nil == properties.color_format then
|
||||||
if 8 == self.pixel_depth then
|
if nil ~= properties.colormap then
|
||||||
properties.color_format = "Y8"
|
properties.color_format =
|
||||||
elseif 24 == self.pixel_depth then
|
color_format_defaults_by_pixel_depth[
|
||||||
properties.color_format = "B8G8R8"
|
#properties.colormap[1] * 8
|
||||||
elseif 32 == self.pixel_depth then
|
]
|
||||||
properties.color_format = "B8G8R8A8"
|
else
|
||||||
|
properties.color_format =
|
||||||
|
color_format_defaults_by_pixel_depth[
|
||||||
|
self.pixel_depth
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert( nil ~= properties.color_format )
|
assert( nil ~= properties.color_format )
|
||||||
|
|
Loading…
Reference in New Issue