File mgp-bilinear-zoom.diff of Package mgp
---
image/zoom.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
mgp.c | 9 ++-
mgp.man | 2
3 files changed, 168 insertions(+), 2 deletions(-)
--- a/image/zoom.c
+++ b/image/zoom.c
@@ -11,6 +11,8 @@
#include "copyright.h"
#include "image.h"
+int smooth_scaling = 1;
+
static unsigned int *buildIndex(width, zoom, rwidth)
unsigned int width;
float zoom;
@@ -36,6 +38,144 @@ static unsigned int *buildIndex(width, z
return(index);
}
+static Pixel rgb8_to_true(r, g, b)
+ byte r;
+ byte g;
+ byte b;
+{
+ return (Pixel)r << 16 | (Pixel)g << 8 | (Pixel)b;
+}
+
+/* simple bilinear resampling */
+static void resize_image(oimage, image)
+ Image *oimage;
+ Image *image;
+{
+ double cx, cy, xoff, yoff;
+ double xstep, ystep;
+ int maxx, maxy;
+ int x1, x2, y1, y2;
+ int i, j;
+ byte *line1, *line2;
+ byte *destptr;
+ unsigned int srclinelen;
+ unsigned int pixlen;
+ Pixel v[4];
+ unsigned int r, g, b;
+
+ maxx = oimage->width - 1;
+ maxy = oimage->height - 1;
+ pixlen= oimage->pixlen;
+ srclinelen= oimage->width * pixlen;
+ destptr = image->data;
+ cy = 0;
+ xstep = (double)oimage->width / (double)image->width;
+ ystep = (double)oimage->height / (double)image->height;
+ for (j = image->height; j > 0; j--) {
+ y1 = cy;
+ if (y1 >= maxy) {
+ y1 = y2 = maxy;
+ yoff = 0;
+ } else {
+ y2 = y1 + 1;
+ yoff = cy - y1;
+ }
+ line1 = oimage->data + srclinelen * y1;
+ line2 = oimage->data + srclinelen * y2;
+ cx = 0;
+ for (i = image->width; i > 0; i--) {
+ x1 = cx;
+ if (x1 >= maxx) {
+ x1 = x2 = maxx;
+ xoff = 0;
+ } else {
+ x2 = x1 + 1;
+ xoff = cx - x1;
+ }
+ v[0] = memToVal(line1 + pixlen * x1, pixlen);
+ v[1] = memToVal(line1 + pixlen * x2, pixlen);
+ v[2] = memToVal(line2 + pixlen * x1, pixlen);
+ v[3] = memToVal(line2 + pixlen * x2, pixlen);
+ r = (TRUE_RED(v[0]) * (1 - xoff) +
+ TRUE_RED(v[1]) * xoff) * (1 - yoff) +
+ (TRUE_RED(v[2]) * (1 - xoff) +
+ TRUE_RED(v[3]) * xoff) * yoff;
+ g = (TRUE_GREEN(v[0]) * (1 - xoff) +
+ TRUE_GREEN(v[1]) * xoff) * (1 - yoff) +
+ (TRUE_GREEN(v[2]) * (1 - xoff) +
+ TRUE_GREEN(v[3]) * xoff) * yoff;
+ b = (TRUE_BLUE(v[0]) * (1 - xoff) +
+ TRUE_BLUE(v[1]) * xoff) * (1 - yoff) +
+ (TRUE_BLUE(v[2]) * (1 - xoff) +
+ TRUE_BLUE(v[3]) * xoff) * yoff;
+ v[0] = rgb8_to_true(r, g, b);
+ valToMem(v[0], destptr, pixlen);
+ destptr += pixlen;
+ cx += xstep;
+ }
+ cy += ystep;
+ }
+}
+
+/* reduce the given image in integer factor */
+static Image *reduced_image(oimage, width, height)
+ Image *oimage;
+ unsigned int width;
+ unsigned int height;
+{
+ Image *dest;
+ byte *destptr;
+ unsigned int srclinelen;
+ unsigned int i, j;
+ unsigned int factorx = oimage->width / width;
+ unsigned int factory = oimage->height / height;
+ unsigned int pixlen= oimage->pixlen;
+
+ if (factorx < 1)
+ factorx = 1;
+ if (factory < 1)
+ factory = 1;
+
+ width = oimage->width / factorx;
+ if (oimage->width % factorx)
+ width++;
+ height = oimage->height / factory;
+ if (oimage->height % factory)
+ height++;
+
+ dest = newTrueImage(width, height);
+ destptr = dest->data;
+
+ srclinelen = oimage->width * oimage->pixlen;
+
+ for (j = 0; j < oimage->height; j += factory) {
+ for (i = 0; i < oimage->width; i += factorx) {
+ unsigned int r, g, b, div, x, y;
+ Pixel v;
+
+ r = g = b= 0;
+ div = 0;
+ for (y = 0; y < factory && j + y < oimage->height; y++) {
+ byte *src = oimage->data + srclinelen * (j + y);
+ for (x = 0; x < factorx && i + x < oimage->width; x++) {
+ v = memToVal(src + pixlen * (i + x), pixlen);
+ r += TRUE_RED(v);
+ g += TRUE_GREEN(v);
+ b += TRUE_BLUE(v);
+ div++;
+ }
+ }
+ r /= div;
+ g /= div;
+ b /= div;
+ v = rgb8_to_true(r, g, b);
+ valToMem(v, destptr, pixlen);
+ destptr += pixlen;
+ }
+ }
+ return dest;
+}
+
Image *zoom(oimage, xzoom, yzoom, verbose)
Image *oimage;
float xzoom, yzoom;
@@ -145,8 +285,25 @@ Image *zoom(oimage, xzoom, yzoom, verbos
/* FALLTHRU */
case ITRUE:
- if (!RGBP(oimage))
+ if (!RGBP(oimage)) {
+ Image *tmpimage = NULL;
+ if (smooth_scaling && oimage->transparent == -1 &&
+ (oimage->width / xwidth > 1 || oimage->height / ywidth > 1)) {
+ tmpimage = reduced_image(oimage, xwidth, ywidth);
+ if (tmpimage->width == xwidth && tmpimage->height == ywidth) {
+ image = tmpimage;
+ break;
+ }
+ }
image= newTrueImage(xwidth, ywidth);
+ if (smooth_scaling && oimage->transparent == -1) {
+ resize_image(tmpimage ? tmpimage : oimage, image);
+ if (tmpimage)
+ freeImage(tmpimage);
+ break;
+ }
+ }
+
pixlen= oimage->pixlen;
destptr= image->data;
srcline= oimage->data;
--- a/mgp.c
+++ b/mgp.c
@@ -113,6 +113,8 @@ static int wantreload __P((void));
/*image*/
extern char *expandPath __P((char *));
+extern int smooth_scaling; /* in image/zoom.c */
+
#ifdef TTY_KEYINPUT
static void
susp(int sig)
@@ -261,7 +263,7 @@ main(argc, argv)
argv=tmp_argv;
argc=tmp_argc;
-#define ACCEPTOPTS "Bd:vVob:c:eg:f:hlGp:qt:Q:PSUT:D:CORw:X:x:nF:E:"
+#define ACCEPTOPTS "Bd:vVob:c:eg:f:hlGp:qt:Q:PsSUT:D:CORw:X:x:nF:E:"
while ((opt = getopt(argc, argv, ACCEPTOPTS)) != -1) {
#undef ACCEPTOPTS
switch (opt) {
@@ -342,6 +344,10 @@ main(argc, argv)
parse_debug++;
break;
+ case 's':
+ smooth_scaling = !smooth_scaling;
+ break;
+
case 'S':
mgp_flag |= FL_NOFORK;
break;
@@ -750,6 +756,7 @@ mgp_usage(name)
fprintf(stderr, "\t-U: Do process directives that forks process\n\t or allow to use non-ASCII filenames (unsecure mode)\n");
fprintf(stderr, "\t-T <timestampfile>: Update timestampfile on page refresh\n");
fprintf(stderr, "\t-P: print stderr from image conversion tools (by default it's discarded)\n");
+ fprintf(stderr, "\t-s: Toggle smooth image scaling\n");
fprintf(stderr, "\t-V: Be verbose\n");
fprintf(stderr, "\t-X <gsdevice>: ghostscript device to use\n");
fprintf(stderr, "\t--title <title>: Set window title\n");
--- a/mgp.man
+++ b/mgp.man
@@ -259,6 +259,8 @@ every time it updates the presentation w
This option is useful for external process to understand when
.Nm
modifies the window.
+.It Fl s
+Toggle the smooth image rendering by bilinear interpolation.
.It Fl V
Be verbose.
Generate debugging output to standard output.