aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/meh.h4
-rw-r--r--src/scale.c80
2 files changed, 76 insertions, 8 deletions
diff --git a/src/meh.h b/src/meh.h
index f2d5e3c..602ecee 100644
--- a/src/meh.h
+++ b/src/meh.h
@@ -33,8 +33,8 @@ struct image{
/* scale */
-void scale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf);
-void nearestscale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf);
+void scale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf);
+void nearestscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf);
/* XLib */
void setaspect(unsigned int w, unsigned int h);
diff --git a/src/scale.c b/src/scale.c
index 21fa505..6555af3 100644
--- a/src/scale.c
+++ b/src/scale.c
@@ -1,4 +1,6 @@
+#include <assert.h>
+#include <string.h>
#include <stdint.h>
#include <sys/time.h>
#include "meh.h"
@@ -34,9 +36,64 @@
ibuf = &img->buf[y * img->bufheight / height * img->bufwidth * 3];\
ibufn = ibuf + dy;
+/*
+ * Super sampling scale. Down only.
+ */
+static void superscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+ uint32_t x, y, i;
+ unsigned char * __restrict__ ibuf;
+ ibuf = &img->buf[0];
+
+ TDEBUG_START
+
+ int divx[bytesperline];
+ int divy[bytesperline];
+ memset(divx, 0, sizeof divx);
+ memset(divy, 0, sizeof divy);
+ for(x = 0; x < img->bufwidth; x++){
+ divx[x * width / img->bufwidth]++;
+ }
+ for(y = 0; y < img->bufheight; y++){
+ divy[y * height / img->bufheight]++;
+ }
+
+ int xoff[img->bufwidth];
+ for(x = 0; x < img->bufwidth; x++){
+ xoff[x] = (x * width / img->bufwidth) * 3;
+ }
-void scale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf){
- int x, y;
+ int tmp[width * 4];
+ unsigned int y0;
+ for(y = 0; y < img->bufheight;){
+ int ydiv = divy[y * height / img->bufheight];
+ char * __restrict__ ydest = &newBuf[bytesperline * (y * height / img->bufheight)];
+ memset(tmp, 0, sizeof tmp);
+ ibuf = &img->buf[y * img->bufwidth * 3];
+ for(y0 = y; y < y0 + ydiv; y++){
+ for(x = 0; x < img->bufwidth; x++){
+ int * __restrict__ dest = tmp + xoff[x];
+ for(i = 0; i < 3; i++){
+ *dest++ += *ibuf++;
+ }
+ }
+ }
+ int * __restrict__ src = tmp;
+ for(x = 0; x < width; x++){
+ ydest[2] = *src++ / ydiv / divx[x];
+ ydest[1] = *src++ / ydiv / divx[x];
+ ydest[0] = *src++ / ydiv / divx[x];
+ ydest += 4;
+ }
+ }
+
+ TDEBUG_END("superscale")
+}
+
+/*
+ * Bilinear scale. Used for up only.
+ */
+static void bilinearscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+ unsigned int x, y;
const unsigned char * __restrict__ ibuf;
const unsigned char * __restrict__ ibufn;
const unsigned char * const bufend = &img->buf[img->bufwidth * img->bufheight * 3];
@@ -86,11 +143,22 @@ void scale(struct image *img, int width, int height, int bytesperline, char* __r
y++;
}
- TDEBUG_END("scale")
+ TDEBUG_END("bilinearscale")
+}
+
+void scale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+ if(width < img->bufwidth){
+ superscale(img, width, height, bytesperline, newBuf);
+ }else{
+ bilinearscale(img, width, height, bytesperline, newBuf);
+ }
}
-void nearestscale(struct image *img, int width, int height, int bytesperline, char* __restrict__ newBuf){
- int x, y;
+/*
+ * Nearest neighbour. Fast up and down.
+ */
+void nearestscale(struct image *img, unsigned int width, unsigned int height, unsigned int bytesperline, char* __restrict__ newBuf){
+ unsigned int x, y;
unsigned char * __restrict__ ibuf;
unsigned int jdy = bytesperline / 4 - width;
unsigned int dx = (img->bufwidth << 10) / width;
@@ -111,7 +179,7 @@ void nearestscale(struct image *img, int width, int height, int bytesperline, ch
newBuf += jdy;
}
- TDEBUG_END("linearscale")
+ TDEBUG_END("nearestscale")
}