diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c4641330..b4b26618 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3750,3 +3750,6 @@ Timo Weing Jose Angel for reporting a bug in default values for DVB-T + +Andreas Baierl + for implementing scaling images diff --git a/HISTORY b/HISTORY index 5e853666..381055d3 100644 --- a/HISTORY +++ b/HISTORY @@ -9871,3 +9871,4 @@ Video Disk Recorder Revision History Ehrnsperger). - Using a dummy OSD if no OSD provider is available is not considered an error any more (thanks to Markus Ehrnsperger). +- Implemented scaling images (thanks to Andreas Baierl). diff --git a/osd.c b/osd.c index 7eb71261..80d046ca 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 5.1 2024/01/18 11:06:45 kls Exp $ + * $Id: osd.c 5.2 2024/01/18 12:04:57 kls Exp $ */ #include "osd.h" @@ -1139,6 +1139,49 @@ void cImage::Fill(tColor Color) data[i] = Color; } +cImage *cImage::Scaled(double FactorX, double FactorY, bool AntiAlias) const +{ + int w = max(1, int(round(Width() * FactorX))); + int h = max(1, int(round(Height() * FactorY))); + cImage *i = new cImage(cSize(w, h)); + int RatioX = (Width() << 16) / i->Width(); + int RatioY = (Height() << 16) / i->Height(); + + if (!AntiAlias || FactorX <= 1.0 && FactorY <= 1.0) { + // Downscaling - no anti-aliasing: + int SourceY = 0; + for (int y = 0; y < i->Height(); y++) { + int SourceX = 0; + for (int x = 0; x < i->Width(); x++) { + tColor c1 = GetPixel(cPoint(SourceX >> 16, SourceY >> 16)); + i->SetPixel(cPoint(x, y), c1); + SourceX += RatioX; + } + SourceY += RatioY; + } + } + else { + // Upscaling - anti-aliasing: + int SourceY = 0; + for (int y = 0; y < i->Height(); y++) { + int SourceX = 0; + int sy = min(SourceY >> 16, Height() - 2); + uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF); + for (int x = 0; x < i->Width(); x++) { + int sx = min(SourceX >> 16, Width() - 2); + uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF); + tColor c1 = AlphaBlend(GetPixel(cPoint(sx, sy)), GetPixel(cPoint(sx + 1, sy)), BlendX); + tColor c2 = AlphaBlend(GetPixel(cPoint(sx, sy + 1)), GetPixel(cPoint(sx + 1, sy + 1)), BlendX); + tColor c3 = AlphaBlend(c1, c2, BlendY); + i->SetPixel(cPoint(x, y), c3); + SourceX += RatioX; + } + SourceY += RatioY; + } + } + return i; +} + // --- cPixmapMemory --------------------------------------------------------- cPixmapMemory::cPixmapMemory(void) @@ -1259,6 +1302,26 @@ void cPixmapMemory::DrawImage(const cPoint &Point, int ImageHandle) Unlock(); } +void cPixmapMemory::DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias) +{ + Lock(); + const cImage *i = &Image; + if (!DoubleEqual(FactorX, 1.0) || !DoubleEqual(FactorY, 1.0)) + i = i->Scaled(FactorX, FactorY, AntiAlias); + DrawImage(Point, *i); + if (i != &Image) + delete i; + Unlock(); +} + +void cPixmapMemory::DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias) +{ + Lock(); + if (const cImage *Image = cOsdProvider::GetImageData(ImageHandle)) + DrawScaledImage(Point, *Image, FactorX, FactorY, AntiAlias); + Unlock(); +} + void cPixmapMemory::DrawPixel(const cPoint &Point, tColor Color) { Lock(); @@ -2118,6 +2181,18 @@ void cOsd::DrawImage(const cPoint &Point, int ImageHandle) pixmaps[0]->DrawImage(Point, ImageHandle); } +void cOsd::DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias) +{ + if (isTrueColor) + pixmaps[0]->DrawScaledImage(Point, Image, FactorX, FactorY, AntiAlias); +} + +void cOsd::DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias) +{ + if (isTrueColor) + pixmaps[0]->DrawScaledImage(Point, ImageHandle, FactorX, FactorY, AntiAlias); +} + void cOsd::DrawPixel(int x, int y, tColor Color) { if (isTrueColor) diff --git a/osd.h b/osd.h index 77722662..55be4823 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 5.1 2021/05/21 12:54:08 kls Exp $ + * $Id: osd.h 5.2 2024/01/18 12:04:57 kls Exp $ */ #ifndef __OSD_H @@ -447,6 +447,11 @@ public: ///< Clears the image data by setting all pixels to be fully transparent. void Fill(tColor Color); ///< Fills the image data with the given Color. + cImage *Scaled(double FactorX, double FactorY, bool AntiAlias = false) const; + ///< Creates a copy of this image, scaled by the given factors. + ///< If AntiAlias is true and either of the factors is greater than 1.0, + ///< anti-aliasing is applied. + ///< The caller must delete the returned image once it is no longer used. }; #define MAXPIXMAPLAYERS 8 @@ -602,6 +607,23 @@ public: ///< the given Point. ImageHandle must be a value that has previously been ///< returned by a call to cOsdProvider::StoreImage(). If ImageHandle ///< has an invalid value, nothing happens. + virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias = false) {}; + ///< Draws the given Image into this pixmap at the given Point and scales it. + ///< If AntiAlias is true and either of the factors is greater than + ///< 1.0, anti-aliasing is applied. + ///< This function should be 'pure', just like all the others. However, since it was + ///< introduced when this class was already in widespread use, the default was made + ///< empty, so that existing code will still compile. + virtual void DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias = false) {}; + ///< Draws the image referenced by the given ImageHandle into this pixmap at + ///< the given Point and scales it. ImageHandle must be a value that has + ///< previously been returned by a call to cOsdProvider::StoreImage(). + ///< If ImageHandle has an invalid value, nothing happens. + ///< If AntiAlias is true and either of the factors is greater than + ///< 1.0, anti-aliasing is applied. + ///< This function should be 'pure', just like all the others. However, since it was + ///< introduced when this class was already in widespread use, the default was made + ///< empty, so that existing code will still compile. virtual void DrawPixel(const cPoint &Point, tColor Color) = 0; ///< Sets the pixel at the given Point to the given Color, which is ///< a full 32 bit ARGB value. If the alpha value of Color is not 0xFF @@ -700,6 +722,8 @@ public: virtual void Fill(tColor Color); virtual void DrawImage(const cPoint &Point, const cImage &Image); virtual void DrawImage(const cPoint &Point, int ImageHandle); + virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias = false); + virtual void DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias = false); virtual void DrawPixel(const cPoint &Point, tColor Color); virtual void DrawBlendedPixel(const cPoint &Point, tColor Color, uint8_t AlphaLayer = ALPHA_OPAQUE); virtual void DrawBitmap(const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false); @@ -857,6 +881,19 @@ public: ///< returned by a call to cOsdProvider::StoreImage(). If ImageHandle ///< has an invalid value, nothing happens. ///< If this is not a true color OSD, this function does nothing. + virtual void DrawScaledImage(const cPoint &Point, const cImage &Image, double FactorX, double FactorY, bool AntiAlias = false); + ///< Draws the given Image on this OSD at the given Point and scales it. + ///< If AntiAlias is true and either of the factors is greater than + ///< 1.0, anti-aliasing is applied. + ///< If this is not a true color OSD, this function does nothing. + virtual void DrawScaledImage(const cPoint &Point, int ImageHandle, double FactorX, double FactorY, bool AntiAlias = false); + ///< Draws the image referenced by the given ImageHandle on this OSD at + ///< the given Point and scales it. ImageHandle must be a value that has + ///< previously been returned by a call to cOsdProvider::StoreImage(). + ///< If ImageHandle has an invalid value, nothing happens. + ///< If AntiAlias is true and either of the factors is greater than + ///< 1.0, anti-aliasing is applied. + ///< If this is not a true color OSD, this function does nothing. virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); ///< Checks whether the OSD can display the given set of sub-areas. ///< The return value indicates whether a call to SetAreas() with this