mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-11 13:17:00 -04:00
implemented more image related functions
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@59 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+4
-5
@@ -46,11 +46,10 @@ IMPLEMENT_REFLECTION(Set) {
|
|||||||
if (tag.reading()) {
|
if (tag.reading()) {
|
||||||
data.init(game->set_fields);
|
data.init(game->set_fields);
|
||||||
}
|
}
|
||||||
WITH_DYNAMIC_ARG(game_for_reading, game.get()) {
|
WITH_DYNAMIC_ARG(game_for_reading, game.get());
|
||||||
REFLECT(stylesheet);
|
REFLECT(stylesheet);
|
||||||
REFLECT_N("set_info", data);
|
REFLECT_N("set_info", data);
|
||||||
REFLECT(cards);
|
REFLECT(cards);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
REFLECT(apprentice_code);
|
REFLECT(apprentice_code);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <gfx/gfx.hpp>
|
||||||
|
#include <util/error.hpp>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Linear Blend
|
||||||
|
|
||||||
|
// sqr(x) = x^2
|
||||||
|
template <typename T> inline T sqr(T x) { return x * x; }
|
||||||
|
|
||||||
|
void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2,double y2) {
|
||||||
|
int width = img1.GetWidth(), height = img1.GetHeight();
|
||||||
|
if (img2.GetWidth() != width || img2.GetHeight() != height) {
|
||||||
|
throw Error(_("Images used for blending must have the same size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const int fixed = 1<<16; // fixed point multiplier
|
||||||
|
// equation:
|
||||||
|
// x * xm + y * ym + d == fixed * f(x,y)
|
||||||
|
// xm and ym are multiples of delta x/y:
|
||||||
|
// xm = a w (x2-x1); ym = a h (y2-y1)
|
||||||
|
// known values
|
||||||
|
// f(x1*w, y1*h) = 0
|
||||||
|
// f(x2*w, y2*h) = 1
|
||||||
|
// filling in:
|
||||||
|
// x1 * w * a * w * (x2-x1) + y1 * h * a * h * (y2-y1) + d == 0
|
||||||
|
// x2 * w * a * w * (x2-x1) + y2 * h * a * h * (y2-y1) + d == fixed
|
||||||
|
// solving for a and d:
|
||||||
|
// (using dx = x1-x2, dy = y1-y2)
|
||||||
|
// a = fixed / (w^2 dx^2 + h^2 dy^2)
|
||||||
|
// d = a * (w^2 x1 dx + h^2 y1 dy)
|
||||||
|
if (x1==x2 && y1==y2) throw Error(_("Coordinates for blending overlap"));
|
||||||
|
double a = fixed / (sqr(width) * sqr(x1-x2) + sqr(height) * sqr(y1-y2));
|
||||||
|
int xm = (x2 - x1) * width * a;
|
||||||
|
int ym = (y2 - y1) * height * a;
|
||||||
|
int d = - (x1 * width * xm + y1 * width * ym);
|
||||||
|
|
||||||
|
Byte *data1 = img1.GetData(), *data2 = img2.GetData();
|
||||||
|
// blend pixels
|
||||||
|
for (int y = 0 ; y < height ; ++y) {
|
||||||
|
for (int x = 0 ; x < width ; ++x) {
|
||||||
|
int mult = x * xm + y * ym + d;
|
||||||
|
if (mult < 0) mult = 0;
|
||||||
|
if (mult > fixed) mult = fixed;
|
||||||
|
data1[0] = data1[0] + mult * (data2[0] - data1[0]) / fixed;
|
||||||
|
data1[1] = data1[1] + mult * (data2[1] - data1[1]) / fixed;
|
||||||
|
data1[2] = data1[2] + mult * (data2[2] - data1[2]) / fixed;
|
||||||
|
data1 += 3;
|
||||||
|
data2 += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Mask Blend
|
||||||
|
|
||||||
|
void mask_blend(Image& img1, const Image& img2, const Image& mask) {
|
||||||
|
if (img2.GetWidth() != img1.GetWidth() || img2.GetHeight() != img1.GetHeight()
|
||||||
|
|| mask.GetWidth() != img1.GetWidth() || mask.GetHeight() != img1.GetHeight()) {
|
||||||
|
throw Error(_("Images used for blending must have the same size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt size = img1.GetWidth() * img1.GetHeight() * 3;
|
||||||
|
Byte *data1 = img1.GetData(), *data2 = img2.GetData(), *dataM = mask.GetData();
|
||||||
|
// for each subpixel...
|
||||||
|
for (UInt i = 0 ; i < size ; ++i) {
|
||||||
|
data1[i] = (data1[i] * dataM[i] + data2[i] * (255 - dataM[i])) / 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Alpha
|
||||||
|
|
||||||
|
void set_alpha(Image& img, const Image& img_alpha) {
|
||||||
|
if (img.GetWidth() != img_alpha.GetWidth() || img.GetHeight() != img_alpha.GetHeight()) {
|
||||||
|
throw InternalError(_("Image used with maks must have same size as mask"));
|
||||||
|
}
|
||||||
|
if (!img.HasAlpha()) img.InitAlpha();
|
||||||
|
Byte *im = img.GetAlpha(), *al = img_alpha.GetData();
|
||||||
|
UInt size = img.GetWidth() * img.GetHeight();
|
||||||
|
for (UInt i = 0 ; i < size ; ++i) {
|
||||||
|
im[i] = (im[i] * al[i*3]) / 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,9 +6,8 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include "../util/prec.hpp"
|
#include <gfx/gfx.hpp>
|
||||||
#include "../util/reflect.hpp"
|
#include <util/reflect.hpp>
|
||||||
#include "gfx.hpp"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|||||||
+13
-18
@@ -19,23 +19,11 @@
|
|||||||
// ----------------------------------------------------------------------------- : Resampling
|
// ----------------------------------------------------------------------------- : Resampling
|
||||||
|
|
||||||
/// Resample (resize) an image, uses bilenear filtering
|
/// Resample (resize) an image, uses bilenear filtering
|
||||||
/** The algorithm first resizes in horizontally, then vertically,
|
void resample(const Image& img_in, Image& img_out);
|
||||||
* the two passes are essentially the same:
|
|
||||||
* - for each row:
|
|
||||||
* - each input pixel becomes a fixed amount of output (in 1<<shift fixed point math)
|
|
||||||
* - for each output pixel:
|
|
||||||
* - 'eat' input pixels until the total is 1<<shift
|
|
||||||
* - write the total to the output pixel
|
|
||||||
* - to ensure the sum of all the pixel amounts is exacly width<<shift an extra rest amount
|
|
||||||
* is 'eaten' from the first pixel
|
|
||||||
*
|
|
||||||
* Uses fixed point numbers internally
|
|
||||||
*/
|
|
||||||
void resample(const Image& imgIn, Image& imgOut);
|
|
||||||
|
|
||||||
/// Resamples an image, first clips the input image to a specified rectangle,
|
/// Resamples an image, first clips the input image to a specified rectangle
|
||||||
/// that rectangle is resampledinto the entire output image
|
/** The selected rectangle is resampled into the entire output image */
|
||||||
void resample_and_clip(const Image& imgIn, Image& imgOut, wxRect rect);
|
void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect);
|
||||||
|
|
||||||
/// How to preserve the aspect ratio of an image when rescaling
|
/// How to preserve the aspect ratio of an image when rescaling
|
||||||
enum PreserveAspect
|
enum PreserveAspect
|
||||||
@@ -44,6 +32,8 @@ enum PreserveAspect
|
|||||||
, ASPECT_FIT ///< generate a smaller image if needed
|
, ASPECT_FIT ///< generate a smaller image if needed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Resample an image, but preserve the aspect ratio by adding a transparent border around the output if needed.
|
||||||
|
void resample_preserve_aspect(const Image& img_in, Image& img_out);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Image rotation
|
// ----------------------------------------------------------------------------- : Image rotation
|
||||||
|
|
||||||
@@ -67,8 +57,13 @@ void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2
|
|||||||
*/
|
*/
|
||||||
void mask_blend(Image& img1, const Image& img2, const Image& mask);
|
void mask_blend(Image& img1, const Image& img2, const Image& mask);
|
||||||
|
|
||||||
/// Use the red channel of img2 as alpha channel for img1
|
/// Use the red channel of img_alpha as alpha channel for img
|
||||||
void set_alpha(Image& img1, const Image& img2);
|
void set_alpha(Image& img, const Image& img_alpha);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Effects
|
||||||
|
|
||||||
|
/// Saturate an image, amount should be in range [0...100]
|
||||||
|
void saturate(Image& image, int amount);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Combining
|
// ----------------------------------------------------------------------------- : Combining
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <gfx/gfx.hpp>
|
||||||
|
#include <util/error.hpp>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Saturation
|
||||||
|
|
||||||
|
void saturate(Image& image, int amount) {
|
||||||
|
if (amount == 0) return; // nothing to do
|
||||||
|
int factor = 300 / amount;
|
||||||
|
int div = factor - 2;
|
||||||
|
// for each pixel...
|
||||||
|
Byte* pix = image.GetData();
|
||||||
|
Byte* end = pix + image.GetWidth() * image.GetHeight() * 3;
|
||||||
|
while (pix != end) {
|
||||||
|
int r = pix[0], g = pix[1], b = pix[2];
|
||||||
|
int r2 = (factor * r - g - b) / div;
|
||||||
|
int g2 = (factor * g - r - b) / div;
|
||||||
|
int b2 = (factor * b - r - g) / div;
|
||||||
|
pix[0] = col(r2);
|
||||||
|
pix[1] = col(g2);
|
||||||
|
pix[2] = col(b2);
|
||||||
|
pix += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <gfx/gfx.hpp>
|
||||||
|
#include <util/error.hpp>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Resample passes
|
||||||
|
|
||||||
|
// bitshift for fixed point numbers
|
||||||
|
// higher is less error
|
||||||
|
// we will get errors if 2^shift * imagesize becomes too large
|
||||||
|
const int shift = 32-10-8; // => max size = 1024, max alpha = 255
|
||||||
|
|
||||||
|
// Resample an image only in a single direction, either horizontally or vertically
|
||||||
|
/* Terms are based on x resampling (keeping the same number of lines):
|
||||||
|
* offset = number of elements to skip at the start
|
||||||
|
* length = length of a line
|
||||||
|
* delta = number of elements between pixels in a lines
|
||||||
|
* lines = number of lines
|
||||||
|
* line_delta = number of elements between the the first pixel of two lines
|
||||||
|
* 1 element = 3 bytes in data, 1 byte in alpha
|
||||||
|
*/
|
||||||
|
void resample_pass(const Image& img_in, Image& img_out, int offset_in, int offset_out,
|
||||||
|
int length_in, int delta_in, int length_out, int delta_out,
|
||||||
|
int lines, int line_delta_in, int line_delta_out)
|
||||||
|
{
|
||||||
|
bool alpha = img_in.HasAlpha();
|
||||||
|
if (alpha) img_out.InitAlpha();
|
||||||
|
int out_fact = (length_out << shift) / length_in; // how much to output for 256 input = 1 pixel
|
||||||
|
int out_rest = (length_out << shift) % length_in;
|
||||||
|
// for each line
|
||||||
|
for (int l = 0 ; l < lines ; ++l) {
|
||||||
|
Byte* in = img_in .GetData() + 3 * (offset_in + line_delta_in);
|
||||||
|
Byte* out = img_out.GetData() + 3 * (offset_out + line_delta_out);
|
||||||
|
UInt in_rem = out_fact + out_rest; // remaining to input from the current input pixel
|
||||||
|
|
||||||
|
if (alpha) {
|
||||||
|
Byte* in_a = img_in .GetAlpha() + (offset_in + line_delta_in);
|
||||||
|
Byte* out_a = img_out.GetAlpha() + (offset_out + line_delta_out);
|
||||||
|
|
||||||
|
for (int x = 0 ; x < length_out ; ++x) {
|
||||||
|
UInt out_rem = 1 << shift;
|
||||||
|
UInt totR = 0, totG = 0, totB = 0, totA = 0;
|
||||||
|
while (out_rem >= in_rem) {
|
||||||
|
// eat a whole input pixel
|
||||||
|
totR += in[0] * in_rem * in_a[0]; // multiply by alpha
|
||||||
|
totG += in[1] * in_rem * in_a[0];
|
||||||
|
totB += in[2] * in_rem * in_a[0];
|
||||||
|
totA += in_a[0] * in_rem;
|
||||||
|
out_rem -= in_rem;
|
||||||
|
in_rem = out_fact;
|
||||||
|
in += 3*delta_in; in_a += delta_in;
|
||||||
|
}
|
||||||
|
if (out_rem > 0) {
|
||||||
|
// eat a partial input pixel
|
||||||
|
totR += in[0] * out_rem * in_a[0];
|
||||||
|
totG += in[1] * out_rem * in_a[0];
|
||||||
|
totB += in[2] * out_rem * in_a[0];
|
||||||
|
totA += in_a[0] * out_rem;
|
||||||
|
in_rem -= out_rem;
|
||||||
|
}
|
||||||
|
// store
|
||||||
|
if (totA) {
|
||||||
|
out[0] = totR / totA;
|
||||||
|
out[1] = totG / totA;
|
||||||
|
out[2] = totB / totA;
|
||||||
|
out_a[0] = totA >> shift;
|
||||||
|
} else {
|
||||||
|
out[0] = out[1] = out[2] = out_a[0] = 0; // div by 0 is bad
|
||||||
|
}
|
||||||
|
out += 3*delta_out; out_a += delta_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// no alpha
|
||||||
|
for (int x = 0 ; x < length_out ; ++x) {
|
||||||
|
UInt out_rem = 1 << shift;
|
||||||
|
UInt totR = 0, totG = 0, totB = 0;
|
||||||
|
while (out_rem >= in_rem) {
|
||||||
|
// eat a whole input pixel
|
||||||
|
totR += in[0] * in_rem;
|
||||||
|
totG += in[1] * in_rem;
|
||||||
|
totB += in[2] * in_rem;
|
||||||
|
out_rem -= in_rem;
|
||||||
|
in_rem = out_fact;
|
||||||
|
in += 3*delta_in;
|
||||||
|
}
|
||||||
|
if (out_rem > 0) {
|
||||||
|
// eat a partial input pixel
|
||||||
|
totR += in[0] * out_rem;
|
||||||
|
totR += in[1] * out_rem;
|
||||||
|
totR += in[2] * out_rem;
|
||||||
|
in_rem -= out_rem;
|
||||||
|
}
|
||||||
|
// store
|
||||||
|
out[0] = totR >> shift;
|
||||||
|
out[1] = totG >> shift;
|
||||||
|
out[2] = totB >> shift;
|
||||||
|
out += 3*delta_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Resample
|
||||||
|
|
||||||
|
/* The algorithm first resizes in horizontally, then vertically,
|
||||||
|
* the two passes are essentially the same:
|
||||||
|
* - for each row:
|
||||||
|
* - each input pixel becomes a fixed amount of output (in 1<<shift fixed point math)
|
||||||
|
* - for each output pixel:
|
||||||
|
* - _('eat') input pixels until the total is 1<<shift
|
||||||
|
* - write the total to the output pixel
|
||||||
|
* - to ensure the sum of all the pixel amounts is exacly width<<shift an extra rest amount
|
||||||
|
* is _('eaten') from the first pixel;
|
||||||
|
*
|
||||||
|
* Uses fixed point numbers
|
||||||
|
*/
|
||||||
|
void resample(const Image& img_in, Image& img_out) {
|
||||||
|
resample_and_clip(img_in, img_out, wxRect(0, 0, img_in.GetWidth(), img_in.GetHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect) {
|
||||||
|
// starting position in data
|
||||||
|
int offset_in = (rect.x + img_in.GetWidth() * rect.y);
|
||||||
|
if (img_out.GetHeight() == rect.height) {
|
||||||
|
// no resizing vertically
|
||||||
|
resample_pass(img_in, img_out, offset_in, 0, rect.width, 1, img_out .GetWidth(), 1, rect .GetHeight(), img_in.GetWidth(), img_out .GetWidth());
|
||||||
|
} else {
|
||||||
|
Image img_temp(img_out.GetWidth(), rect.height, false);
|
||||||
|
resample_pass(img_in, img_temp, offset_in, 0, rect.width, 1, img_temp.GetWidth(), 1, rect .GetHeight(), img_in.GetWidth(), img_temp.GetWidth());
|
||||||
|
resample_pass(img_temp, img_out, 0, 0, rect.height, img_temp.GetWidth(), img_out .GetHeight(), img_temp.GetWidth(), img_temp.GetWidth(), 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Aspect ratio preserving
|
||||||
|
|
||||||
|
// fill an image with 100% transparent
|
||||||
|
void fill_transparent(Image& img) {
|
||||||
|
if (!img.HasAlpha()) img.InitAlpha();
|
||||||
|
memset(img.GetAlpha(), 0, img.GetWidth() * img.GetHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
void resample_preserve_aspect(const Image& img_in, Image& img_out) {
|
||||||
|
int rheight = img_in.GetHeight() * img_out.GetWidth() / img_in.GetWidth();
|
||||||
|
int rwidth = img_in.GetWidth() * img_out.GetHeight() / img_in.GetHeight();
|
||||||
|
// actual size of output
|
||||||
|
if (rheight < img_out.GetHeight()) rwidth = img_out.GetWidth();
|
||||||
|
else if (rwidth < img_out.GetWidth()) rheight = img_out.GetHeight();
|
||||||
|
else {rwidth = img_out.GetWidth(); rheight = img_out.GetHeight();}
|
||||||
|
int dx = (img_out.GetWidth() - rwidth) / 2;
|
||||||
|
int dy = (img_out.GetHeight() - rheight) / 2;
|
||||||
|
// transparent background
|
||||||
|
fill_transparent(img_out);
|
||||||
|
// resample
|
||||||
|
int offset_out = dx + img_out.GetWidth() * dy;
|
||||||
|
Image img_temp(rwidth, img_in.GetHeight(), false);
|
||||||
|
resample_pass(img_in, img_temp, 0, 0, img_in.GetWidth(), 1, rwidth, 1, img_in.GetHeight(), img_in.GetWidth(), img_temp.GetWidth());
|
||||||
|
resample_pass(img_temp, img_out, 0, offset_out, img_in.GetHeight(), img_temp.GetWidth(), rheight, img_out.GetWidth(), rwidth, 1, 1);
|
||||||
|
}
|
||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include "../util/prec.hpp"
|
#include <gfx/gfx.hpp>
|
||||||
#include "gfx.hpp"
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Implementation
|
// ----------------------------------------------------------------------------- : Implementation
|
||||||
|
|
||||||
|
|||||||
@@ -1052,6 +1052,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\bezier.hpp">
|
RelativePath=".\gfx\bezier.hpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\gfx\blend_image.cpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\combine_image.cpp">
|
RelativePath=".\gfx\combine_image.cpp">
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
@@ -1070,12 +1073,18 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\gfx.hpp">
|
RelativePath=".\gfx\gfx.hpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\gfx\image_effects.cpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\polynomial.cpp">
|
RelativePath=".\gfx\polynomial.cpp">
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\polynomial.hpp">
|
RelativePath=".\gfx\polynomial.hpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\gfx\resample_image.cpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\gfx\resample_text.cpp">
|
RelativePath=".\gfx\resample_text.cpp">
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
|
|||||||
+56
-1
@@ -56,11 +56,62 @@ bool script_image_up_to_date(const ScriptValueP& value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||||
|
|
||||||
|
ScriptImageP ScriptableImage::generate(Context& ctx) const {
|
||||||
|
try {
|
||||||
|
ScriptImageP img = to_script_image(script.invoke(ctx));
|
||||||
|
return img;
|
||||||
|
} catch (Error e) {
|
||||||
|
// loading images can fail
|
||||||
|
// it is likely we are inside a paint function or outside the main thread, handle error later
|
||||||
|
handle_error(e, false, false);
|
||||||
|
return new_intrusive1<ScriptImage>(Image(1,1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptImageP ScriptableImage::generate(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) const {
|
||||||
|
ScriptImageP image = generate(ctx);
|
||||||
|
if (!image->image.Ok()) {
|
||||||
|
// return an image so we don't fail
|
||||||
|
image->image = Image(1,1);
|
||||||
|
}
|
||||||
|
UInt iw = image->image.GetWidth(), ih = image->image.GetHeight();
|
||||||
|
if ((iw == width && ih == height) || width == 0) {
|
||||||
|
// already the right size
|
||||||
|
} else if (preserve_aspect == ASPECT_FIT) {
|
||||||
|
// determine actual size of resulting image
|
||||||
|
UInt w, h;
|
||||||
|
if (iw * height > ih * width) { // too much height requested
|
||||||
|
w = width;
|
||||||
|
h = width * ih / iw;
|
||||||
|
} else {
|
||||||
|
w = height * iw / ih;
|
||||||
|
h = height;
|
||||||
|
}
|
||||||
|
Image resampled_image(w, h, false);
|
||||||
|
resample(image->image, resampled_image);
|
||||||
|
image->image = resampled_image;
|
||||||
|
} else {
|
||||||
|
Image resampled_image(width, height, false);
|
||||||
|
if (preserve_aspect == ASPECT_BORDER && (width < height * 3) && (height < width * 3)) {
|
||||||
|
// preserve the aspect ratio if there is not too much difference
|
||||||
|
resample_preserve_aspect(image->image, resampled_image);
|
||||||
|
} else {
|
||||||
|
resample(image->image, resampled_image);
|
||||||
|
}
|
||||||
|
image->image = resampled_image;
|
||||||
|
}
|
||||||
|
if (saturate) {
|
||||||
|
::saturate(image->image, 40);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
ScriptImageP ScriptableImage::update(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) {
|
ScriptImageP ScriptableImage::update(Context& ctx, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) {
|
||||||
// up to date?
|
// up to date?
|
||||||
if (!cache || (UInt)cache->image.GetWidth() != width || (UInt)cache->image.GetHeight() == height) {
|
if (!cache || (UInt)cache->image.GetWidth() != width || (UInt)cache->image.GetHeight() == height || !upToDate(ctx, last_update)) {
|
||||||
// cache must be updated
|
// cache must be updated
|
||||||
cache = generate(ctx, width, height, preserve_aspect, saturate);
|
cache = generate(ctx, width, height, preserve_aspect, saturate);
|
||||||
last_update.update();
|
last_update.update();
|
||||||
@@ -68,6 +119,10 @@ ScriptImageP ScriptableImage::update(Context& ctx, UInt width, UInt height, Pres
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScriptableImage::upToDate(Context& ctx, Age age) const {
|
||||||
|
WITH_DYNAMIC_ARG(last_update_age, age.get());
|
||||||
|
return (int)*script.invoke(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reflection
|
// ----------------------------------------------------------------------------- : Reflection
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ class Age {
|
|||||||
/// Compare two ages, smaller means earlier
|
/// Compare two ages, smaller means earlier
|
||||||
inline bool operator < (Age a) const { return age < a.age; }
|
inline bool operator < (Age a) const { return age < a.age; }
|
||||||
|
|
||||||
|
/// A number corresponding to the age
|
||||||
|
inline LONG get() const { return age; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// This age
|
/// This age
|
||||||
LONG age;
|
LONG age;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
/// Declare a dynamic argument.
|
/// Declare a dynamic argument.
|
||||||
/** The value of the argument can be got with: name()
|
/** The value of the argument can be got with: name()
|
||||||
* To change the value use WITH_DYNAMIC_ARG(name, newValue) { ... }
|
* To change the value use WITH_DYNAMIC_ARG(name, newValue)
|
||||||
* To be used in a header file. Use IMPLEMENT_DYN_ARG in a source file
|
* To be used in a header file. Use IMPLEMENT_DYN_ARG in a source file
|
||||||
*/
|
*/
|
||||||
#define DECLARE_DYNAMIC_ARG(Type, name) \
|
#define DECLARE_DYNAMIC_ARG(Type, name) \
|
||||||
@@ -42,7 +42,6 @@
|
|||||||
inline ~name##_changer() { \
|
inline ~name##_changer() { \
|
||||||
name##_private = oldValue; \
|
name##_private = oldValue; \
|
||||||
} \
|
} \
|
||||||
inline operator bool() { return true; } \
|
|
||||||
private: \
|
private: \
|
||||||
Type oldValue; \
|
Type oldValue; \
|
||||||
}
|
}
|
||||||
@@ -55,14 +54,15 @@
|
|||||||
/** Usage:
|
/** Usage:
|
||||||
* @code
|
* @code
|
||||||
* // here name() == old value
|
* // here name() == old value
|
||||||
* WITH_DYNAMIC_ARG(name, newValue) {
|
* {
|
||||||
|
* WITH_DYNAMIC_ARG(name, newValue);
|
||||||
* // here name() == newValue
|
* // here name() == newValue
|
||||||
* }
|
* }
|
||||||
* // here name() == old value
|
* // here name() == old value
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define WITH_DYNAMIC_ARG(name, value) \
|
#define WITH_DYNAMIC_ARG(name, value) \
|
||||||
if (name##_changer name##_dummmy = value) // hack: variable in if guard scopes over the following block
|
name##_changer name##_dummmy(value)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user