Commit 8dbfb426 authored by twanvl's avatar twanvl

Added saturate script function (+documentation), it also desaturates

parent ef33e93c
......@@ -67,7 +67,8 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:combine_blend]] Blend two images together using a given [[type:combine|combining mode]].
| [[fun:set_mask]] Set the transparancy mask of an image.
| [[fun:set_alpha]] Change the transparency of an image.
| [[fun:set_combine]] Chnage 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:enlarge]] Enlarge an image by putting a border around it.
| [[fun:crop]] Crop an image, giving only a small subset of it.
| [[fun:drop_shadow]] Add a drop shadow to an image.
......
Function: saturate
--Usage--
> saturate(input: image, amount: saturation amount)
Saturate or desaturate an image. Saturation makes the colors brighter, desaturation makes the image more grey.
To saturate use an amount between @0@ (no saturation) and @1@ (super crazy, too much saturation).
To desaturate use an amount between @0@ (no desaturation) and @-1@ (convert to greyscale).
--Parameters--
! Parameter Type Description
| @input@ [[type:image]] Image to (de)saturate.
| @alpha@ [[type:double]] Saturation factor.
--Examples--
> saturate("image5.png", amount: 0.5) == [[Image]]
>>> saturate(<img src="image5.png" alt='"image5.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />, amount: 0.5) == <img src="image_saturate1.png" alt='"image_saturate1.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
> saturate("image5.png", amount: -0.5) == [[Image]]
>>> saturate(<img src="image5.png" alt='"image5.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />, amount: -0.5) == <img src="image_saturate2.png" alt='"image_saturate2.png"' style="border:1px solid black;vertical-align:middle;margin:1px;" />
......@@ -74,7 +74,7 @@ Image conform_image(const Image& img, const GeneratedImage::Options& options) {
}
// saturate?
if (options.saturate) {
saturate(image, 40);
saturate(image, .1);
}
options.width = image.GetWidth();
options.height = image.GetHeight();
......@@ -159,9 +159,6 @@ Image SetMaskImage::generate(const Options& opt) const {
set_alpha(img, mask->generate(opt));
return img;
}
ImageCombine SetMaskImage::combine() const {
return image->combine();
}
bool SetMaskImage::operator == (const GeneratedImage& that) const {
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
return that2 && *image == *that2->image
......@@ -173,9 +170,6 @@ Image SetAlphaImage::generate(const Options& opt) const {
set_alpha(img, alpha);
return img;
}
ImageCombine SetAlphaImage::combine() const {
return image->combine();
}
bool SetAlphaImage::operator == (const GeneratedImage& that) const {
const SetAlphaImage* that2 = dynamic_cast<const SetAlphaImage*>(&that);
return that2 && *image == *that2->image
......@@ -196,6 +190,19 @@ bool SetCombineImage::operator == (const GeneratedImage& that) const {
&& image_combine == that2->image_combine;
}
// ----------------------------------------------------------------------------- : SaturateImage
Image SaturateImage::generate(const Options& opt) const {
Image img = image->generate(opt);
saturate(img, amount);
return img;
}
bool SaturateImage::operator == (const GeneratedImage& that) const {
const SaturateImage* that2 = dynamic_cast<const SaturateImage*>(&that);
return that2 && *image == *that2->image
&& amount == that2->amount;
}
// ----------------------------------------------------------------------------- : EnlargeImage
Image EnlargeImage::generate(const Options& opt) const {
......
......@@ -66,6 +66,20 @@ class GeneratedImage : public ScriptValue {
/// Resize an image to conform to the options
Image conform_image(const Image&, const GeneratedImage::Options&);
// ----------------------------------------------------------------------------- : SimpleFilterImage
/// Apply some filter to a single image
class SimpleFilterImage : public GeneratedImage {
public:
inline SimpleFilterImage(const GeneratedImageP& image)
: image(image)
{}
virtual ImageCombine combine() const { return image->combine(); }
virtual bool local() const { return image->local(); }
protected:
GeneratedImageP image;
};
// ----------------------------------------------------------------------------- : BlankImage
/// An image generator that returns a blank image
......@@ -133,51 +147,59 @@ class CombineBlendImage : public GeneratedImage {
// ----------------------------------------------------------------------------- : SetMaskImage
/// Change the alpha channel of an image
class SetMaskImage : public GeneratedImage {
class SetMaskImage : public SimpleFilterImage {
public:
inline SetMaskImage(const GeneratedImageP& image, const GeneratedImageP& mask)
: image(image), mask(mask)
: SimpleFilterImage(image), mask(mask)
{}
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local() && mask->local(); }
private:
GeneratedImageP image, mask;
GeneratedImageP mask;
};
/// Change the alpha channel of an image
class SetAlphaImage : public GeneratedImage {
class SetAlphaImage : public SimpleFilterImage {
public:
inline SetAlphaImage(const GeneratedImageP& image, double alpha)
: image(image), alpha(alpha)
: SimpleFilterImage(image), alpha(alpha)
{}
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
double alpha;
};
// ----------------------------------------------------------------------------- : SetCombineImage
/// Change the combine mode
class SetCombineImage : public GeneratedImage {
class SetCombineImage : public SimpleFilterImage {
public:
inline SetCombineImage(const GeneratedImageP& image, ImageCombine image_combine)
: image(image), image_combine(image_combine)
: SimpleFilterImage(image), image_combine(image_combine)
{}
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
ImageCombine image_combine;
};
// ----------------------------------------------------------------------------- : SaturateImage
/// Saturate/desaturate an image
class SaturateImage : public SimpleFilterImage {
public:
inline SaturateImage(const GeneratedImageP& image, double alpha)
: SimpleFilterImage(image), amount(amount)
{}
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
private:
GeneratedImageP image;
double amount;
};
// ----------------------------------------------------------------------------- : EnlargeImage
/// Enlarge an image by adding a border around it
......
......@@ -92,11 +92,8 @@ void mask_blend(Image& img1, const Image& img2, const Image& mask);
// ----------------------------------------------------------------------------- : Effects
/// Saturate an image, amount should be in range [0...100]
void saturate(Image& image, int amount);
/// Desaturate an image
void desaturate(Image& image);
/// Saturate an image
void saturate(Image& image, double amount);
// ----------------------------------------------------------------------------- : Combining
......
......@@ -12,33 +12,38 @@
// ----------------------------------------------------------------------------- : Saturation
void saturate(Image& image, int amount) {
void saturate(Image& image, double 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;
}
}
void desaturate(Image& image/*, int amount*/) {
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];
pix[0] = (r+r+g+b) / 4;
pix[1] = (g+r+g+b) / 4;
pix[2] = (b+r+g+b) / 4;
pix += 3;
if (amount > 0) {
amount = min(amount,0.99);
int factor = 256 * amount;
int div = 768 - 3 * factor;
while (pix != end) {
int r = pix[0], g = pix[1], b = pix[2];
int avg = factor*(r+g+b);
pix[0] = col((768*r - avg) / div);
pix[1] = col((768*g - avg) / div);
pix[2] = col((768*b - avg) / div);
pix += 3;
}
} else if (amount < -0.99) {
while (pix != end) {
int r = pix[0], g = pix[1], b = pix[2];
pix[0] = pix[1] = pix[2] = (r+g+b)/3;
pix += 3;
}
} else {
int factor1 = 256 * -amount;
int factor2 = 768 - 3*factor1;
while (pix != end) {
int r = pix[0], g = pix[1], b = pix[2];
int avg = factor1*(r+g+b);
pix[0] = (factor2*r + avg) / 768;
pix[1] = (factor2*g + avg) / 768;
pix[2] = (factor2*b + avg) / 768;
pix += 3;
}
}
}
......@@ -277,7 +277,7 @@ class PackageIconRequest : public ThumbnailRequest {
Image resampled(16,16,false);
resample_preserve_aspect(image,resampled);
ti->icon = Bitmap(resampled);
desaturate(resampled);
saturate(resampled, -.75);
set_alpha(resampled,0.5);
ti->icon_grey = Bitmap(resampled);
list->Refresh(false);
......@@ -318,7 +318,7 @@ void PackageUpdateList::initItems() {
image = load_resource_image(_("installer_group"));
}
ti.icon = Bitmap(image);
desaturate(image);
saturate(image, -.75);
set_alpha(image, 0.5);
ti.icon_grey = Bitmap(image);
if (p && !p->description->icon.Ok() && !p->description->icon_url.empty()) {
......
......@@ -79,6 +79,12 @@ SCRIPT_FUNCTION(set_combine) {
return new_intrusive2<SetCombineImage>(input, image_combine);
}
SCRIPT_FUNCTION(saturate) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM(double, amount);
return new_intrusive2<SaturateImage>(input, amount);
}
SCRIPT_FUNCTION(enlarge) {
SCRIPT_PARAM_C(GeneratedImageP, input);
SCRIPT_PARAM_N(double, _("border size"), border_size);
......@@ -170,6 +176,7 @@ void init_script_image_functions(Context& ctx) {
ctx.setVariable(_("set mask"), script_set_mask);
ctx.setVariable(_("set alpha"), script_set_alpha);
ctx.setVariable(_("set combine"), script_set_combine);
ctx.setVariable(_("saturate"), script_saturate);
ctx.setVariable(_("enlarge"), script_enlarge);
ctx.setVariable(_("crop"), script_crop);
ctx.setVariable(_("drop shadow"), script_drop_shadow);
......
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