Skip to content

Commit d90d7ea

Browse files
author
Niels Martin Hansen
committed
Implement raster.pixel_value_map function using expression evaluator. Seems to work correct.
Originally committed to SVN as r1507.
1 parent bef33a3 commit d90d7ea

File tree

5 files changed

+112
-1
lines changed

5 files changed

+112
-1
lines changed

docs/expression-evaluator.txt

+7-1
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,10 @@ else return the third argument.
217217
Sample programs
218218
---------------
219219

220-
To be written. No functions in OverLua use the expression evaluator yet.
220+
For raster.pixel_value_map:
221+
222+
"rand =t0 t0 =R t0 =G t0 =B"
223+
Create a field of random gray-values.
224+
225+
"0 =R 1 G - =G"
226+
Zero out the red channel and invert the green channel.

docs/overlua.txt

+19
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,25 @@ The filter is one-dimensional, but is applied first horizontally and then
188188
vertically ovre the image to get the final image.
189189

190190

191+
raster.pixel_value_map(surface, expression)
192+
193+
Map an expression over every pixel RGB value in the surface. Only works for
194+
ARGB32 and RGB24 surfaces.
195+
196+
The expression is an RPN expression in the OverLua Expression Evaluator
197+
language, see expression-evaluator.txt for details.
198+
199+
No additional functions are made available to the expression evaluator by
200+
this function.
201+
202+
The following new registers are made available to the expression evaluator:
203+
R In range 0..1, red component. Input and output.
204+
G Ditto, for green component.
205+
B Ditto, for blue component.
206+
X X-coordinate of pixel being processed. Input only.
207+
Y Y-coordinate of pixel being processed. Input only.
208+
209+
191210
More filtering functions are planned, though no specifics yet.
192211

193212
Wishes/suggestions are welcome, and so are patches to add more functions.

docs/test3.lua

+5
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@ function render_frame(f, t)
55
--raster.separable_filter(surf, {-1, 3, -1}, 1)
66
--raster.directional_blur(surf, t, t/10)
77
raster.radial_blur(surf, 200, 200, t/60)
8+
raster.pixel_value_map(surf, "0 =R 1 G - =G")
89
f.overlay_cairo_surface(surf, 0, 0)
10+
11+
surf = cairo.image_surface_create(200, 200, "rgb24")
12+
raster.pixel_value_map(surf, "rand =t0 t0 =R t0 =G t0 =B")
13+
f.overlay_cairo_surface(surf, 20, 20)
914
end

expression_engine.h

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ namespace ExpressionEngine {
105105

106106
// Create a machine from a specification and a program source
107107
Machine(const Specification &spec, const char *source);
108+
109+
// Create a blank machine
110+
Machine() { }
108111
};
109112

110113
};

raster_ops.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <omp.h>
3131
#include <stdint.h>
3232

33+
#include "expression_engine.h"
3334
#include "raster_ops.h"
3435
#include "../lua51/src/lauxlib.h"
3536

@@ -686,13 +687,90 @@ static int separable_filter(lua_State *L)
686687
}
687688

688689

690+
static int pixel_value_map(lua_State *L)
691+
{
692+
cairo_surface_t *surf = CheckSurface(L, 1);
693+
const char *program = luaL_checkstring(L, 2);
694+
695+
// Set up engine specs
696+
ExpressionEngine::Specification spec;
697+
spec.registers.resize(5);
698+
spec.registers[0] = "R";
699+
spec.registers[1] = "G";
700+
spec.registers[2] = "B";
701+
spec.registers[3] = "X";
702+
spec.registers[4] = "Y";
703+
704+
// Compile program
705+
ExpressionEngine::Machine machine;
706+
try {
707+
machine = ExpressionEngine::Machine(spec, program);
708+
}
709+
catch (const char *e) {
710+
// This is a parse error
711+
luaL_error(L, "Error in expression program near\"%s\"", e);
712+
}
713+
714+
// Init image
715+
cairo_surface_flush(surf);
716+
int width = cairo_image_surface_get_width(surf);
717+
int height = cairo_image_surface_get_height(surf);
718+
ptrdiff_t stride = (ptrdiff_t)cairo_image_surface_get_stride(surf);
719+
unsigned char *data = cairo_image_surface_get_data(surf);
720+
cairo_format_t format = cairo_image_surface_get_format(surf);
721+
722+
if (format == CAIRO_FORMAT_ARGB32) {
723+
BaseImage<PixelFormat::cairo_argb32> img(width, height, stride, data);
724+
for (int y = 0; y < height; y++) {
725+
for (int x = 0; x < width; x++) {
726+
PixelFormat::cairo_argb32 &p = img.Pixel(x, y);
727+
machine.registers[0] = (double)p.R() / 255.0;
728+
machine.registers[1] = (double)p.G() / 255.0;
729+
machine.registers[2] = (double)p.B() / 255.0;
730+
machine.registers[3] = x;
731+
machine.registers[4] = y;
732+
machine.Run();
733+
p.R() = (uint8_t)(machine.registers[0] * 255);
734+
p.G() = (uint8_t)(machine.registers[1] * 255);
735+
p.B() = (uint8_t)(machine.registers[2] * 255);
736+
}
737+
}
738+
}
739+
else if (format == CAIRO_FORMAT_RGB24) {
740+
BaseImage<PixelFormat::cairo_rgb24> img(width, height, stride, data);
741+
for (int y = 0; y < height; y++) {
742+
for (int x = 0; x < width; x++) {
743+
PixelFormat::cairo_rgb24 &p = img.Pixel(x, y);
744+
machine.registers[0] = (double)p.R() / 255.0;
745+
machine.registers[1] = (double)p.G() / 255.0;
746+
machine.registers[2] = (double)p.B() / 255.0;
747+
machine.registers[3] = x;
748+
machine.registers[4] = y;
749+
machine.Run();
750+
p.R() = (uint8_t)(machine.registers[0] * 255);
751+
p.G() = (uint8_t)(machine.registers[1] * 255);
752+
p.B() = (uint8_t)(machine.registers[2] * 255);
753+
}
754+
}
755+
}
756+
else {
757+
luaL_error(L, "Unsupported pixel format");
758+
}
759+
760+
cairo_surface_mark_dirty(surf);
761+
762+
return 0;
763+
}
764+
765+
689766
// Registration
690767

691768
static luaL_Reg rasterlib[] = {
692769
{"gaussian_blur", gaussian_blur}, {"box_blur", box_blur},
693770
{"directional_blur", directional_blur}, {"radial_blur", radial_blur},
694771
{"separable_filter", separable_filter},
695772
{"invert", invert_image},
773+
{"pixel_value_map", pixel_value_map},
696774
{NULL, NULL}
697775
};
698776

0 commit comments

Comments
 (0)