diff options
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | src/jpeg.c | 54 | ||||
-rw-r--r-- | src/jpeg.h | 3 | ||||
-rw-r--r-- | src/main.c | 210 | ||||
-rw-r--r-- | src/util.c | 3 | ||||
-rw-r--r-- | src/util.h | 1 |
6 files changed, 297 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1b0e819 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ + +# User configuration +-include config.mk + +SRCFILES := $(wildcard src/*.c) +OBJFILES := $(SRCFILES:%.c=%.o) +DEPFILES := $(OBJFILES:%.o=%.d) +CLEANFILES := $(CLEANFILES) $(DEPFILES) $(OBJFILES) meh +CFLAGS := -O3 -Wall -g -ggdb +LIBS := -lX11 -ljpeg + +meh: $(OBJFILES) + $(CC) -o $@ $(OBJFILES) $(LIBS) + +-include $(DEPFILES) + +%.o: %.c Makefile + @echo "CC $<" + @$(CC) $(CFLAGS) -MMD -MP -MT "$*.d" -c -o $@ $< + +# Clean +clean: + $(RM) $(CLEANFILES) + +.PHONY: clean + diff --git a/src/jpeg.c b/src/jpeg.c new file mode 100644 index 0000000..6d3b40c --- /dev/null +++ b/src/jpeg.c @@ -0,0 +1,54 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "jpeglib.h" + +#include "jpeg.h" + +unsigned char *loadjpeg(char *filename, int *width, int *height){ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + FILE *infile; + JSAMPARRAY buffer; + int row_stride; + int i = 0; + int x, y; + unsigned char *retbuf; + + if((infile = fopen(filename, "rb")) == NULL){ + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, infile); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + *width = cinfo.output_width; + *height = cinfo.output_height; + retbuf = malloc(cinfo.output_components * (cinfo.output_width * cinfo.output_height)); + + if(cinfo.output_components != 3){ + fprintf(stderr, "TODO: greyscale images are not supported\n"); + exit(1); + } + row_stride = cinfo.output_width * cinfo.output_components; + buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + for(y = 0; y < cinfo.output_height; y++){ + jpeg_read_scanlines(&cinfo, buffer, 1); + for(x = 0; x < row_stride; x++){ + retbuf[i++] = buffer[0][x]; + } + assert(i % *width == 0); + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return retbuf; +} + + diff --git a/src/jpeg.h b/src/jpeg.h new file mode 100644 index 0000000..c834f76 --- /dev/null +++ b/src/jpeg.h @@ -0,0 +1,3 @@ + +unsigned char *loadjpeg(char *filename, int *width, int *height); + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..b4ce5ce --- /dev/null +++ b/src/main.c @@ -0,0 +1,210 @@ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "jpeg.h" +#include "util.h" + +Display *display; +int screen; +Window window; +GC gc; + +void usage(){ + printf("USAGE: meh [FILE1 [FILE2 [...]]]"); + exit(1); +} + +static int popcount(unsigned long mask){ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount(mask); +#else + int y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +#endif +} + + +unsigned int getshift(unsigned int mask){ + return popcount((mask - 1) & ~mask) & 31; +} + +XImage *create_image_from_buffer(unsigned char *buf, int width, int height, int bufwidth, int bufheight) { + int depth; + XImage *img = NULL; + Visual *vis; + unsigned int rshift, gshift, bshift; + int outIndex = 0; + int i; + int x,y; + int numBufBytes = (3 * bufwidth * bufheight); + + depth = DefaultDepth(display, screen); + vis = DefaultVisual(display, screen); + + rshift = getshift(vis->red_mask); + gshift = getshift(vis->green_mask); + bshift = getshift(vis->blue_mask); + + if (depth >= 24) { + size_t numNewBufBytes = (4 * (width * height)); + u_int32_t *newBuf = malloc(numNewBufBytes); + + //for(outIndex = 0; outIndex < width * height; outIndex++){ + for(y = 0; y < height; y++){ + for(x = 0; x < width; x++){ + unsigned int r, g, b; + i = (y * bufheight / height * bufwidth + x * bufwidth / width) * 3; + assert(i < numBufBytes); + r = (buf[i++] << rshift) & vis->red_mask; + g = (buf[i++] << gshift) & vis->green_mask; + b = (buf[i++] << bshift) & vis->blue_mask; + + newBuf[y * width + x] = r | g | b; + } + } + + img = XCreateImage (display, + CopyFromParent, depth, + ZPixmap, 0, + (char *) newBuf, + width, height, + 32, 0 + ); + + } else if (depth >= 15) { + exit(1); + size_t numNewBufBytes = (2 * (width * height)); + u_int16_t *newBuf = malloc (numNewBufBytes); + + for (i = 0; i < numBufBytes;) { + unsigned int r, g, b; + r = (buf[i++] << rshift) & vis->red_mask; + g = (buf[i++] << gshift) & vis->green_mask; + b = (buf[i++] << bshift) & vis->blue_mask; + + newBuf[outIndex++] = r | g | b; + } + + img = XCreateImage (display, + CopyFromParent, depth, + ZPixmap, 0, + (char *) newBuf, + width, height, + 16, 0 + ); + } else { + fprintf (stderr, "This program does not support displays with a depth less than 15."); + exit(1); + return NULL; + } + + XInitImage (img); + + return img; +} + + +void init(){ + display = XOpenDisplay (NULL); + assert(display); + screen = DefaultScreen(display); + + window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 640, 480, 0, DefaultDepth(display, screen), InputOutput, CopyFromParent, 0, NULL); + gc = XCreateGC(display, window, 0, NULL); + + XMapRaised(display, window); + XSelectInput(display, window, StructureNotifyMask | ExposureMask | KeyPressMask); + XFlush(display); +} + +void run(char *images[], int length){ + int i = 0; + int bufwidth, bufheight; + int width = 0, height = 0; + XImage *img = NULL; + unsigned char *buf = NULL; + int redraw = 0; + + for(;;){ + XEvent event; + XNextEvent(display, &event); + switch(event.type){ + case MapNotify: + printf("MapNotify\n"); + break; + case ConfigureNotify: + printf("ConfigureNotify(%i, %i, %i, %i)\n", event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height); + if(width != event.xconfigure.width || height != event.xconfigure.height){ + if(img) + free(img); + img = NULL; + width = event.xconfigure.width; + height = event.xconfigure.height; + } + break; + case Expose: + redraw = 1; + break; + case KeyPress: + switch(XLookupKeysym(&event.xkey, 0)){ + case XK_Escape: + exit(0); + break; + case XK_q: + exit(0); + break; + case XK_t: + i = (i + 1) % length; + if(img) + free(img); + if(buf) + free(buf); + img = NULL; + buf = NULL; + redraw = 1; + break; + case XK_n: + i = i ? i - 1 : length - 1; + if(img) + free(img); + if(buf) + free(buf); + img = NULL; + buf = NULL; + redraw = 1; + break; + } + break; + } + if(redraw){ + if(!buf) + buf = loadjpeg(images[i], &bufwidth, &bufheight); + assert(buf); + if(!img) + img = create_image_from_buffer(buf, width, height, bufwidth, bufheight); + assert(img); + XPutImage(display, window, gc, img, 0, 0, 0, 0, width, height); + XFlush(display); + redraw = 0; + } + } +} + +int main(int argc, char *argv[]){ + if(argc < 2) + usage(); + init(); + + run(&argv[1], argc - 1); + + return 0; +} + diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..55538e7 --- /dev/null +++ b/src/util.c @@ -0,0 +1,3 @@ + +#include "util.h" + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/util.h @@ -0,0 +1 @@ + |