summaryrefslogtreecommitdiff
path: root/glcdgraphics/imagefile.c
diff options
context:
space:
mode:
Diffstat (limited to 'glcdgraphics/imagefile.c')
-rw-r--r--glcdgraphics/imagefile.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/glcdgraphics/imagefile.c b/glcdgraphics/imagefile.c
index 2f56f4a..d6baf24 100644
--- a/glcdgraphics/imagefile.c
+++ b/glcdgraphics/imagefile.c
@@ -11,6 +11,7 @@
#include "image.h"
#include "imagefile.h"
+#include "bitmap.h"
namespace GLCD
{
@@ -32,4 +33,132 @@ bool cImageFile::Save(cImage & image, const std::string & fileName)
return false;
}
+
+uint32_t cImageFile::Blend(uint32_t FgColour, uint32_t BgColour, uint8_t Level, double antiAliasGranularity) const
+{
+ if (antiAliasGranularity > 0.0)
+ Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity);
+ int Af = (FgColour & 0xFF000000) >> 24;
+ int Rf = (FgColour & 0x00FF0000) >> 16;
+ int Gf = (FgColour & 0x0000FF00) >> 8;
+ int Bf = (FgColour & 0x000000FF);
+ int Ab = (BgColour & 0xFF000000) >> 24;
+ int Rb = (BgColour & 0x00FF0000) >> 16;
+ int Gb = (BgColour & 0x0000FF00) >> 8;
+ int Bb = (BgColour & 0x000000FF);
+ int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF;
+ int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF;
+ int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF;
+ int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF;
+ return (A << 24) | (R << 16) | (G << 8) | B;
+}
+
+bool cImageFile::Scale(cImage & image, uint16_t scalew, uint16_t scaleh, bool AntiAlias)
+{
+ if (! (scalew || scaleh) )
+ return false;
+
+ // one out of scalew/h == 0 ? -> auto aspect ratio
+ if (scalew && ! scaleh) {
+ scaleh = (uint16_t)( ((uint32_t)scalew * (uint32_t)image.Height()) / (uint32_t)image.Width() );
+ } else if (!scalew && scaleh) {
+ scalew = (uint16_t)( ((uint32_t)scaleh * (uint32_t)image.Width()) / (uint32_t)image.Height() );
+ }
+
+ cImage tempImg = cImage();
+ tempImg.SetWidth(scalew);
+ tempImg.SetHeight(scaleh);
+
+ // Scaling/Blending based on VDR / osd.c
+ // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf
+ // by deltener@mindtremors.com
+ //
+ // slightly improved by Wolfgang Astleitner (modify factors and ratios so that scaled image is centered when upscaling)
+
+ double FactorX, FactorY;
+ int RatioX, RatioY;
+
+ if (!AntiAlias) {
+ FactorX = (double)scalew / (double)image.Width();
+ FactorY = (double)scaleh / (double)image.Height();
+ RatioX = (image.Width() << 16) / scalew;
+ RatioY = (image.Height() << 16) / scaleh;
+ } else {
+ FactorX = (double)scalew / (double)(image.Width()-1);
+ FactorY = (double)scaleh / (double)(image.Height()-1);
+ RatioX = ((image.Width()-1) << 16) / scalew;
+ RatioY = ((image.Height()-1) << 16) / scaleh;
+ }
+
+ bool downscale = (!AntiAlias || (FactorX <= 1.0 && FactorY <= 1.0));
+
+ for (unsigned int frame = 0; frame < image.Count() ; frame ++ ) {
+ cBitmap *b = new cBitmap(scalew, scaleh, GRAPHLCD_Transparent);
+
+ cBitmap *currFrame = image.GetBitmap(frame);
+
+ if (downscale) {
+ // Downscaling - no anti-aliasing:
+ const uint32_t *DestRow = b->Data();
+ int SourceY = 0;
+ for (int y = 0; y < scaleh; y++) {
+ int SourceX = 0;
+ const uint32_t *SourceRow = currFrame->Data() + (SourceY >> 16) * image.Width();
+ uint32_t *Dest = (uint32_t*) DestRow;
+ for (int x = 0; x < scalew; x++) {
+ *Dest++ = SourceRow[SourceX >> 16];
+ SourceX += RatioX;
+ }
+ SourceY += RatioY;
+ DestRow += scalew;
+ }
+ } else {
+ // Upscaling - anti-aliasing:
+ int SourceY = 0;
+ for (int y = 0; y < scaleh /*- 1*/; y++) {
+ int SourceX = 0;
+ int sy = SourceY >> 16;
+ uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF);
+ for (int x = 0; x < scalew /*- 1*/; x++) {
+ int sx = SourceX >> 16;
+ uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF);
+ // TODO: antiAliasGranularity
+ uint32_t c1 = Blend(currFrame->GetPixel(sx, sy), currFrame->GetPixel(sx + 1, sy), BlendX);
+ uint32_t c2 = Blend(currFrame->GetPixel(sx, sy + 1), currFrame->GetPixel(sx + 1, sy + 1), BlendX);
+ uint32_t c3 = Blend(c1, c2, BlendY);
+ b->DrawPixel(x, y, c3);
+ SourceX += RatioX;
+ }
+ SourceY += RatioY;
+ }
+ }
+ tempImg.AddBitmap(b);
+ }
+ // clear all bitmaps from image
+ image.Clear();
+ // set new resolution
+ image.SetWidth(scalew);
+ image.SetHeight(scaleh);
+ // re-add bitmaps from scaled image container
+ for (unsigned int frame = 0; frame < tempImg.Count(); frame ++) {
+ image.AddBitmap(new cBitmap(scalew, scaleh, (uint32_t*)tempImg.GetBitmap(frame)->Data()));
+ }
+ return true;
+}
+
+bool cImageFile::LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh)
+{
+ if (Load(image, fileName)) {
+ if (scalew || scaleh) {
+ return Scale(image, scalew, scaleh, true);
+ } else {
+ return true;
+ }
+ } else {
+ scalew = 0;
+ scaleh = 0;
+ return false;
+ }
+}
+
} // end of namespace