Commit b4bcb394 authored by twanvl's avatar twanvl

Added 'recolor_image' function

parent 27d93cc9
......@@ -83,7 +83,8 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:set_alpha]] Change the transparency of an image.
| [[fun:set_combine]] Change how the image should be combined with the background.
| [[fun:saturate]] Saturate/desaturate an image.
| [[fun:invert]] Invert the colors of an image.
| [[fun:invert_image]] Invert the colors of an image.
| [[fun:recolor_image]] Change the colors of an image to match the font color.
| [[fun:enlarge]] Enlarge an image by putting a border around it.
| [[fun:crop]] Crop an image, giving only a small subset of it.
| [[fun:flip_horizontal]] Flip an image horizontally.
......
Function: invert
--Usage--
> invert(input: image)
Invert the colors in an image.
--Parameters--
! Parameter Type Description
| @input@ [[type:image]] Image to invert.
--Examples--
> invert("image_logo.png") == [[Image]]
>>> invert(<img src="image_logo.png" alt='"image_logo.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />) == <img src="image_logo_invert.png" alt='"image_logo_invert.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
Function: invert_image
--Usage--
> invert_image(input: image)
Invert the colors in an image.
--Parameters--
! Parameter Type Description
| @input@ [[type:image]] Image to invert.
--Examples--
> invert_image("image_logo.png") == [[Image]]
>>> invert_image(<img src="image_logo.png" alt='"image_logo.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />) == <img src="image_logo_invert.png" alt='"image_logo_invert.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
Function: recolor_image
--Usage--
> recolor_image(input: image, color: color)
Re-color an image:
* Red is replaced by the color
* Green is replaced by black or white, of the same lightness as the color.
So if the color is light, green will be replaced by white.
* Blue is replaced by black or white, of the opposite lightness.
* White stays white, black stays black
This function is mostly intended to make symbols in a symbol font wich can match the text color.
--Parameters--
! Parameter Type Description
| @input@ [[type:image]] Image to recolor.
| @color@ [[type:color]] Color by which to replace red.
--Examples--
> recolor_image("symbol1.png", color: rgb(180,0,0)) == [[Image]]
>>> recolor_image(<img src="symbol1.png" alt='"symbol1.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />, color: rgb(180,0,0)) == <img src="symbol1_red.png" alt='"symbol1_red.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
> recolor_image("symbol1.png", color: rgb(100,255,0)) == [[Image]]
>>> recolor_image(<img src="symbol1.png" alt='"symbol1.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />, color: rgb(100,255,0)) == <img src="symbol1_green.png" alt='"symbol1_green.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
......@@ -159,7 +159,10 @@ RealSize SymbolInFont::size(Package& pkg, double size) {
}
void SymbolInFont::update(Context& ctx) {
image.update(ctx);
if (image.update(ctx)) {
// image has changed, cache is no longer valid
bitmaps.clear();
}
enabled.update(ctx);
if (text_font)
text_font->update(ctx);
......
......@@ -107,19 +107,16 @@ Color saturate(const Color& c, double amount) {
}
void fill_image(Image& image, const Color& color) {
Byte* pos = image.GetData();
Byte* end = pos + image.GetWidth() * image.GetHeight() * 3;
Byte r = color.Red(), g = color.Green(), b = color.Blue();
if (r == g && r == b) {
void fill_image(Image& image, RGB x) {
RGB* pos = (RGB*)image.GetData();
RGB* end = pos + image.GetWidth() * image.GetHeight();
if (x.r == x.g && x.r == x.b) {
// optimization: use memset
memset(pos, r, end-pos);
memset(pos, x.r, (end-pos) * sizeof(*pos));
} else {
// fill the image
while (pos != end) {
*pos++ = r;
*pos++ = g;
*pos++ = b;
*pos++ = x;
}
}
}
......@@ -32,6 +32,53 @@ class AColor : public Color {
inline bool operator != (const AColor& that) const { return ! (*this == that); }
};
// -----------------------------------------------------------------------------
// RGB Color, packed into 3 bytes
// -----------------------------------------------------------------------------
// stupid headers stealing useful names
#undef RGB
// it is important to pack this into 3 bytes, so we can directly convert from wxImage data
#if defined(_MSC_VER)
#pragma pack(push, 1)
#define MAKE_PACKED
#else
#define MAKE_PACKED __attribute__((__packed__))
#endif
/// An RGB triplet, packed into 3 bytes
struct RGB {
Byte r,g,b;
RGB() {}
RGB(Byte x) : r(x), g(x), b(x) {}
RGB(Byte r, Byte g, Byte b) : r(r), g(g), b(b) {}
RGB(wxColour const& x) : r(x.Red()), g(x.Green()), b(x.Blue()) {}
inline int total() { return r+g+b; }
inline operator wxColour() const {
return wxColour(r,g,b);
}
inline bool operator == (RGB const& that) const {
return r == that.r && g == that.g && b == that.b;
}
inline bool operator < (RGB const& that) const {
if (r < that.r) return true;
if (r > that.r) return false;
if (g < that.g) return true;
if (g > that.g) return false;
return b < that.b;
}
} MAKE_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
// ----------------------------------------------------------------------------- : Parsing
/// Parse a color
......@@ -80,13 +127,13 @@ Color saturate(const Color& c, double amount);
* rgb(128,128,0) -> 0.5*cr + 0.5*cg
* rgb(128,0,0) -> 0.5*cr
*/
Color recolor(Color const& c, Color const& cr, Color const& cg, Color const& cb, Color const& cw);
Image recolor(Image const& im, Color const& cr, Color const& cg, Color const& cb, Color const& cw);
RGB recolor(RGB x, RGB cr, RGB cg, RGB cb, RGB cw);
void recolor(Image& img, RGB cr, RGB cg, RGB cb, RGB cw);
/// Like recolor: map green to similar black/white and blue to complementary white/black
Image recolor(Image const& im, Color const& cr);
void recolor(Image& img, RGB cr);
/// Fills an image with the specified color
void fill_image(Image& image, const Color& color);
void fill_image(Image& image, RGB color);
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -208,6 +208,19 @@ bool InvertImage::operator == (const GeneratedImage& that) const {
return that2 && *image == *that2->image;
}
// ----------------------------------------------------------------------------- : RecolorImage
Image RecolorImage::generate(const Options& opt) const {
Image img = image->generate(opt);
recolor(img, color);
return img;
}
bool RecolorImage::operator == (const GeneratedImage& that) const {
const RecolorImage* that2 = dynamic_cast<const RecolorImage*>(&that);
return that2 && *image == *that2->image
&& color == that2->color;
}
// ----------------------------------------------------------------------------- : FlipImage
Image FlipImageHorizontal::generate(const Options& opt) const {
......
......@@ -214,6 +214,20 @@ class InvertImage : public SimpleFilterImage {
virtual bool operator == (const GeneratedImage& that) const;
};
// ----------------------------------------------------------------------------- : RecolorImage
/// Recolor an image
class RecolorImage : public SimpleFilterImage {
public:
inline RecolorImage(const GeneratedImageP& image, Color color)
: SimpleFilterImage(image), color(color)
{}
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
private:
Color color;
};
// ----------------------------------------------------------------------------- : FlipImage
/// Flip an image horizontally
......
......@@ -70,3 +70,43 @@ void invert(Image& img) {
data[i] = 255 - data[i];
}
}
// ----------------------------------------------------------------------------- : Coloring symbol images
RGB recolor(RGB x, RGB cr, RGB cg, RGB cb, RGB cw) {
int lo = min(x.r,min(x.g,x.b));
// amount of each
int nr = x.r - lo;
int ng = x.g - lo;
int nb = x.b - lo;
int nw = lo;
// We should have that nr+ng+bw+nw < 255,
// otherwise the input is not a mixture of red/green/blue/white.
// Just to be sure, divide by the sum instead of 255
int total = max(255, nr+ng+nb+nw);
return RGB(
static_cast<Byte>( (nr * cr.r + ng * cg.r + nb * cb.r + nw * cw.r) / total ),
static_cast<Byte>( (nr * cr.g + ng * cg.g + nb * cb.g + nw * cw.g) / total ),
static_cast<Byte>( (nr * cr.b + ng * cg.b + nb * cb.b + nw * cw.b) / total )
);
}
void recolor(Image& img, RGB cr, RGB cg, RGB cb, RGB cw) {
RGB* data = (RGB*)img.GetData();
int n = img.GetWidth() * img.GetHeight();
for (int i = 0 ; i < n ; ++i) {
data[i] = recolor(data[i], cr, cg, cb, cw);
}
}
Byte to_grayscale(RGB x) {
return (Byte)((6969 * x.r + 23434 * x.g + 2365 * x.b) / 32768); // from libpng
}
void recolor(Image& img, RGB cr) {
RGB black(0,0,0), white(255,255,255);
bool dark = to_grayscale(cr) < 100;
recolor(img, cr, dark ? black : white, dark ? white : black, white);
}
......@@ -3631,6 +3631,9 @@
<File
RelativePath="..\doc\function\index.txt">
</File>
<File
RelativePath="..\doc\function\invert_image.txt">
</File>
<File
RelativePath="..\doc\function\keyword_usage.txt">
</File>
......@@ -3658,6 +3661,9 @@
<File
RelativePath="..\doc\function\process_english_hints.txt">
</File>
<File
RelativePath="..\doc\function\recolor_image.txt">
</File>
<File
RelativePath="..\doc\function\regex_escape.txt">
</File>
......
......@@ -91,6 +91,12 @@ SCRIPT_FUNCTION(invert_image) {
return intrusive(new InvertImage(input));
}
SCRIPT_FUNCTION(recolor_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(Color, color);
return intrusive(new RecolorImage(input,color));
}
SCRIPT_FUNCTION(enlarge) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(double, _("border size"), border_size);
......@@ -212,6 +218,7 @@ void init_script_image_functions(Context& ctx) {
ctx.setVariable(_("set combine"), script_set_combine);
ctx.setVariable(_("saturate"), script_saturate);
ctx.setVariable(_("invert image"), script_invert_image);
ctx.setVariable(_("recolor image"), script_recolor_image);
ctx.setVariable(_("enlarge"), script_enlarge);
ctx.setVariable(_("crop"), script_crop);
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
......
......@@ -36,6 +36,8 @@
#include <set>
using namespace std;
#undef RGB
// ----------------------------------------------------------------------------- : Wx Aliasses
// Remove some of the wxUglyness
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment