mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
add 'add_stroke_effect' script function
This commit is contained in:
@@ -91,6 +91,7 @@ These functions are built into the program, other [[type:function]]s can be defi
|
|||||||
| [[fun:recolor_image]] Change the colors of an image to match the font color.
|
| [[fun:recolor_image]] Change the colors of an image to match the font color.
|
||||||
| [[fun:resize_image]] Stretch or squeeze an image to a given height and width.
|
| [[fun:resize_image]] Stretch or squeeze an image to a given height and width.
|
||||||
| [[fun:enlarge]] Enlarge an image by putting a border around it.
|
| [[fun:enlarge]] Enlarge an image by putting a border around it.
|
||||||
|
| [[fun:add_stroke_effect]] Add a stroke effect around an image.
|
||||||
| [[fun:add_bleed_edge]] Add a crude print bleed edge around an image.
|
| [[fun:add_bleed_edge]] Add a crude print bleed edge around an image.
|
||||||
| [[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.
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
Function: add_stroke_effect
|
||||||
|
|
||||||
|
--Usage--
|
||||||
|
> add_stroke_effect(input: image, radius: number, blur: number, color: color)
|
||||||
|
|
||||||
|
Add a stroke effect around an image.
|
||||||
|
|
||||||
|
--Parameters--
|
||||||
|
! Parameter Type Description
|
||||||
|
| @input@ [[type:image]] Image that needs a stroke effect
|
||||||
|
| @radius@ [[type:int]] Size of the stroke, in pixels
|
||||||
|
| @blur@ [[type:int]] Size of the blur of the stroke, in pixels. Optional, defaults to 0
|
||||||
|
| @color@ [[type:color]] Color of the stroke
|
||||||
|
| @include_image@ [[type:boolean]] Draw the original image in the middle of the stroke effect. Optional, defaults to true
|
||||||
|
|
||||||
@@ -301,96 +301,20 @@ void SymbolFont::draw(RotatedDC& dc, RealRect rect, double scale, const SymbolFo
|
|||||||
RealPoint bmp_pos = align_in_rect(font.alignment(), bmp_size, sym_rect);
|
RealPoint bmp_pos = align_in_rect(font.alignment(), bmp_size, sym_rect);
|
||||||
// 2. draw potential stroke or shadow
|
// 2. draw potential stroke or shadow
|
||||||
if (font.hasStroke()) {
|
if (font.hasStroke()) {
|
||||||
// add margin
|
|
||||||
Image img = bmp.ConvertToImage();
|
|
||||||
if (!img.HasAlpha()) set_alpha(img, 0);
|
|
||||||
int blur_radius = lround(font.stroke_blur() * s_scale);
|
int blur_radius = lround(font.stroke_blur() * s_scale);
|
||||||
int stroke_radius = lround(font.stroke_radius() * s_scale);
|
int stroke_radius = lround(font.stroke_radius() * s_scale);
|
||||||
int margin = blur_radius + stroke_radius;
|
Image s_img = make_stroke_image(bmp.ConvertToImage(), font.stroke_color(), stroke_radius, blur_radius);
|
||||||
int s_width = img.GetWidth() + 2 * margin, s_height = img.GetHeight() + 2 * margin;
|
|
||||||
int x_end = s_width - margin;
|
|
||||||
int y_end = s_height - margin;
|
|
||||||
wxImage s_img(s_width, s_height, false);
|
|
||||||
s_img.InitAlpha();
|
|
||||||
// convert to stroke color
|
|
||||||
Byte* s_data = s_img.GetData();
|
|
||||||
Byte* s_alpha = s_img.GetAlpha(), *alpha = img.GetAlpha();
|
|
||||||
Color color = font.stroke_color();
|
|
||||||
unsigned char r = color.Red();
|
|
||||||
unsigned char g = color.Green();
|
|
||||||
unsigned char b = color.Blue();
|
|
||||||
unsigned char a = color.Alpha();
|
|
||||||
for (int y = 0 ; y < s_height ; ++y) {
|
|
||||||
for (int x = 0 ; x < s_width ; ++x) {
|
|
||||||
s_data[0] = r;
|
|
||||||
s_data[1] = g;
|
|
||||||
s_data[2] = b;
|
|
||||||
s_data += 3;
|
|
||||||
if (margin <= x && x < x_end && margin <= y && y < y_end) {
|
|
||||||
s_alpha[0] = alpha[0] * a / 255;
|
|
||||||
alpha += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_alpha[0] = 0;
|
|
||||||
}
|
|
||||||
s_alpha += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add stroke effect
|
|
||||||
for (int i = 0 ; i < stroke_radius ; ++i) {
|
|
||||||
thicken_image_alpha(s_img, 1);
|
|
||||||
}
|
|
||||||
// add blur
|
|
||||||
for (int i = 0 ; i < blur_radius ; ++i) {
|
|
||||||
blur_image_alpha(s_img, 3);
|
|
||||||
}
|
|
||||||
// draw
|
|
||||||
RealSize s_size = dc.trInvS(RealSize(s_img));
|
RealSize s_size = dc.trInvS(RealSize(s_img));
|
||||||
RealPoint s_pos(bmp_pos.x - (s_size.width - bmp_size.width)/2, bmp_pos.y - (s_size.height - bmp_size.height)/2);
|
RealPoint s_pos(bmp_pos.x - (s_size.width - bmp_size.width)/2, bmp_pos.y - (s_size.height - bmp_size.height)/2);
|
||||||
dc.DrawImage(s_img, s_pos);
|
dc.DrawImage(s_img, s_pos);
|
||||||
}
|
}
|
||||||
else if (font.hasShadow()) {
|
else if (font.hasShadow()) {
|
||||||
// add margin
|
int blur_radius = lround(font.shadow_blur() * s_scale);
|
||||||
Image img = bmp.ConvertToImage();
|
Image s_img = make_stroke_image(bmp.ConvertToImage(), font.shadow_color(), 0, blur_radius);
|
||||||
if (!img.HasAlpha()) set_alpha(img, 0);
|
|
||||||
int margin = lround(font.shadow_blur() * s_scale);
|
|
||||||
int s_width = img.GetWidth() + 2 * margin, s_height = img.GetHeight() + 2 * margin;
|
|
||||||
int x_end = s_width - margin;
|
|
||||||
int y_end = s_height - margin;
|
|
||||||
wxImage s_img(s_width, s_height, false);
|
|
||||||
s_img.InitAlpha();
|
|
||||||
// convert to shadow color
|
|
||||||
Byte* s_data = s_img.GetData();
|
|
||||||
Byte* s_alpha = s_img.GetAlpha(), *alpha = img.GetAlpha();
|
|
||||||
Color color = font.shadow_color();
|
|
||||||
unsigned char r = color.Red();
|
|
||||||
unsigned char g = color.Green();
|
|
||||||
unsigned char b = color.Blue();
|
|
||||||
unsigned char a = color.Alpha();
|
|
||||||
for (int y = 0 ; y < s_height ; ++y) {
|
|
||||||
for (int x = 0 ; x < s_width ; ++x) {
|
|
||||||
s_data[0] = r;
|
|
||||||
s_data[1] = g;
|
|
||||||
s_data[2] = b;
|
|
||||||
s_data += 3;
|
|
||||||
if (margin <= x && x < x_end && margin <= y && y < y_end) {
|
|
||||||
s_alpha[0] = alpha[0] * a / 255;
|
|
||||||
alpha += 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_alpha[0] = 0;
|
|
||||||
}
|
|
||||||
s_alpha += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add blur
|
|
||||||
for (int i = 0 ; i < margin ; ++i) {
|
|
||||||
blur_image_alpha(s_img, 3);
|
|
||||||
}
|
|
||||||
// draw
|
|
||||||
RealSize s_size = dc.trInvS(RealSize(s_img));
|
RealSize s_size = dc.trInvS(RealSize(s_img));
|
||||||
RealPoint s_pos(bmp_pos.x - (s_size.width - bmp_size.width)/2, bmp_pos.y - (s_size.height - bmp_size.height)/2);
|
RealPoint s_pos(bmp_pos.x - (s_size.width - bmp_size.width)/2, bmp_pos.y - (s_size.height - bmp_size.height)/2);
|
||||||
dc.DrawImage(s_img, s_pos + RealPoint(font.shadow_displacement_x(), font.shadow_displacement_y()) * scale);
|
RealSize s_displacement = dc.trInvS(RealSize(font.shadow_displacement_x, font.shadow_displacement_y) * s_scale);
|
||||||
|
dc.DrawImage(s_img, s_pos + s_displacement);
|
||||||
}
|
}
|
||||||
bmps.push_back(std::move(bmp));
|
bmps.push_back(std::move(bmp));
|
||||||
bmp_sizes.push_back(bmp_size);
|
bmp_sizes.push_back(bmp_size);
|
||||||
|
|||||||
@@ -320,6 +320,26 @@ bool ResizeImage::operator == (const GeneratedImage& that) const {
|
|||||||
&& height == that2->height;
|
&& height == that2->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : StrokeImage
|
||||||
|
|
||||||
|
Image StrokeImage::generate(const Options& opt) {
|
||||||
|
// create enlarged image
|
||||||
|
Image base_img = base_image->generate(opt);
|
||||||
|
Image s_img = make_stroke_image(base_img, color, radius, blur);
|
||||||
|
if (include_image) {
|
||||||
|
int offset = radius + blur;
|
||||||
|
s_img.Paste(base_img, offset, offset, wxIMAGE_ALPHA_BLEND_COMPOSE);
|
||||||
|
}
|
||||||
|
return s_img;
|
||||||
|
}
|
||||||
|
bool StrokeImage::operator == (const GeneratedImage& that) const {
|
||||||
|
const StrokeImage* that2 = dynamic_cast<const StrokeImage*>(&that);
|
||||||
|
return that2 && *base_image == *that2->base_image
|
||||||
|
&& radius == that2->radius
|
||||||
|
&& blur == that2->blur
|
||||||
|
&& color == that2->color;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : BleedEdgedImage
|
// ----------------------------------------------------------------------------- : BleedEdgedImage
|
||||||
|
|
||||||
Image BleedEdgedImage::generate(const Options& opt) {
|
Image BleedEdgedImage::generate(const Options& opt) {
|
||||||
|
|||||||
@@ -318,6 +318,23 @@ private:
|
|||||||
double offset_x, offset_y;
|
double offset_x, offset_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : StrokeImage
|
||||||
|
|
||||||
|
/// Create a stroke effect that goes around an image
|
||||||
|
class StrokeImage : public GeneratedImage {
|
||||||
|
public:
|
||||||
|
inline StrokeImage(const GeneratedImageP& base_image, int radius, int blur, Color color, bool include_image)
|
||||||
|
: base_image(base_image), radius(radius), blur(blur), color(color), include_image(include_image)
|
||||||
|
{}
|
||||||
|
Image generate(const Options& opt) override;
|
||||||
|
bool operator == (const GeneratedImage& that) const override;
|
||||||
|
private:
|
||||||
|
GeneratedImageP base_image;
|
||||||
|
int radius, blur;
|
||||||
|
Color color;
|
||||||
|
bool include_image;
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : BleedEdgedImage
|
// ----------------------------------------------------------------------------- : BleedEdgedImage
|
||||||
|
|
||||||
/// Add a crude bleed edge to an image
|
/// Add a crude bleed edge to an image
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ Byte thicken_pixel_alpha_7x7(std::vector<Byte> in, int i, int x, int y, int widt
|
|||||||
// Thicken the alpha channel of an image
|
// Thicken the alpha channel of an image
|
||||||
void thicken_image_alpha(Image& img, int radius);
|
void thicken_image_alpha(Image& img, int radius);
|
||||||
|
|
||||||
|
// Create a stroke effect that goes around an image
|
||||||
|
Image make_stroke_image(Image& img, Color stroke_color, int stroke_radius, int blur_radius = 0);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Combining
|
// ----------------------------------------------------------------------------- : Combining
|
||||||
|
|
||||||
/// Ways in which images can be combined, similair to what Photoshop supports
|
/// Ways in which images can be combined, similair to what Photoshop supports
|
||||||
|
|||||||
@@ -362,6 +362,50 @@ void downsample_to_alpha(Bitmap& bmp_in, Image& img_out) {
|
|||||||
delete[] temp;
|
delete[] temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image make_stroke_image(Image& img, Color stroke_color, int stroke_radius, int blur_radius) {
|
||||||
|
stroke_radius = max(0,min(100,stroke_radius));
|
||||||
|
blur_radius = max(0,min(100,blur_radius));
|
||||||
|
if (!img.HasAlpha()) set_alpha(img, 255);
|
||||||
|
int margin = blur_radius + stroke_radius;
|
||||||
|
int s_width = img.GetWidth() + 2 * margin, s_height = img.GetHeight() + 2 * margin;
|
||||||
|
int x_end = s_width - margin;
|
||||||
|
int y_end = s_height - margin;
|
||||||
|
wxImage s_img(s_width, s_height, false);
|
||||||
|
s_img.InitAlpha();
|
||||||
|
// convert to stroke color
|
||||||
|
Byte* s_data = s_img.GetData();
|
||||||
|
Byte* s_alpha = s_img.GetAlpha(), *alpha = img.GetAlpha();
|
||||||
|
unsigned char r = stroke_color.Red();
|
||||||
|
unsigned char g = stroke_color.Green();
|
||||||
|
unsigned char b = stroke_color.Blue();
|
||||||
|
unsigned char a = stroke_color.Alpha();
|
||||||
|
for (int y = 0 ; y < s_height ; ++y) {
|
||||||
|
for (int x = 0 ; x < s_width ; ++x) {
|
||||||
|
s_data[0] = r;
|
||||||
|
s_data[1] = g;
|
||||||
|
s_data[2] = b;
|
||||||
|
s_data += 3;
|
||||||
|
if (margin <= x && x < x_end && margin <= y && y < y_end) {
|
||||||
|
s_alpha[0] = alpha[0] * a / 255;
|
||||||
|
alpha += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_alpha[0] = 0;
|
||||||
|
}
|
||||||
|
s_alpha += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add stroke effect
|
||||||
|
for (int i = 0 ; i < stroke_radius ; ++i) {
|
||||||
|
thicken_image_alpha(s_img, 1);
|
||||||
|
}
|
||||||
|
// add blur
|
||||||
|
for (int i = 0 ; i < blur_radius ; ++i) {
|
||||||
|
blur_image_alpha(s_img, 3);
|
||||||
|
}
|
||||||
|
return s_img;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Coloring symbol images
|
// ----------------------------------------------------------------------------- : Coloring symbol images
|
||||||
|
|
||||||
RGB recolor(RGB x, RGB cr, RGB cg, RGB cb, RGB cw) {
|
RGB recolor(RGB x, RGB cr, RGB cg, RGB cb, RGB cw) {
|
||||||
|
|||||||
@@ -47,40 +47,22 @@ void draw_resampled_text(DC& dc, const String& text, const RealPoint& pos, const
|
|||||||
downsample_to_alpha(buffer, img);
|
downsample_to_alpha(buffer, img);
|
||||||
// if there is no stroke effect, just add blur and draw
|
// if there is no stroke effect, just add blur and draw
|
||||||
if (stroke_radius == 0) {
|
if (stroke_radius == 0) {
|
||||||
|
if (blur_radius == 0) {
|
||||||
if (color.Alpha() != 255) {
|
if (color.Alpha() != 255) {
|
||||||
set_alpha(img, color.Alpha() / 255.);
|
set_alpha(img, color.Alpha() / 255.);
|
||||||
}
|
}
|
||||||
if (blur_radius > 0) {
|
|
||||||
Image s_img(w + 2*blur_radius, h + 2*blur_radius, false);
|
|
||||||
set_alpha(s_img, 0);
|
|
||||||
s_img.Paste(img, blur_radius, blur_radius, wxIMAGE_ALPHA_BLEND_COMPOSE);
|
|
||||||
for (int i = 0 ; i < blur_radius ; ++i) {
|
|
||||||
blur_image_alpha(s_img, 3);
|
|
||||||
}
|
|
||||||
fill_image(s_img, color);
|
|
||||||
dc.DrawBitmap(s_img, xi-blur_radius, yi-blur_radius);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fill_image(img, color);
|
fill_image(img, color);
|
||||||
dc.DrawBitmap(img, xi, yi);
|
dc.DrawBitmap(img, xi, yi);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Image s_img = make_stroke_image(img, color, 0, blur_radius);
|
||||||
|
dc.DrawBitmap(s_img, xi-blur_radius, yi-blur_radius);
|
||||||
}
|
}
|
||||||
// otherwise add stroke effect
|
}
|
||||||
|
// otherwise add stroke effect, add copy of text on top, draw
|
||||||
else {
|
else {
|
||||||
int radius = blur_radius + stroke_radius;
|
int radius = blur_radius + stroke_radius;
|
||||||
Image s_img(w + 2*radius, h + 2*radius, false);
|
Image s_img = make_stroke_image(img, stroke_color, stroke_radius, blur_radius);
|
||||||
set_alpha(s_img, 0);
|
|
||||||
s_img.Paste(img, radius, radius, wxIMAGE_ALPHA_BLEND_COMPOSE);
|
|
||||||
for (int i = 0 ; i < stroke_radius ; ++i) {
|
|
||||||
thicken_image_alpha(s_img, 1);
|
|
||||||
}
|
|
||||||
for (int i = 0 ; i < blur_radius ; ++i) {
|
|
||||||
blur_image_alpha(s_img, 3);
|
|
||||||
}
|
|
||||||
if (stroke_color.Alpha() != 255) {
|
|
||||||
set_alpha(s_img, stroke_color.Alpha() / 255.);
|
|
||||||
}
|
|
||||||
fill_image(s_img, stroke_color);
|
|
||||||
if (stroke_color != color) {
|
if (stroke_color != color) {
|
||||||
fill_image(img, color);
|
fill_image(img, color);
|
||||||
if (color.Alpha() != 255) {
|
if (color.Alpha() != 255) {
|
||||||
|
|||||||
@@ -172,6 +172,15 @@ SCRIPT_FUNCTION(enlarge) {
|
|||||||
return make_intrusive<EnlargeImage>(input, border_size);
|
return make_intrusive<EnlargeImage>(input, border_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCRIPT_FUNCTION(add_stroke_effect) {
|
||||||
|
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||||
|
SCRIPT_PARAM(Color, color);
|
||||||
|
SCRIPT_PARAM(int, radius);
|
||||||
|
SCRIPT_PARAM_DEFAULT(int, blur, 0);
|
||||||
|
SCRIPT_PARAM_DEFAULT(bool, include_image, true);
|
||||||
|
return make_intrusive<StrokeImage>(input, radius, blur, color, include_image);
|
||||||
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(add_bleed_edge) {
|
SCRIPT_FUNCTION(add_bleed_edge) {
|
||||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||||
SCRIPT_PARAM_DEFAULT(double, horizontal_size, -1.0);
|
SCRIPT_PARAM_DEFAULT(double, horizontal_size, -1.0);
|
||||||
@@ -308,6 +317,7 @@ void init_script_image_functions(Context& ctx) {
|
|||||||
ctx.setVariable(_("invert_image"), script_invert_image);
|
ctx.setVariable(_("invert_image"), script_invert_image);
|
||||||
ctx.setVariable(_("recolor_image"), script_recolor_image);
|
ctx.setVariable(_("recolor_image"), script_recolor_image);
|
||||||
ctx.setVariable(_("enlarge"), script_enlarge);
|
ctx.setVariable(_("enlarge"), script_enlarge);
|
||||||
|
ctx.setVariable(_("add_stroke_effect"),script_add_stroke_effect);
|
||||||
ctx.setVariable(_("add_bleed_edge"), script_add_bleed_edge);
|
ctx.setVariable(_("add_bleed_edge"), script_add_bleed_edge);
|
||||||
ctx.setVariable(_("resize_image"), script_resize_image);
|
ctx.setVariable(_("resize_image"), script_resize_image);
|
||||||
ctx.setVariable(_("crop"), script_crop);
|
ctx.setVariable(_("crop"), script_crop);
|
||||||
|
|||||||
@@ -221,7 +221,8 @@ void RotatedDC::DrawText(const String& text, const RealPoint& pos, Color color,
|
|||||||
void RotatedDC::DrawTextWithShadowOrStroke(const String& text, const Font& font, const RealPoint& pos, double scale, double stretch) {
|
void RotatedDC::DrawTextWithShadowOrStroke(const String& text, const Font& font, const RealPoint& pos, double scale, double stretch) {
|
||||||
double s_scale = scale * dc.GetFont().GetPointSize() / text_scaling / 15.;
|
double s_scale = scale * dc.GetFont().GetPointSize() / text_scaling / 15.;
|
||||||
if (font.hasShadow() && !font.hasStroke()) {
|
if (font.hasShadow() && !font.hasStroke()) {
|
||||||
DrawText(text, pos + RealSize(font.shadow_displacement_x, font.shadow_displacement_y) * scale, font.shadow_color, lround(font.shadow_blur * s_scale), Color(0,0,0), 0, stretch);
|
RealSize shadow_displacement = trInvS(RealSize(font.shadow_displacement_x, font.shadow_displacement_y) * s_scale);
|
||||||
|
DrawText(text, pos + shadow_displacement, font.shadow_color, lround(font.shadow_blur * s_scale), Color(0,0,0), 0, stretch);
|
||||||
}
|
}
|
||||||
DrawText(text, pos, font.color, lround(font.stroke_blur * s_scale), font.stroke_color, lround(font.stroke_radius * s_scale), stretch);
|
DrawText(text, pos, font.color, lround(font.stroke_blur * s_scale), font.stroke_color, lround(font.stroke_radius * s_scale), stretch);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user