/*
* Create a tiled interface and draw it.
*
*
* Compile with:
* gcc -g -O2 -o tileTest tileTest.c -ltiff -lgeotiff \
* `pkg-config --libs --cflags gtk+-2.0`
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <gtk/gtk.h>
#include <tiffio.h>
#include <xtiffio.h>
//#include <geotiff.h>
//#include <geo_normalize.h>
#define APPNAME "tileTest"
#define WIDTH 640
#define HEIGHT 480
static GdkPixbuf *pixbuf;
static TIFF *tiff;
static void
FillGradient(guchar *pixels, uint32 chan, uint32 rs, uint32 w, uint32 h)
{
int x, y;
guchar *p;
/*
* Pattern goes like:
*
* (0,0,0) ... (X,X/2,0)
* . .
* . .
* . .
* (0,Y/2,Y) ... (X,X/2+Y/2,Y)
*
* X and Y are normalized from 0:width-1 and 0:height-1 to 0:255 and 0:255.
*
*/
#define NORM(v,a) ((v) * 256 / (a))
for (x = 0; x < w; x++) {
for (y = 0; y < h; y++) {
int r, g, b;
r = NORM(x, w);
b = NORM(y, h);
g = r / 2 + b / 2;
p = pixels + y * rs + x * chan;
p[0] = r;
p[1] = g;
p[2] = b;
p[3] = 255;
}
}
}
struct BackingStore {
uint32 w; // width of bs
uint32 h; // height of bs
uint32 x; // offset into bs of viewport
uint32 y; // offset into bs of viewport
uint8 *buf;
};
static struct BackingStore *bs = NULL;
void
FreeBackingStore(void)
{
free(bs->buf);
free(bs);
}
void
AllocBackingStore(uint32 w, uint32 h)
{
assert(bs == NULL);
bs = malloc(sizeof(struct BackingStore));
if (bs == NULL) {
fprintf(stderr, "Failed to alloc backing store: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
bs->buf = malloc(w * h * 16); // 4 bytes/pixel and 2x width and height
if (bs == NULL) {
free(bs);
fprintf(stderr, "Failed to alloc backing store buffer: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
bs->w = w * 2;
bs->h = h * 2;
bs->x = 0;
bs->y = 0;
}
void
UpdateBackingStore(uint32 vx, uint32 vy, uint32 vw, uint32 vh)
{
}
void
FillImage(guchar *pixels, uint32 chan, uint32 rs, uint32 w, uint32 h)
{
/* w, h => viewport width, height */
/* rs => row stride */
uint32 tw, th, npix, *ras; /* TIFF width, height, number of pixels, raster */
uint32 txo, tyo; /* TIFF X offset, Y offset to start of viewport */
uint32 xo, yo;
uint32 W, H, x, y;
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &tw);
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &th);
npix = tw * th;
printf("image width %u, height %u, npix %u\n", tw, th, npix);
ras = (uint32 *)_TIFFmalloc(npix * 4);
if (ras == NULL) {
fprintf(stderr, "Failed to _TIFFmalloc %u bytes!\n", npix * 4);
gtk_main_quit();
return;
}
/*
* Figure out viewport.
*/
if (tw > w) {
txo = (tw - w) / 2;
W = w;
xo = 0;
} else if (tw < w) {
txo = 0;
W = tw;
xo = (w - tw) / 2;
} else {
txo = xo = 0;
W = w;
}
if (th > h) {
tyo = (th - h) / 2;
H = h;
yo = 0;
} else if (th < h) {
tyo = 0;
H = th;
yo = (h - th) / 2;
} else {
tyo = yo = 0;
H = h;
}
printf("TIFF offset (%u,%u), pixbuf offset (%u,%u), (W,H) (%u,%u)\n",
txo, tyo, xo, yo, W, H);
if (TIFFIsTiled(tiff)) {
printf("image is tiled, size = %u bytes\n", TIFFTileSize(tiff));
} else {
printf("image has %u strips, scanline size = %u\n",
TIFFNumberOfStrips(tiff), TIFFScanlineSize(tiff));
}
if (!TIFFReadRGBAImage(tiff, tw, th, ras, 0)) {
fprintf(stderr, "TIFFReadRGBAImage failed\n");
goto out;
}
/* if (!TIFFReadRGBAImageOriented(tiff, tw, th, ras, 0, ORIENTATION_TOPLEFT)) { */
/* fprintf(stderr, "Failed to TIFFReadRGBAImage!\n"); */
/* gtk_main_quit(); */
/* return; */
/* } */
for (x = 0; x < W; x++) {
for (y = 0; y < H; y++) {
guchar *p;
uint32 *tp;
//uint8 r, g, b;
p = pixels + (y + yo) * rs + (x + xo) * chan;
tp = ras + (y + tyo) * tw + (x + txo);
p[0] = TIFFGetR(*tp);
p[1] = TIFFGetG(*tp);
p[2] = TIFFGetB(*tp);
p[3] = TIFFGetA(*tp);
/* printf("(x,y,r,g,b,A) => (%u,%u,%hhu,%hhu,%hhu,%hhu)\n", */
/* x, y, p[0], p[1], p[2], p[3]); */
}
}
out:
_TIFFfree(ras);
}
void
FillPixbuf(void)
{
uint32 chan, w, h, rs;
guchar *pixels;
pixels = gdk_pixbuf_get_pixels(pixbuf);
chan = gdk_pixbuf_get_n_channels(pixbuf);
rs = gdk_pixbuf_get_rowstride(pixbuf);
w = gdk_pixbuf_get_width(pixbuf);
h = gdk_pixbuf_get_height(pixbuf);
FillGradient(pixels, chan, rs, w, h);
FillImage(pixels, chan, rs, w, h);
}
gboolean
quit(GtkWidget *widget, GdkEvent *thisevent, gpointer data)
{
gtk_main_quit();
return TRUE;
}
gboolean
expose(GtkWidget *widget, GdkEvent *thisevent, gpointer data)
{
gdk_draw_pixbuf(widget->window, NULL, pixbuf, 0, 0, 0, 0, -1, -1,
GDK_RGB_DITHER_NONE, 0, 0);
return TRUE;
}
void
ui(void)
{
GtkWidget *window, *img;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), APPNAME);
gtk_window_set_default_size(GTK_WINDOW(window), WIDTH, HEIGHT);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
g_signal_connect(G_OBJECT (window), "delete_event", G_CALLBACK(quit),NULL);
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, WIDTH, HEIGHT);
FillPixbuf();
img = gtk_drawing_area_new();
gtk_widget_set_size_request(img, WIDTH, HEIGHT);
g_signal_connect(G_OBJECT(img), "expose_event", G_CALLBACK(expose), NULL);
gtk_container_add(GTK_CONTAINER(window), img);
gtk_widget_show_all(window);
}
int
main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
if (argc != 2) {
fprintf(stderr, "Missing filename\n");
exit(EXIT_FAILURE);
}
if ((tiff = TIFFOpen(argv[1], "r")) == NULL) {
fprintf(stderr, "Failed to open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
ui();
g_set_application_name(APPNAME);
AllocBackingStore(WIDTH, HEIGHT);
gtk_main();
FreeBackingStore();
TIFFClose(tiff);
return 0;
}