mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Added 'recolor_image' function
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1473 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -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_alpha]] Change the transparency of an image.
|
||||||
| [[fun:set_combine]] Change how the image should be combined with the background.
|
| [[fun:set_combine]] Change how the image should be combined with the background.
|
||||||
| [[fun:saturate]] Saturate/desaturate an image.
|
| [[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:enlarge]] Enlarge an image by putting a border around it.
|
||||||
| [[fun:crop]] Crop an image, giving only a small subset of it.
|
| [[fun:crop]] Crop an image, giving only a small subset of it.
|
||||||
| [[fun:flip_horizontal]] Flip an image horizontally.
|
| [[fun:flip_horizontal]] Flip an image horizontally.
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
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;" />
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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;" />
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
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) {
|
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);
|
enabled.update(ctx);
|
||||||
if (text_font)
|
if (text_font)
|
||||||
text_font->update(ctx);
|
text_font->update(ctx);
|
||||||
|
|||||||
+6
-9
@@ -107,19 +107,16 @@ Color saturate(const Color& c, double amount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fill_image(Image& image, const Color& color) {
|
void fill_image(Image& image, RGB x) {
|
||||||
Byte* pos = image.GetData();
|
RGB* pos = (RGB*)image.GetData();
|
||||||
Byte* end = pos + image.GetWidth() * image.GetHeight() * 3;
|
RGB* end = pos + image.GetWidth() * image.GetHeight();
|
||||||
Byte r = color.Red(), g = color.Green(), b = color.Blue();
|
if (x.r == x.g && x.r == x.b) {
|
||||||
if (r == g && r == b) {
|
|
||||||
// optimization: use memset
|
// optimization: use memset
|
||||||
memset(pos, r, end-pos);
|
memset(pos, x.r, (end-pos) * sizeof(*pos));
|
||||||
} else {
|
} else {
|
||||||
// fill the image
|
// fill the image
|
||||||
while (pos != end) {
|
while (pos != end) {
|
||||||
*pos++ = r;
|
*pos++ = x;
|
||||||
*pos++ = g;
|
|
||||||
*pos++ = b;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-4
@@ -32,6 +32,53 @@ class AColor : public Color {
|
|||||||
inline bool operator != (const AColor& that) const { return ! (*this == that); }
|
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
|
// ----------------------------------------------------------------------------- : Parsing
|
||||||
|
|
||||||
/// Parse a color
|
/// 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,128,0) -> 0.5*cr + 0.5*cg
|
||||||
* rgb(128,0,0) -> 0.5*cr
|
* rgb(128,0,0) -> 0.5*cr
|
||||||
*/
|
*/
|
||||||
Color recolor(Color const& c, Color const& cr, Color const& cg, Color const& cb, Color const& cw);
|
RGB recolor(RGB x, RGB cr, RGB cg, RGB cb, RGB cw);
|
||||||
Image recolor(Image const& im, Color const& cr, Color const& cg, Color const& cb, Color const& 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
|
/// 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
|
/// Fills an image with the specified color
|
||||||
void fill_image(Image& image, const Color& color);
|
void fill_image(Image& image, RGB color);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -208,6 +208,19 @@ bool InvertImage::operator == (const GeneratedImage& that) const {
|
|||||||
return that2 && *image == *that2->image;
|
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
|
// ----------------------------------------------------------------------------- : FlipImage
|
||||||
|
|
||||||
Image FlipImageHorizontal::generate(const Options& opt) const {
|
Image FlipImageHorizontal::generate(const Options& opt) const {
|
||||||
|
|||||||
@@ -214,6 +214,20 @@ class InvertImage : public SimpleFilterImage {
|
|||||||
virtual bool operator == (const GeneratedImage& that) const;
|
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
|
// ----------------------------------------------------------------------------- : FlipImage
|
||||||
|
|
||||||
/// Flip an image horizontally
|
/// Flip an image horizontally
|
||||||
|
|||||||
@@ -70,3 +70,43 @@ void invert(Image& img) {
|
|||||||
data[i] = 255 - data[i];
|
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
|
<File
|
||||||
RelativePath="..\doc\function\index.txt">
|
RelativePath="..\doc\function\index.txt">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\doc\function\invert_image.txt">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\doc\function\keyword_usage.txt">
|
RelativePath="..\doc\function\keyword_usage.txt">
|
||||||
</File>
|
</File>
|
||||||
@@ -3658,6 +3661,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\doc\function\process_english_hints.txt">
|
RelativePath="..\doc\function\process_english_hints.txt">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\doc\function\recolor_image.txt">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\doc\function\regex_escape.txt">
|
RelativePath="..\doc\function\regex_escape.txt">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@@ -91,6 +91,12 @@ SCRIPT_FUNCTION(invert_image) {
|
|||||||
return intrusive(new InvertImage(input));
|
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_FUNCTION(enlarge) {
|
||||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||||
SCRIPT_PARAM_N(double, _("border size"), border_size);
|
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(_("set combine"), script_set_combine);
|
||||||
ctx.setVariable(_("saturate"), script_saturate);
|
ctx.setVariable(_("saturate"), script_saturate);
|
||||||
ctx.setVariable(_("invert image"), script_invert_image);
|
ctx.setVariable(_("invert image"), script_invert_image);
|
||||||
|
ctx.setVariable(_("recolor image"), script_recolor_image);
|
||||||
ctx.setVariable(_("enlarge"), script_enlarge);
|
ctx.setVariable(_("enlarge"), script_enlarge);
|
||||||
ctx.setVariable(_("crop"), script_crop);
|
ctx.setVariable(_("crop"), script_crop);
|
||||||
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
|
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#undef RGB
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Wx Aliasses
|
// ----------------------------------------------------------------------------- : Wx Aliasses
|
||||||
|
|
||||||
// Remove some of the wxUglyness
|
// Remove some of the wxUglyness
|
||||||
|
|||||||
Reference in New Issue
Block a user