Add scripts to color-reduce pictures with constraints
Scripts for various Thomson machines, Oric and ZX. All the hard work of Samuel Devulder, with extensive research on color palette reduction algorithms, lots of testing, research and debugging. Thanks a lot!
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- ZX-like image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- This program is free software; you can redistribute
|
||||
-- it and/or modify it under the terms of the GNU
|
||||
-- General Public License as published by the Free
|
||||
-- Software Foundation; version 2 of the License.
|
||||
-- See <http://www.gnu.org/licenses/>
|
||||
|
||||
run('../../thomson/lib/ostromoukhov.lua')
|
||||
|
||||
-- get screen size
|
||||
local screen_w, screen_h = getpicturesize()
|
||||
|
||||
OtherDither = {}
|
||||
function OtherDither:new(a)
|
||||
local o = { -- default ZX values
|
||||
-- width of the screen
|
||||
width=a and a.width or 256,
|
||||
-- height of the screen
|
||||
height=a and a.height or 192,
|
||||
-- size of Nx1 clash size
|
||||
clash_size=a and a.clash_size or 8,
|
||||
-- normalize the picture levels (like in imagemagick)
|
||||
normalize=a and a.normalize or 0.005,
|
||||
-- put a pixel
|
||||
pset=a and a.pset or function(self,x,y,c)
|
||||
if c<0 then c=-c-1 end
|
||||
self.screen[x+y*self.width] = c
|
||||
end,
|
||||
-- init gfx data
|
||||
setGfx=a and a.setGfx or function(self)
|
||||
self.screen={}
|
||||
end,
|
||||
-- update gfx to screen
|
||||
updatescreen=a and a.updatescreen or function(self)
|
||||
for i=0,255 do setcolor(i,0,0,0) end
|
||||
for y=0,self.height-1 do
|
||||
for x=0,self.width-1 do
|
||||
putpicturepixel(x,y,self.screen[x+y*self.width] or 0)
|
||||
end
|
||||
end
|
||||
-- refresh palette
|
||||
for i,v in ipairs(self.pal) do
|
||||
local r=v % 16
|
||||
local g=math.floor(v/16) % 16
|
||||
local b=math.floor(v/256) % 16
|
||||
setcolor(i+thomson._palette.offset-1,
|
||||
thomson.levels.pc[r+1],
|
||||
thomson.levels.pc[g+1],
|
||||
thomson.levels.pc[b+1])
|
||||
end
|
||||
updatescreen()
|
||||
end,
|
||||
-- palette with thomson ordering (to use thomson's
|
||||
-- lib support)
|
||||
pal= a and a.pal or {
|
||||
0x000,0xF00,0x00F,0xF0F,0x0F0,0xFF0,0x0FF,0xFFF,
|
||||
0x000,0x200,0x002,0x202,0x020,0x220,0x022,0x222
|
||||
}
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
-- Converts ZX coordinates (0-255,0-191) into screen coordinates
|
||||
function OtherDither:to_screen(x,y)
|
||||
local i,j;
|
||||
if screen_w/screen_h < self.width/self.height then
|
||||
i = x*screen_h/self.height
|
||||
j = y*screen_h/self.height
|
||||
else
|
||||
i = x*screen_w/self.width
|
||||
j = y*screen_w/self.width
|
||||
end
|
||||
return math.floor(i), math.floor(j)
|
||||
end
|
||||
|
||||
-- return the Color @(x,y) in linear space (0-255)
|
||||
-- corresonding to the other platform screen
|
||||
OtherDither._getLinearPixel = {} -- cache
|
||||
function OtherDither:getLinearPixel(x,y)
|
||||
local k=x+y*self.width
|
||||
local p = self._getLinearPixel and self._getLinearPixel[k]
|
||||
if not p then
|
||||
local x1,y1 = self:to_screen(x,y)
|
||||
local x2,y2 = self:to_screen(x+1,y+1)
|
||||
if x2==x1 then x2=x1+1 end
|
||||
if y2==y1 then y2=y1+1 end
|
||||
|
||||
p = Color:new(0,0,0)
|
||||
for j=y1,y2-1 do
|
||||
for i=x1,x2-1 do
|
||||
p:add(getLinearPictureColor(i,j))
|
||||
end
|
||||
end
|
||||
p:div((y2-y1)*(x2-x1)) --:floor()
|
||||
|
||||
if self._getLinearPixel then
|
||||
self._getLinearPixel[k]=p
|
||||
end
|
||||
end
|
||||
|
||||
return self._getLinearPixel and p:clone() or p
|
||||
end
|
||||
|
||||
function OtherDither:ccAcceptCouple(c1,c2)
|
||||
-- bright colors can't mix with dimmed ones
|
||||
return c1~=c2 and ((c1<=8 and c2<=8) or (c1>8 and c2>8))
|
||||
end
|
||||
|
||||
function OtherDither:dither()
|
||||
local NORMALIZE=Color.NORMALIZE
|
||||
Color.NORMALIZE=self.normalize
|
||||
|
||||
local dither=OstroDither:new(self.pal)
|
||||
dither.ccAcceptCouple = function(dither,c1,c2) return self:ccAcceptCouple(c1,c2) end
|
||||
dither.clash_size = self.clash_size
|
||||
dither.attenuation = .9
|
||||
|
||||
self:setGfx()
|
||||
dither:ccDither(self.width,self.height,
|
||||
function(x,y) return self:getLinearPixel(x,y) end,
|
||||
function(x,y,c) self:pset(x,y,c) end,
|
||||
true,
|
||||
function(y)
|
||||
thomson.info("Converting...",
|
||||
math.floor(y*100/self.height),"%")
|
||||
end,true)
|
||||
-- refresh screen
|
||||
setpicturesize(self.width,self.height)
|
||||
self:updatescreen()
|
||||
finalizepicture()
|
||||
Color.NORMALIZE=NORMALIZE
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- Oric image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- This program is free software; you can redistribute
|
||||
-- it and/or modify it under the terms of the GNU
|
||||
-- General Public License as published by the Free
|
||||
-- Software Foundation; version 2 of the License.
|
||||
-- See <http://www.gnu.org/licenses/>
|
||||
|
||||
run('lib/ostro_other.lua')
|
||||
|
||||
OtherDither:new{
|
||||
width=240,
|
||||
height=200,
|
||||
clash_size=6,
|
||||
pal={0x000,0x00F,0x0F0,0x0FF,0xF00,0xF0F,0xFF0,0xFFF},
|
||||
pset=function(self,x,y,c)
|
||||
if x<6 then c=0 end
|
||||
if c<0 then c=-c-1 end
|
||||
self.screen[x+y*self.width] = c
|
||||
end
|
||||
}:dither()
|
||||
@@ -0,0 +1,17 @@
|
||||
-- ostro_zx.lua : converts a color image into a
|
||||
-- ZX image (8+8 fixed colors with color clash)
|
||||
-- using Ostromoukhov's error diffusion algorithm.
|
||||
--
|
||||
-- Version: 03/21/2017
|
||||
--
|
||||
-- Copyright 2016-2017 by Samuel Devulder
|
||||
--
|
||||
-- This program is free software; you can redistribute
|
||||
-- it and/or modify it under the terms of the GNU
|
||||
-- General Public License as published by the Free
|
||||
-- Software Foundation; version 2 of the License.
|
||||
-- See <http://www.gnu.org/licenses/>
|
||||
|
||||
run('lib/ostro_other.lua')
|
||||
|
||||
OtherDither:new{width=256,height=192,clash_size=8}:dither()
|
||||
Reference in New Issue
Block a user