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: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:add_stroke_effect]] Add a stroke effect 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: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);
|
||||
// 2. draw potential stroke or shadow
|
||||
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 stroke_radius = lround(font.stroke_radius() * s_scale);
|
||||
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();
|
||||
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
|
||||
Image s_img = make_stroke_image(bmp.ConvertToImage(), font.stroke_color(), stroke_radius, blur_radius);
|
||||
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);
|
||||
dc.DrawImage(s_img, s_pos);
|
||||
}
|
||||
else if (font.hasShadow()) {
|
||||
// add margin
|
||||
Image img = bmp.ConvertToImage();
|
||||
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
|
||||
int blur_radius = lround(font.shadow_blur() * s_scale);
|
||||
Image s_img = make_stroke_image(bmp.ConvertToImage(), font.shadow_color(), 0, blur_radius);
|
||||
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);
|
||||
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));
|
||||
bmp_sizes.push_back(bmp_size);
|
||||
|
||||
@@ -320,6 +320,26 @@ bool ResizeImage::operator == (const GeneratedImage& that) const {
|
||||
&& 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
|
||||
|
||||
Image BleedEdgedImage::generate(const Options& opt) {
|
||||
|
||||
@@ -318,6 +318,23 @@ private:
|
||||
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
|
||||
|
||||
/// Add a crude bleed edge to an image
|
||||
|
||||
@@ -107,6 +107,9 @@ Byte thicken_pixel_alpha_5x5(std::vector<Byte> in, int i, int x, int y, int widt
|
||||
Byte thicken_pixel_alpha_7x7(std::vector<Byte> in, int i, int x, int y, int width, int height);
|
||||
// Thicken the alpha channel of an image
|
||||
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
|
||||
|
||||
|
||||
@@ -360,7 +360,51 @@ void downsample_to_alpha(Bitmap& bmp_in, Image& img_out) {
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -47,40 +47,22 @@ void draw_resampled_text(DC& dc, const String& text, const RealPoint& pos, const
|
||||
downsample_to_alpha(buffer, img);
|
||||
// if there is no stroke effect, just add blur and draw
|
||||
if (stroke_radius == 0) {
|
||||
if (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);
|
||||
if (blur_radius == 0) {
|
||||
if (color.Alpha() != 255) {
|
||||
set_alpha(img, color.Alpha() / 255.);
|
||||
}
|
||||
fill_image(s_img, color);
|
||||
dc.DrawBitmap(s_img, xi-blur_radius, yi-blur_radius);
|
||||
fill_image(img, color);
|
||||
dc.DrawBitmap(img, xi, yi);
|
||||
}
|
||||
else {
|
||||
fill_image(img, color);
|
||||
dc.DrawBitmap(img, xi, yi);
|
||||
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 {
|
||||
int radius = blur_radius + stroke_radius;
|
||||
Image s_img(w + 2*radius, h + 2*radius, false);
|
||||
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);
|
||||
Image s_img = make_stroke_image(img, stroke_color, stroke_radius, blur_radius);
|
||||
if (stroke_color != color) {
|
||||
fill_image(img, color);
|
||||
if (color.Alpha() != 255) {
|
||||
|
||||
@@ -172,6 +172,15 @@ SCRIPT_FUNCTION(enlarge) {
|
||||
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_PARAM_C(GeneratedImageP, input);
|
||||
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(_("recolor_image"), script_recolor_image);
|
||||
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(_("resize_image"), script_resize_image);
|
||||
ctx.setVariable(_("crop"), script_crop);
|
||||
|
||||
@@ -220,8 +220,9 @@ 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) {
|
||||
double s_scale = scale * dc.GetFont().GetPointSize() / text_scaling / 15.;
|
||||
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);
|
||||
if (font.hasShadow() && !font.hasStroke()) {
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user