aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jpeg.c54
-rw-r--r--src/jpeg.h3
-rw-r--r--src/main.c210
-rw-r--r--src/util.c3
-rw-r--r--src/util.h1
5 files changed, 271 insertions, 0 deletions
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 @@
+