diff options
-rw-r--r-- | HISTORY | 3 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | icons/default/skinElements/menubutton.png | bin | 49719 -> 9360 bytes | |||
-rw-r--r-- | icons/default/skinElements/menubuttonactive.png | bin | 53449 -> 11656 bytes | |||
-rw-r--r-- | icons/default/skinIcons/DiskUsage.png | bin | 2835 -> 4404 bytes | |||
-rw-r--r-- | imagecache.c | 136 | ||||
-rw-r--r-- | imagemagickwrapper.c | 41 | ||||
-rw-r--r-- | imagemagickwrapper.h | 2 | ||||
-rw-r--r-- | imagescaler.c | 149 | ||||
-rw-r--r-- | imagescaler.h | 97 |
10 files changed, 317 insertions, 113 deletions
@@ -377,3 +377,6 @@ Version 0.1.4 - Fixed a bug that setup values are not stored if theme is changed Version 1.0.0 + +- improved image scaling by using internal scaling libary from + Nikolaus Meine (thanks @Soeren Moch for providing the patch) @@ -64,7 +64,7 @@ endif ### The object files (add further files here): OBJS = $(PLUGIN).o config.o displaychannel.o displaymenu.o displaymenuview.o displaymessage.o displayreplay.o displaytracks.o displayvolume.o displaychannelview.o fontmanager.o \ - geometrymanager.o imagecache.o imagemagickwrapper.o helpers.o imageloader.o menudetailview.o menuitem.o nopacity.o setup.o textwindow.o timers.o + geometrymanager.o imagecache.o imagemagickwrapper.o imagescaler.o helpers.o imageloader.o menudetailview.o menuitem.o nopacity.o setup.o textwindow.o timers.o ### The main target: diff --git a/icons/default/skinElements/menubutton.png b/icons/default/skinElements/menubutton.png Binary files differindex 505e226..0800a5e 100644 --- a/icons/default/skinElements/menubutton.png +++ b/icons/default/skinElements/menubutton.png diff --git a/icons/default/skinElements/menubuttonactive.png b/icons/default/skinElements/menubuttonactive.png Binary files differindex 859a85a..caae104 100644 --- a/icons/default/skinElements/menubuttonactive.png +++ b/icons/default/skinElements/menubuttonactive.png diff --git a/icons/default/skinIcons/DiskUsage.png b/icons/default/skinIcons/DiskUsage.png Binary files differindex de1dfbb..f40fcd9 100644 --- a/icons/default/skinIcons/DiskUsage.png +++ b/icons/default/skinIcons/DiskUsage.png diff --git a/imagecache.c b/imagecache.c index 52a7992..29690c3 100644 --- a/imagecache.c +++ b/imagecache.c @@ -51,9 +51,6 @@ void cImageCache::CreateCache(void) { if (success) { channelsCached++; InsertIntoLogoCache(ctLogo, *channel->GetChannelID().ToString()); - } - success = LoadLogo(channel); - if (success) { InsertIntoLogoCache(ctLogoMenuItem, *channel->GetChannelID().ToString()); } } @@ -151,12 +148,11 @@ cImage *cImageCache::GetLogo(eCacheType type, const cChannel *channel) { cPoint logoSize = LogoSize(type); int width = logoSize.X(); int height = logoSize.Y(); - buffer.sample(Geometry(width, height)); if (tempStaticLogo) { delete tempStaticLogo; tempStaticLogo = NULL; } - tempStaticLogo = CreateImage(); + tempStaticLogo = CreateImage(width, height); return tempStaticLogo; } else { //add requested logo to cache @@ -324,10 +320,7 @@ bool cImageCache::LoadIcon(eCacheType type, std::string name) { } void cImageCache::InsertIntoIconCache(eCacheType type, std::string name, int width, int height, bool preserveAspect) { - Geometry size(width, height); - size.aspect(!preserveAspect); - buffer.sample(size); - cImage *image = CreateImage(); + cImage *image = CreateImage(width, height, preserveAspect); if (type == ctMenuIcon) menuIconCache.insert(std::pair<std::string, cImage*>(name, image)); else if (type == ctSkinIcon) @@ -376,8 +369,7 @@ void cImageCache::InsertIntoLogoCache(eCacheType type, std::string channelID) { cPoint logoSize = LogoSize(type); int width = logoSize.X(); int height = logoSize.Y(); - buffer.sample(Geometry(width, height)); - cImage *image = CreateImage(); + cImage *image = CreateImage(width, height); if (type == ctLogo) logoCache.insert(std::pair<std::string, cImage*>(channelID, image)); else if (type == ctLogoMenuItem) @@ -496,82 +488,37 @@ void cImageCache::CreateSkinElementsGraphics(void) { std::string imgMenuItem = "skinElements/menubutton"; std::string imgMenuItemActive = "skinElements/menubuttonactive"; std::string imgMenuItemTop = "skinElements/menubuttontop"; - //Main Menu + //Main Menu + Setup Menu + Schedules Menu + Channels Menu + Recordings Menu + Timers Menu + Tracks Menu success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) + if (success) { InsertIntoSkinElementCache(seMain, geoManager->menuItemWidthMain, geoManager->menuItemHeightMain); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seMainHigh, geoManager->menuItemWidthMain, geoManager->menuItemHeightMain); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seMainTop, geoManager->menuItemWidthMain, geoManager->menuItemHeightMain); - - //Setup Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seSetup, geoManager->menuItemWidthSetup, geoManager->menuItemHeightMain); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seSetupHigh, geoManager->menuItemWidthSetup, geoManager->menuItemHeightMain); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seSetupTop, geoManager->menuItemWidthSetup, geoManager->menuItemHeightMain); - - //Schedules Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seSchedules, geoManager->menuItemWidthSchedule, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seSchedulesHigh, geoManager->menuItemWidthSchedule, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seSchedulesTop, geoManager->menuItemWidthSchedule, geoManager->menuItemHeightSchedule); - - //Channels Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seChannels, geoManager->menuItemWidthChannel, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seChannelsHigh, geoManager->menuItemWidthChannel, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seChannelsTop, geoManager->menuItemWidthChannel, geoManager->menuItemHeightSchedule); - - //Recordings Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seRecordings, geoManager->menuItemWidthRecording, geoManager->menuItemHeightRecordings); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seRecordingsHigh, geoManager->menuItemWidthRecording, geoManager->menuItemHeightRecordings); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seRecordingsTop, geoManager->menuItemWidthRecording, geoManager->menuItemHeightRecordings); - - //Timers Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seTimers, geoManager->menuItemWidthTimer, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) - InsertIntoSkinElementCache(seTimersHigh, geoManager->menuItemWidthTimer, geoManager->menuItemHeightSchedule); - success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) - InsertIntoSkinElementCache(seTimersTop, geoManager->menuItemWidthTimer, geoManager->menuItemHeightSchedule); - - //Tracks Menu - success = LoadIcon(ctSkinElement, imgMenuItem); - if (success) InsertIntoSkinElementCache(seTracks, geoManager->menuItemWidthTracks, geoManager->menuItemHeightTracks); + } success = LoadIcon(ctSkinElement, imgMenuItemActive); - if (success) + if (success) { + InsertIntoSkinElementCache(seMainHigh, geoManager->menuItemWidthMain, geoManager->menuItemHeightMain); + InsertIntoSkinElementCache(seSetupHigh, geoManager->menuItemWidthSetup, geoManager->menuItemHeightMain); + InsertIntoSkinElementCache(seSchedulesHigh, geoManager->menuItemWidthSchedule, geoManager->menuItemHeightSchedule); + InsertIntoSkinElementCache(seChannelsHigh, geoManager->menuItemWidthChannel, geoManager->menuItemHeightSchedule); + InsertIntoSkinElementCache(seRecordingsHigh, geoManager->menuItemWidthRecording, geoManager->menuItemHeightRecordings); + InsertIntoSkinElementCache(seTimersHigh, geoManager->menuItemWidthTimer, geoManager->menuItemHeightSchedule); InsertIntoSkinElementCache(seTracksHigh, geoManager->menuItemWidthTracks, geoManager->menuItemHeightTracks); + } success = LoadIcon(ctSkinElement, imgMenuItemTop); - if (success) + if (success) { + InsertIntoSkinElementCache(seMainTop, geoManager->menuItemWidthMain, geoManager->menuItemHeightMain); + InsertIntoSkinElementCache(seSetupTop, geoManager->menuItemWidthSetup, geoManager->menuItemHeightMain); + InsertIntoSkinElementCache(seSchedulesTop, geoManager->menuItemWidthSchedule, geoManager->menuItemHeightSchedule); + InsertIntoSkinElementCache(seChannelsTop, geoManager->menuItemWidthChannel, geoManager->menuItemHeightSchedule); + InsertIntoSkinElementCache(seRecordingsTop, geoManager->menuItemWidthRecording, geoManager->menuItemHeightRecordings); + InsertIntoSkinElementCache(seTimersTop, geoManager->menuItemWidthTimer, geoManager->menuItemHeightSchedule); InsertIntoSkinElementCache(seTracksTop, geoManager->menuItemWidthTracks, geoManager->menuItemHeightTracks); + } //Color Buttons std::string imgButtonRed = "skinElements/buttonred"; @@ -608,37 +555,31 @@ void cImageCache::CreateSkinElementsGraphics(void) { if (success) InsertIntoSkinElementCache(seMenuHeader, geoManager->osdWidth, geoManager->menuHeaderHeight); - //Menu Messages Background + //Messages Background + Menu Messages Background std::string msgStatus = "skinElements/messageStatus"; std::string msgInfo = "skinElements/messageInfo"; std::string msgWarning = "skinElements/messageWarning"; std::string msgError = "skinElements/messageError"; success = LoadIcon(ctSkinElement, msgStatus); - if (success) - InsertIntoSkinElementCache(seMessageMenuStatus, geoManager->menuMessageWidth, geoManager->menuMessageHeight); - success = LoadIcon(ctSkinElement, msgInfo); - if (success) - InsertIntoSkinElementCache(seMessageMenuInfo, geoManager->menuMessageWidth, geoManager->menuMessageHeight); - success = LoadIcon(ctSkinElement, msgWarning); - if (success) - InsertIntoSkinElementCache(seMessageMenuWarning, geoManager->menuMessageWidth, geoManager->menuMessageHeight); - success = LoadIcon(ctSkinElement, msgError); - if (success) - InsertIntoSkinElementCache(seMessageMenuError, geoManager->menuMessageWidth, geoManager->menuMessageHeight); - //Messages Background - success = LoadIcon(ctSkinElement, msgStatus); - if (success) + if (success) { InsertIntoSkinElementCache(seMessageStatus, geoManager->messageWidth, geoManager->messageHeight); + InsertIntoSkinElementCache(seMessageMenuStatus, geoManager->menuMessageWidth, geoManager->menuMessageHeight); + } success = LoadIcon(ctSkinElement, msgInfo); - if (success) + if (success) { InsertIntoSkinElementCache(seMessageInfo, geoManager->messageWidth, geoManager->messageHeight); + InsertIntoSkinElementCache(seMessageMenuInfo, geoManager->menuMessageWidth, geoManager->menuMessageHeight); + } success = LoadIcon(ctSkinElement, msgWarning); - if (success) + if (success) { InsertIntoSkinElementCache(seMessageWarning, geoManager->messageWidth, geoManager->messageHeight); + InsertIntoSkinElementCache(seMessageMenuWarning, geoManager->menuMessageWidth, geoManager->menuMessageHeight); + } success = LoadIcon(ctSkinElement, msgError); - if (success) + if (success) { InsertIntoSkinElementCache(seMessageError, geoManager->messageWidth, geoManager->messageHeight); - + InsertIntoSkinElementCache(seMessageMenuError, geoManager->menuMessageWidth, geoManager->menuMessageHeight); + } //DisplayChannel Background and Foreground std::string imgChannelBackground; @@ -695,12 +636,7 @@ void cImageCache::CreateSkinElementsGraphics(void) { } void cImageCache::InsertIntoSkinElementCache(eSkinElementType type, int width, int height) { - if (width>0 && height>0) { - Geometry size(width, height); - size.aspect(true); - buffer.sample(size); - } - cImage *image = CreateImage(); + cImage *image = CreateImage(width, height, false); skinElementCache.insert(std::pair<eSkinElementType, cImage*>(type, image)); } diff --git a/imagemagickwrapper.c b/imagemagickwrapper.c index 7cdf980..0660a69 100644 --- a/imagemagickwrapper.c +++ b/imagemagickwrapper.c @@ -2,6 +2,7 @@ #include <sstream> #include "imagemagickwrapper.h" #include "config.h" +#include "imagescaler.h" cImageMagickWrapper::cImageMagickWrapper() { InitializeMagick(NULL); @@ -10,22 +11,40 @@ cImageMagickWrapper::cImageMagickWrapper() { cImageMagickWrapper::~cImageMagickWrapper() { } -cImage *cImageMagickWrapper::CreateImage() { +cImage *cImageMagickWrapper::CreateImage(int width, int height, bool preserveAspect) { int w, h; w = buffer.columns(); h = buffer.rows(); - cImage *image = new cImage(cSize(w, h)); + if (width == 0) + width = w; + if (height == 0) + height = h; + if (preserveAspect) { + unsigned scale_w = 1000 * width / w; + unsigned scale_h = 1000 * height / h; + if (scale_w > scale_h) + width = w * height / h; + else + height = h * width / w; + } const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h); - for (int iy = 0; iy < h; ++iy) { - for (int ix = 0; ix < w; ++ix) { - tColor col = (~int(pixels->opacity * 255 / MaxRGB) << 24) - | (int(pixels->green * 255 / MaxRGB) << 8) - | (int(pixels->red * 255 / MaxRGB) << 16) - | (int(pixels->blue * 255 / MaxRGB) ); - image->SetPixel(cPoint(ix, iy), col); - ++pixels; - } + cImage *image = new cImage(cSize(width, height)); + tColor *imgData = (tColor *)image->Data(); + if (w != width || h != height) { + ImageScaler scaler; + scaler.SetImageParameters(imgData, width, width, height, w, h); + for (const void *pixels_end = &pixels[w*h]; pixels < pixels_end; ++pixels) + scaler.PutSourcePixel(pixels->blue / ((MaxRGB + 1) / 256), + pixels->green / ((MaxRGB + 1) / 256), + pixels->red / ((MaxRGB + 1) / 256), + ~(pixels->opacity / ((MaxRGB + 1) / 256))); + return image; } + for (const void *pixels_end = &pixels[width*height]; pixels < pixels_end; ++pixels) + *imgData++ = ((~int(pixels->opacity / ((MaxRGB + 1) / 256)) << 24) | + (int(pixels->green / ((MaxRGB + 1) / 256)) << 8) | + (int(pixels->red / ((MaxRGB + 1) / 256)) << 16) | + (int(pixels->blue / ((MaxRGB + 1) / 256)) )); return image; } diff --git a/imagemagickwrapper.h b/imagemagickwrapper.h index a5cc482..5f9901e 100644 --- a/imagemagickwrapper.h +++ b/imagemagickwrapper.h @@ -17,7 +17,7 @@ public: protected: Image buffer; Color Argb2Color(tColor col); - cImage *CreateImage(void); + cImage *CreateImage(int width, int height, bool preserveAspect = true); cImage CreateImageCopy(void); bool LoadImage(std::string FileName, std::string Path, std::string Extension); bool LoadImage(const char *fullpath); diff --git a/imagescaler.c b/imagescaler.c new file mode 100644 index 0000000..cebe912 --- /dev/null +++ b/imagescaler.c @@ -0,0 +1,149 @@ + +#include "imagescaler.h" + +#include <cstdlib> +#include <cmath> + +ImageScaler::ImageScaler() : + m_memory(NULL), + m_hor_filters(NULL), + m_ver_filters(NULL), + m_buffer(NULL), + m_dst_image(NULL), + m_dst_stride(0), + m_dst_width(0), + m_dst_height(0), + m_src_width(0), + m_src_height(0), + m_src_x(0), + m_src_y(0), + m_dst_x(0), + m_dst_y(0) { +} + +ImageScaler::~ImageScaler() { + if ( m_memory ) free( m_memory ); +} + +// sin(x)/(x) +static float sincf( float x ) { + if ( fabsf(x) < 0.05f ) return 1.0f - (1.0f/6.0f)*x*x; // taylor series approximation to avoid 0/0 + return sin(x)/x; +} + +static void CalculateFilters( ImageScaler::Filter *filters, int dst_size, int src_size ) { + const float fc = dst_size >= src_size ? 1.0f : ((float) dst_size)/((float) src_size); + + for (int i = 0; i < dst_size; i++) { + const int d = 2*dst_size; // sample position denominator + const int e = (2*i+1) * src_size - dst_size; // sample position enumerator + int offset = e / d; // truncated sample position + const float sub_offset = ((float) (e - offset*d)) / ((float) d); // exact sample position is (float) e/d = offset + sub_offset + + // calculate filter coefficients + float h[4]; + for (int j=0; j<4; j++) { + const float t = 3.14159265359f * (sub_offset+(1-j)); + h[j] = sincf( fc * t ) * cosf( 0.25f * t ); // sinc-lowpass and cos-window + } + + // ensure that filter does not reach out off image bounds: + while ( offset < 1 ) { + h[0] += h[1]; + h[1] = h[2]; + h[2] = h[3]; + h[3] = 0.0f; + offset++; + } + + while ( offset+3 > src_size ) { + h[3] += h[2]; + h[2] = h[1]; + h[1] = h[0]; + h[0] = 0.0f; + offset--; + } + + // coefficients are normalized to sum up to 2048 + const float norm = 2048.0f / ( h[0] + h[1] + h[2] + h[3] ); + + offset--; // offset of fist used pixel + + filters[i].m_offset = offset + 4; // store offset of first unused pixel + + for (int j=0; j<4; j++) { + const float t = norm * h[j]; + filters[i].m_coeff[(offset+j) & 3] = (int) ((t > 0.0f) ? (t+0.5f) : (t-0.5f)); // consider ring buffer index permutations + } + } + + // set end marker + filters[dst_size].m_offset = (unsigned) -1; + +} + +void ImageScaler::SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ) { + m_src_x = 0; + m_src_y = 0; + m_dst_x = 0; + m_dst_y = 0; + + m_dst_image = dst_image; + m_dst_stride = dst_stride; + + // if image dimensions do not change we can keep the old filter coefficients + if ( (src_width == m_src_width) && (src_height == m_src_height) && (dst_width == m_dst_width) && (dst_height == m_dst_height) ) return; + + m_dst_width = dst_width; + m_dst_height = dst_height; + m_src_width = src_width; + m_src_height = src_height; + + if ( m_memory ) free( m_memory ); + + const unsigned hor_filters_size = (m_dst_width + 1) * sizeof(Filter); // reserve one extra position for end marker + const unsigned ver_filters_size = (m_dst_height + 1) * sizeof(Filter); + const unsigned buffer_size = 4 * m_dst_width * sizeof(TmpPixel); + + char *p = (char *) malloc( hor_filters_size + ver_filters_size + buffer_size ); + + m_memory = p; + + m_hor_filters = (Filter *) p; p += hor_filters_size; + m_ver_filters = (Filter *) p; p += ver_filters_size; + m_buffer = (TmpPixel *) p; + + CalculateFilters( m_hor_filters, m_dst_width , m_src_width ); + CalculateFilters( m_ver_filters, m_dst_height, m_src_height ); +} + +// shift range to 0..255 and clamp overflows +static unsigned shift_clamp( int x ) { + x = ( x + (1<<21) ) >> 22; + if ( x < 0 ) return 0; + if ( x > 255 ) return 255; + return x; +} + +void ImageScaler::NextSourceLine() { + m_dst_x = 0; + m_src_x = 0; + m_src_y++; + + while ( m_ver_filters[m_dst_y].m_offset == m_src_y ) { + const int h0 = m_ver_filters[m_dst_y].m_coeff[0]; + const int h1 = m_ver_filters[m_dst_y].m_coeff[1]; + const int h2 = m_ver_filters[m_dst_y].m_coeff[2]; + const int h3 = m_ver_filters[m_dst_y].m_coeff[3]; + const TmpPixel *src = m_buffer; + unsigned *dst = m_dst_image + m_dst_stride * m_dst_y; + + for (unsigned i=0; i<m_dst_width; i++) { + const ImageScaler::TmpPixel t( src[0]*h0 + src[1]*h1 + src[2]*h2 + src[3]*h3 ); + src += 4; + dst[i] = shift_clamp(t[0]) | (shift_clamp(t[1])<<8) | (shift_clamp(t[2])<<16) | (shift_clamp(t[3])<<24); + } + + m_dst_y++; + } +} diff --git a/imagescaler.h b/imagescaler.h new file mode 100644 index 0000000..f2de6ba --- /dev/null +++ b/imagescaler.h @@ -0,0 +1,97 @@ +#ifndef _ImageScaler_h +#define _ImageScaler_h + +/*! + * this class scales images consisting of 4 components (RGBA) + * to an arbitrary size using a 4-tap filter + */ +class ImageScaler { +public: + + struct Filter { + unsigned m_offset; + short m_coeff[4]; + }; + + ImageScaler(); + ~ImageScaler(); + + //! set destination image and source image size + void SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ); + + /*! process one pixel of source image; destination image is written while input is processed + * SetImageParameters() must be called first + */ + void PutSourcePixel( unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3 ) { + m_hbuf[ (m_src_x++) & 3 ].Set( c0, c1, c2, c3 ); + + TmpPixel *bp = m_buffer + 4 * m_dst_x + (m_src_y & 3); + const Filter *fh; + + while ( (fh=m_hor_filters+m_dst_x)->m_offset == m_src_x ) { + *bp = m_hbuf[0]*fh->m_coeff[0] + m_hbuf[1]*fh->m_coeff[1] + m_hbuf[2]*fh->m_coeff[2] + m_hbuf[3]*fh->m_coeff[3]; + m_dst_x++; + bp += 4; + } + + if ( m_src_x == m_src_width ) NextSourceLine(); + } + +private: + + //! temporary image pixel class - a 4-element integer vector + class TmpPixel { + public: + TmpPixel() { + } + + TmpPixel( int c0, int c1, int c2, int c3 ) { + Set(c0,c1,c2,c3); + } + + void Set( int c0, int c1, int c2, int c3 ) { + m_comp[0] = c0; + m_comp[1] = c1; + m_comp[2] = c2; + m_comp[3] = c3; + } + + TmpPixel operator*( int s ) const { + return TmpPixel( m_comp[0]*s, m_comp[1]*s, m_comp[2]*s, m_comp[3]*s ); + } + + TmpPixel operator+( const TmpPixel &x ) const { + return TmpPixel( m_comp[0] + x[0], m_comp[1] + x[1], m_comp[2] + x[2], m_comp[3] + x[3] ); + } + + // return component i=[0..3] - No range check! + int operator[](unsigned i) const { + return m_comp[i]; + } + + private: + int m_comp[4]; + }; + + //! this is called whenever one input line is processed completely + void NextSourceLine(); + + TmpPixel m_hbuf[4]; //! ring buffer for 4 input pixels + char *m_memory; //! buffer container + Filter *m_hor_filters; //! buffer for horizontal filters (one for each output image column) + Filter *m_ver_filters; //! buffer for vertical filters (one for each output image row) + TmpPixel *m_buffer; //! buffer contains 4 horizontally filtered input lines, multiplexed + unsigned *m_dst_image; //! pointer to destination image + unsigned m_dst_stride; //! destination image stride + unsigned m_dst_width; //! destination image width + unsigned m_dst_height; //! destination image height + unsigned m_src_width; //! source image width + unsigned m_src_height; //! source image height + unsigned m_src_x; //! x position of next source image pixel + unsigned m_src_y; //! y position of source image line currently beeing processed + unsigned m_dst_x; //! x position of next destination image pixel + unsigned m_dst_y; //! x position of next destination image line +}; + +#endif // _ImageScaler_h + |