Logo Search packages:      
Sourcecode: fbi version File versions  Download package

viewer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <signal.h>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/extensions/XShm.h>

#include "ida.h"
#include "x11.h"
#include "dither.h"
#include "readers.h"
#include "viewer.h"
#include "hex.h"
#include "idaconfig.h"

/* ----------------------------------------------------------------------- */

#define POINTER_NORMAL    0
#define POINTER_BUSY      1
#define POINTER_PICK      2
#define RUBBER_NEW        3
#define RUBBER_MOVE       4
#define RUBBER_X1         5
#define RUBBER_Y1         6
#define RUBBER_X2         7
#define RUBBER_Y2         8

#define RUBBER_RANGE      6
#define RUBBER_INTERVAL 100

#define PROCESS_LINES    16

int debug;
Cursor ptrs[POINTER_COUNT];

/* ----------------------------------------------------------------------- */

Pixmap image_to_pixmap(struct ida_image *img)
{
    unsigned char line[256],*src;
    XImage *ximage;
    void *shm;
    Pixmap pix;
    GC gc;
    unsigned int x,y;

    ximage = x11_create_ximage(app_shell, img->i.width, img->i.height, &shm);
    for (y = 0; y < img->i.height; y++) {
      src = img->data + 3*y*img->i.width;
      if (display_type == PSEUDOCOLOR) {
          dither_line(src, line, y, img->i.width);
          for (x = 0; x < img->i.width; x++)
            XPutPixel(ximage, x, y, x11_map[line[x]]);
      } else {
          for (x = 0; x < img->i.width; x++, src += 3) {
            pix = x11_lut_red[src[0]] |
                x11_lut_green[src[1]] |
                x11_lut_blue[src[2]];
            XPutPixel(ximage, x, y, pix);
          }
      }
    }
    pix = XCreatePixmap(dpy,XtWindow(app_shell),img->i.width, img->i.height,
                  DefaultDepthOfScreen(XtScreen(app_shell)));
    gc = XCreateGC(dpy, pix, 0, NULL);
    XPUTIMAGE(dpy, pix, gc, ximage, 0, 0, 0, 0, img->i.width, img->i.height);
    XFreeGC(dpy, gc);
    x11_destroy_ximage(app_shell, ximage, shm);
    return pix;
}

/* ----------------------------------------------------------------------- */

int viewer_i2s(int zoom, int val)
{
    if (0 > zoom)
      return val/(-zoom+1);
    if (0 < zoom)
      return val*(zoom+1);
    return val;
}

/* ----------------------------------------------------------------------- */

static void
viewer_renderline(struct ida_viewer *ida, char *scanline)
{
    unsigned char *src,*dst,*rgb;
    unsigned long pix;
    unsigned int x,s,scrline;

    src = scanline;

    if (0 == ida->zoom) {
      /* as-is */
      if (display_type == PSEUDOCOLOR) {
          dst = ida->dither_line;
          dither_line(src, dst, ida->line, ida->scrwidth);
          for (x = 0; x < ida->scrwidth; x++, dst++)
            XPutPixel(ida->ximage, x, ida->line, x11_map[*dst]);
      } else {
          for (x = 0; x < ida->scrwidth; x++, src += 3) {
            pix = x11_lut_red[src[0]] |
                x11_lut_green[src[1]] |
                x11_lut_blue[src[2]];
            XPutPixel(ida->ximage, x, ida->line, pix);
          }
      }

    } else if (ida->zoom < 0) {
      /* zoom out */
      s = -ida->zoom+1;
      if (s-1 != (ida->line % s))
          return;
      scrline = ida->line/s;
      if (display_type == PSEUDOCOLOR) {
          rgb = ida->rgb_line;
          for (x = 0; x < ida->scrwidth; x++, rgb += 3, src += 3*s) {
            rgb[0] = src[0];
            rgb[1] = src[1];
            rgb[2] = src[2];
          }
          rgb = ida->rgb_line;
          dst = ida->dither_line;
          dither_line(rgb, dst, scrline, ida->scrwidth);
          for (x = 0; x < ida->scrwidth; x++, dst++)
            XPutPixel(ida->ximage, x, scrline, x11_map[*dst]);
      } else {
#if 0
          /* just drop pixels */
          for (x = 0; x < ida->scrwidth; x++, src += 3*s) {
            pix = x11_lut_red[src[0]] |
                x11_lut_green[src[1]] |
                x11_lut_blue[src[2]];
            XPutPixel(ida->ximage, x, scrline, pix);
          }
#else
          /* horizontal interpolation (vertical is much harder ...) */
          for (x = 0; x < ida->scrwidth; x++, src += 3*s) {
            int red,green,blue,count,ix;
            red   = 0;
            green = 0;
            blue  = 0;
            count = 0;
            for (ix = 0; ix < 3*s; ix += 3) {
                red   += src[ix+0];
                green += src[ix+1]; 
                blue  += src[ix+2]; 
                count += 1;
            }
            pix = x11_lut_red[red/count] |
                x11_lut_green[green/count] |
                x11_lut_blue[blue/count];
            XPutPixel(ida->ximage, x, scrline, pix);
          }
#endif
      }
      
    } else {
      /* zoom in */
      s = ida->zoom+1;
      if (display_type == PSEUDOCOLOR) {
          rgb = ida->rgb_line;
          for (x = 0; x < ida->scrwidth; rgb += 3) {
            rgb[0] = src[0];
            rgb[1] = src[1];
            rgb[2] = src[2];
            x++;
            if (0 == (x%s))
                src += 3;
          }
          for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) {
            rgb = ida->rgb_line;
            dst = ida->dither_line;
            dither_line(rgb, dst, scrline, ida->scrwidth);
            for (x = 0; x < ida->scrwidth; x++, dst++)
                XPutPixel(ida->ximage, x, scrline, x11_map[*dst]);
          }
      } else {
          for (scrline = ida->line*s; scrline < ida->line*s+s; scrline++) {
            src = scanline;
            for (x = 0; x < ida->scrwidth; src += 3) {
                unsigned int i;
                pix = x11_lut_red[src[0]] |
                  x11_lut_green[src[1]] |
                  x11_lut_blue[src[2]];
                for (i = 0; i < s; i++, x++)
                  XPutPixel(ida->ximage, x, scrline, pix);
            }
          }
      }
    }
}

/* ----------------------------------------------------------------------- */

static void
viewer_cleanup(struct ida_viewer *ida)
{
    if (ida->load_read) {
      ida->load_done(ida->load_data);
      ida->load_line = 0;
      ida->load_read = NULL;
      ida->load_done = NULL;
      ida->load_data = NULL;
    }
    if (ida->op_work) {
      ida->op_done(ida->op_data);
      ida->op_line = 0;
      ida->op_work = NULL;
      ida->op_done = NULL;
      ida->op_data = NULL;
      if (ida->op_src.data) {
          if (ida->undo.data) {
            fprintf(stderr,"have undo buffer /* shouldn't happen */");
            free(ida->undo.data);
          }
          ida->undo = ida->op_src;
          memset(&ida->op_src,0,sizeof(ida->op_src));
      }
    }
}

static Boolean
viewer_workproc(XtPointer client_data)
{
    struct ida_viewer *ida = client_data;
    unsigned int start,end;
    char *scanline;

    start = ida->line;
    end   = ida->line + ida->steps;
    if (end > ida->img.i.height)
      end = ida->img.i.height;

    /* image loading */
    if (ida->load_read) {
      for (ida->line = start; ida->line < end; ida->line++) {
          if (ida->load_line > ida->line)
            continue;
          scanline = ida->img.data + ida->img.i.width * ida->load_line * 3;
          ida->load_read(scanline,ida->load_line,ida->load_data);
          ida->load_line++;
      }
    }

    /* image processing */
    if (ida->op_work  &&  0 == ida->op_preview) {
      for (ida->line = start; ida->line < end; ida->line++) {
          if (ida->op_line > ida->line)
            continue;
          scanline = ida->img.data + ida->img.i.width * ida->op_line * 3;
          ida->op_work(&ida->op_src,&ida->op_rect,
                  scanline,ida->op_line,ida->op_data);
          ida->op_line++;
      }
    }

    /* image rendering */
    if (ida->op_work  && ida->op_preview) {
      for (ida->line = start; ida->line < end; ida->line++) {
          ida->op_line = ida->line;
          ida->op_work(&ida->img,&ida->op_rect,
                   ida->preview_line,ida->line,ida->op_data);
          viewer_renderline(ida,ida->preview_line);
      }
    } else {
      for (ida->line = start; ida->line < end; ida->line++) {
          scanline = ida->img.data + ida->img.i.width * ida->line * 3;
          viewer_renderline(ida,scanline);
      }
    }

    /* trigger redraw */
    XClearArea(XtDisplay(ida->widget), XtWindow(ida->widget),
             0, viewer_i2s(ida->zoom,start),
             ida->scrwidth, viewer_i2s(ida->zoom,ida->steps), True);

    /* all done ? */
    if (ida->line == ida->img.i.height) {
      viewer_cleanup(ida);
      ida->wproc = 0;
#if 1
      if (args.testload)
          XtCallActionProc(ida->widget,"Next",NULL,NULL,0);
#endif
      return TRUE;
    }
    return FALSE;
}

static void viewer_workstart(struct ida_viewer *ida)
{
    /* (re-) start */
    ida->line  = 0;
    if (!ida->wproc)
      ida->wproc = XtAppAddWorkProc(app_context,viewer_workproc,ida);
}

static void viewer_workstop(struct ida_viewer *ida)
{
    if (!ida->wproc)
      return;

    viewer_cleanup(ida);
    XtRemoveWorkProc(ida->wproc);
    ida->wproc = 0;
}

static void viewer_workfinish(struct ida_viewer *ida)
{
    char *scanline;

    if (ida->load_read) {
      for (ida->line = ida->load_line; ida->line < ida->img.i.height;) {
          scanline = ida->img.data + ida->img.i.width * ida->line * 3;
          ida->load_read(scanline,ida->load_line,ida->load_data);
          ida->line++;
          ida->load_line++;
      }
    }
    if (ida->op_work && 0 == ida->op_preview) {
      for (ida->line = ida->op_line; ida->line < ida->img.i.height;) {
          scanline = ida->img.data + ida->img.i.width * ida->line * 3;
          ida->op_work(&ida->op_src,&ida->op_rect,
                  scanline,ida->op_line,ida->op_data);
          ida->line++;
          ida->op_line++;
      }
    }
    viewer_workstop(ida);
}

/* ----------------------------------------------------------------------- */

static void
viewer_new_view(struct ida_viewer *ida)
{
    if (NULL != ida->ximage)
      x11_destroy_ximage(ida->widget,ida->ximage,ida->ximage_shm);
    if (NULL != ida->rgb_line)
      free(ida->rgb_line);
    if (NULL != ida->dither_line)
      free(ida->dither_line);
    if (NULL != ida->preview_line)
      free(ida->preview_line);

    ida->scrwidth  = viewer_i2s(ida->zoom,ida->img.i.width);
    ida->scrheight = viewer_i2s(ida->zoom,ida->img.i.height);
    ida->steps = PROCESS_LINES;
    if (ida->zoom < 0)
      while ((ida->steps % (-ida->zoom+1)) != 0)
          ida->steps++;

    ida->rgb_line = malloc(ida->scrwidth*3);
    ida->dither_line = malloc(ida->scrwidth);
    ida->preview_line = malloc(ida->img.i.width*3);
    ida->ximage = x11_create_ximage(ida->widget, ida->scrwidth, ida->scrheight,
                           &ida->ximage_shm);
    if (NULL == ida->ximage) {
      ida->zoom--;
      return viewer_new_view(ida);
    }
    XtVaSetValues(ida->widget,
              XtNwidth,  ida->scrwidth,
              XtNheight, ida->scrheight,
              NULL);
    viewer_workstart(ida);
}

static void
viewer_timeout(XtPointer client_data, XtIntervalId *id);

static int
viewer_rubber_draw(struct ida_viewer *ida)
{
    XGCValues values;
    struct ida_rect r = ida->current;
    int x,y,w,h;

    values.function   = GXxor;
    values.foreground = ida->mask;
    XChangeGC(dpy,ida->wgc,GCFunction|GCForeground,&values);
    if (r.x1 < r.x2) {
      x = viewer_i2s(ida->zoom,r.x1);
      w = viewer_i2s(ida->zoom,r.x2 - r.x1);
    } else {
      x = viewer_i2s(ida->zoom,r.x2);
      w = viewer_i2s(ida->zoom,r.x1 - r.x2);
    }
    if (r.y1 < r.y2) {
      y = viewer_i2s(ida->zoom,r.y1);
      h = viewer_i2s(ida->zoom,r.y2 - r.y1);
    } else {
      y = viewer_i2s(ida->zoom,r.y2);
      h = viewer_i2s(ida->zoom,r.y1 - r.y2);
    }
    if (0 == h && 0 == w)
      return 0;
    if (w)
      w--;
    if (h)
      h--;
    XDrawRectangle(dpy,XtWindow(ida->widget),ida->wgc,x,y,w,h);
    return 1;
}

static void
viewer_rubber_off(struct ida_viewer *ida)
{
    if (ida->marked)
      viewer_rubber_draw(ida);
    ida->marked = 0;
    if (ida->timer)
      XtRemoveTimeOut(ida->timer);
    ida->timer = 0;
}

static void
viewer_rubber_on(struct ida_viewer *ida)
{
    ida->marked = viewer_rubber_draw(ida);
    if (ida->marked)
      ida->timer = XtAppAddTimeOut(app_context,RUBBER_INTERVAL,
                            viewer_timeout,ida);
}

static void
viewer_timeout(XtPointer client_data, XtIntervalId *id)
{
    struct ida_viewer *ida = client_data;

    ida->timer = 0;
    viewer_rubber_off(ida);
    ida->mask <<= 1;
    if ((ida->mask & 0x10) == 0x10)
      ida->mask |= 0x01;
    viewer_rubber_on(ida);
}

static void
viewer_redraw(Widget widget, XtPointer client_data,
            XEvent *ev, Boolean *cont)
{
    struct ida_viewer *ida = client_data;
    XExposeEvent *event;
    XGCValues values;

    if (ev->type != Expose)
      return;
    event = (XExposeEvent*)ev;
    
    if (NULL == ida->ximage)
      return;
    if (event->x + event->width > (int)ida->scrwidth)
      return;
    if (event->y + event->height > (int)ida->scrheight)
      return;
    if (NULL == ida->wgc)
      ida->wgc = XCreateGC(XtDisplay(widget), XtWindow(widget), 0, NULL);

    viewer_rubber_off(ida);
    values.function   = GXcopy;
    XChangeGC(dpy,ida->wgc,GCFunction,&values);
    XPUTIMAGE(XtDisplay(ida->widget), XtWindow(widget),
            ida->wgc, ida->ximage,
            event->x, event->y, event->x, event->y,
            event->width, event->height);
    viewer_rubber_on(ida);
}

static int
viewer_pos2state(struct ida_viewer *ida, int x, int y)
{
    int x1,x2,y1,y2;

    if (POINTER_PICK == ida->state)
      return ida->state;

    x1 = viewer_i2s(ida->zoom,ida->current.x1);
    x2 = viewer_i2s(ida->zoom,ida->current.x2);
    y1 = viewer_i2s(ida->zoom,ida->current.y1);
    y2 = viewer_i2s(ida->zoom,ida->current.y2);
    if ((x1 < x && x < x2) || (x2 < x && x < x1)) {
      if (y1-RUBBER_RANGE < y && y < y1+RUBBER_RANGE)
          return RUBBER_Y1;
      if (y2-RUBBER_RANGE < y && y < y2+RUBBER_RANGE)
          return RUBBER_Y2;
    }
    if ((y1 < y && y < y2) || (y2 < y && y < y1)) {
      if (x1-RUBBER_RANGE < x && x < x1+RUBBER_RANGE)
          return RUBBER_X1;
      if (x2-RUBBER_RANGE < x && x < x2+RUBBER_RANGE)
          return RUBBER_X2;
    }
    if (((x1 < x && x < x2) || (x2 < x && x < x1)) &&
      ((y1 < y && y < y2) || (y2 < y && y < y1)))
      return RUBBER_MOVE;
    return RUBBER_NEW;
}

static void
viewer_mouse(Widget widget, XtPointer client_data,
           XEvent *ev, Boolean *cont)
{
    struct ida_viewer *ida = client_data;
    int state = POINTER_NORMAL;
    unsigned char *pix;
    int x,y;
    
    viewer_rubber_off(ida);

    switch (ev->type) {
    case ButtonPress:
    {
      XButtonEvent *eb = (XButtonEvent*)ev;

      if (eb->button != Button1)
          goto out;
      ida->state = viewer_pos2state(ida,eb->x,eb->y);
      switch (ida->state) {
      case POINTER_PICK:
          x = viewer_i2s(-ida->zoom,eb->x);
          y = viewer_i2s(-ida->zoom,eb->y);
          pix = ida->img.data + ida->img.i.width*y*3 + x*3;
          ida->pick_cb(x,y,pix,ida->pick_data);
          ida->pick_cb = NULL;
          ida->pick_data = NULL;
          ida->state = POINTER_NORMAL;
          state = POINTER_NORMAL;
          break;
      case RUBBER_NEW:
          ida->mask = 0x33333333;
          ida->current.x1 = ida->current.x2 = viewer_i2s(-ida->zoom,eb->x);
          ida->current.y1 = ida->current.y2 = viewer_i2s(-ida->zoom,eb->y);
          break;
      case RUBBER_MOVE:
          ida->last_x = viewer_i2s(-ida->zoom,eb->x);
          ida->last_y = viewer_i2s(-ida->zoom,eb->y);
          break;
      case RUBBER_X1:
          ida->current.x1 = viewer_i2s(-ida->zoom,eb->x);
          break;
      case RUBBER_Y1:
          ida->current.y1 = viewer_i2s(-ida->zoom,eb->y);
          break;
      case RUBBER_X2:
          ida->current.x2 = viewer_i2s(-ida->zoom,eb->x);
          break;
      case RUBBER_Y2:
          ida->current.y2 = viewer_i2s(-ida->zoom,eb->y);
          break;
      }
      state = ida->state;
      break;
    }
    case MotionNotify:
    {
      XMotionEvent *em = (XMotionEvent*)ev;

      if (!(em->state & Button1Mask)) {
          state = viewer_pos2state(ida,em->x,em->y);
          goto out;
      }
      switch (ida->state) {
      case RUBBER_NEW:
          ida->current.x2 = viewer_i2s(-ida->zoom,em->x);
          ida->current.y2 = viewer_i2s(-ida->zoom,em->y);
          if (em->state & ShiftMask) {
            /* square selection */
            int xlen,ylen;
            xlen = abs(ida->current.x1 - ida->current.x2);
            ylen = abs(ida->current.y1 - ida->current.y2);
            if (ylen > xlen) {
                if (ida->current.x1 < ida->current.x2)
                  ida->current.x2 -= (xlen - ylen);
                else
                  ida->current.x2 += (xlen - ylen);
            } else {
                if (ida->current.y1 < ida->current.y2)
                  ida->current.y2 -= (ylen - xlen);
                else
                  ida->current.y2 += (ylen - xlen);
            }
          }
          break;
      case RUBBER_MOVE:
          x = viewer_i2s(-ida->zoom,em->x);
          y = viewer_i2s(-ida->zoom,em->y);
          ida->current.x1 += (x - ida->last_x);
          ida->current.x2 += (x - ida->last_x);
          ida->current.y1 += (y - ida->last_y);
          ida->current.y2 += (y - ida->last_y);
          ida->last_x = x;
          ida->last_y = y;
          break;
      case RUBBER_X1:
          ida->current.x1 = viewer_i2s(-ida->zoom,em->x);
          break;
      case RUBBER_Y1:
          ida->current.y1 = viewer_i2s(-ida->zoom,em->y);
          break;
      case RUBBER_X2:
          ida->current.x2 = viewer_i2s(-ida->zoom,em->x);
          break;
      case RUBBER_Y2:
          ida->current.y2 = viewer_i2s(-ida->zoom,em->y);
          break;
      }
      state = ida->state;
      break;
    }
    case ButtonRelease:
    {
      XButtonEvent *eb = (XButtonEvent*)ev;

      if (eb->button != Button1)
          goto out;
      ida->state = POINTER_NORMAL;
      state = ida->state;
      break;
    }
    }

    if (ida->current.x1 < 0)
      ida->current.x1 = 0;
    if (ida->current.x1 > ida->img.i.width)
      ida->current.x1 = ida->img.i.width;
    if (ida->current.x2 < 0)
      ida->current.x2 = 0;
    if (ida->current.x2 > ida->img.i.width)
      ida->current.x2 = ida->img.i.width;
    if (ida->current.y1 < 0)
      ida->current.y1 = 0;
    if (ida->current.y1 > ida->img.i.height)
      ida->current.y1 = ida->img.i.height;
    if (ida->current.y2 < 0)
      ida->current.y2 = 0;
    if (ida->current.y2 > ida->img.i.height)
      ida->current.y2 = ida->img.i.height;

 out:
    XDefineCursor(dpy, XtWindow(widget), ptrs[state]);
    viewer_rubber_on(ida);
}

/* ----------------------------------------------------------------------- */
/* public stuff                                                            */

void viewer_pick(struct ida_viewer *ida, viewer_pick_cb cb, XtPointer data)
{
    if (POINTER_NORMAL != ida->state)
      return;
    if (debug)
      fprintf(stderr,"viewer_pick\n");
    ida->state = POINTER_PICK;
    ida->pick_cb   = cb;
    ida->pick_data = data;
}

void viewer_unpick(struct ida_viewer *ida)
{
    if (POINTER_PICK != ida->state)
      return;
    if (debug)
      fprintf(stderr,"viewer_unpick\n");
    ida->state = POINTER_NORMAL;
    ida->pick_cb   = NULL;
    ida->pick_data = NULL;
}

void
viewer_autozoom(struct ida_viewer *ida)
{
    if (GET_AUTOZOOM()) {
      ida->zoom = 0;
      while (XtScreen(ida->widget)->width  < viewer_i2s(ida->zoom,ida->img.i.width) ||
             XtScreen(ida->widget)->height < viewer_i2s(ida->zoom,ida->img.i.height))
          ida->zoom--;
    }
    viewer_new_view(ida);
}

void
viewer_setzoom(struct ida_viewer *ida, int zoom)
{
    ida->zoom = zoom;
    viewer_new_view(ida);
}

static void
viewer_op_rect(struct ida_viewer *ida)
{
    if (ida->current.x1 == ida->current.x2 &&
      ida->current.y1 == ida->current.y2) {
      /* full image */
      ida->op_rect.x1 = 0;
      ida->op_rect.x2 = ida->img.i.width;
      ida->op_rect.y1 = 0;
      ida->op_rect.y2 = ida->img.i.height;
      return;
    } else {
      /* have selection */
      if (ida->current.x1 < ida->current.x2) {
          ida->op_rect.x1 = ida->current.x1;
          ida->op_rect.x2 = ida->current.x2;
      } else {
          ida->op_rect.x1 = ida->current.x2;
          ida->op_rect.x2 = ida->current.x1;
      }
      if (ida->current.y1 < ida->current.y2) {
          ida->op_rect.y1 = ida->current.y1;
          ida->op_rect.y2 = ida->current.y2;
      } else {
          ida->op_rect.y1 = ida->current.y2;
          ida->op_rect.y2 = ida->current.y1;
      }
    }
}

int
viewer_start_op(struct ida_viewer *ida, struct ida_op *op, void *parm)
{
    struct ida_image dst;

    ptr_busy();
    viewer_workfinish(ida);
    viewer_rubber_off(ida);

    /* try init */
    viewer_op_rect(ida);
    if (debug)
      fprintf(stderr,"viewer_start_op: init %s(%p)\n",op->name,parm);
    ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm);
    ptr_idle();
    if (NULL == ida->op_data)
      return -1;
    dst.data = malloc(dst.i.width * dst.i.height * 3);

    /* prepare background processing */
    if (ida->undo.data) {
      free(ida->undo.data);
      memset(&ida->undo,0,sizeof(ida->undo));
    }
    if (ida->op_src.data) {
      fprintf(stderr,"have op_src buffer /* shouldn't happen */");
      free(ida->op_src.data);
    }
    ida->op_src = ida->img;
    ida->img = dst;
    ida->op_line = 0;
    ida->op_work = op->work;
    ida->op_done = op->done;
    ida->op_preview = 0;

    if (ida->op_src.i.width  != ida->img.i.width ||
      ida->op_src.i.height != ida->img.i.height) {
      memset(&ida->current,0,sizeof(ida->current));
      viewer_autozoom(ida);
    } else
      viewer_new_view(ida);
    return 0;
}

int
viewer_undo(struct ida_viewer *ida)
{
    int resize;

    viewer_workfinish(ida);
    if (NULL == ida->undo.data)
      return -1;
    viewer_rubber_off(ida);
    memset(&ida->current,0,sizeof(ida->current));
    
    resize = (ida->undo.i.width  != ida->img.i.width ||
            ida->undo.i.height != ida->img.i.height);
    free(ida->img.data);
    ida->img = ida->undo;
    memset(&ida->undo,0,sizeof(ida->undo));

    if (resize)
      viewer_autozoom(ida);
    else
      viewer_new_view(ida);
    return 0;
}

int
viewer_start_preview(struct ida_viewer *ida, struct ida_op *op, void *parm)
{
    struct ida_image dst;

    viewer_workfinish(ida);

    /* try init */
    viewer_op_rect(ida);
    ida->op_data = op->init(&ida->img,&ida->op_rect,&dst.i,parm);
    if (NULL == ida->op_data)
      return -1;

    /* prepare background preview */
    ida->op_line = 0;
    ida->op_work = op->work;
    ida->op_done = op->done;
    ida->op_preview = 1;

    viewer_workstart(ida);
    return 0;
}

int
viewer_cancel_preview(struct ida_viewer *ida)
{
    viewer_workstop(ida);
    viewer_workstart(ida);
    return 0;
}

int
viewer_loader_start(struct ida_viewer *ida, struct ida_loader *loader,
                FILE *fp, char *filename, unsigned int page)
{
    struct ida_image_info info;
    void *data;

    /* init loader */
    ptr_busy();
    memset(&info,0,sizeof(info));
    data = loader->init(fp,filename,page,&info,0);
    ptr_idle();
    if (NULL == data) {
      fprintf(stderr,"loading %s [%s] FAILED\n",filename,loader->name);
      if (fp)
          hex_display(filename);
      return -1;
    }

    /* ok, going to load new image */
    viewer_workstop(ida);
    viewer_rubber_off(ida);
    memset(&ida->current,0,sizeof(ida->current));
    if (ida->undo.data) {
      free(ida->undo.data);
      memset(&ida->undo,0,sizeof(ida->undo));
    }
    if (NULL != ida->img.data)
      free(ida->img.data);
    ida->file       = filename;
    ida->img.i      = info;
    ida->img.data   = malloc(ida->img.i.width * ida->img.i.height * 3);
    
    /* prepare background loading */
    ida->load_line = 0;
    ida->load_read = loader->read;
    ida->load_done = loader->done;
    ida->load_data = data;
    
    viewer_autozoom(ida);
    return info.npages;
}

int
viewer_loadimage(struct ida_viewer *ida, char *filename, unsigned int page)
{
    struct list_head  *item;
    struct ida_loader *loader;
    char blk[512];
    FILE *fp;

    if (NULL == (fp = fopen(filename, "r"))) {
      fprintf(stderr,"fopen %s: %s\n",filename,strerror(errno));
        return -1;
    }
    if (debug)
      fprintf(stderr,"load: %s\n",filename);
    memset(blk,0,sizeof(blk));
    fread(blk,1,sizeof(blk),fp);
    rewind(fp);

    /* pick loader */
    list_for_each(item,&loaders) {
        loader = list_entry(item, struct ida_loader, list);
#if 0
      if (NULL == loader->magic)
          break;
#else
      if (NULL == loader->magic)
          continue;
#endif
      if (0 == memcmp(blk+loader->moff,loader->magic,loader->mlen))
          return viewer_loader_start(ida,loader,fp,filename,page);
    }
    fprintf(stderr,"%s: unknown format\n",filename);
    hex_display(filename);
    fclose(fp);
    return -1;
}

int
viewer_setimage(struct ida_viewer *ida, struct ida_image *img, char *name)
{
    /* ok, going to load new image */
    viewer_workstop(ida);
    viewer_rubber_off(ida);
    memset(&ida->current,0,sizeof(ida->current));
    if (ida->undo.data) {
      free(ida->undo.data);
      memset(&ida->undo,0,sizeof(ida->undo));
    }

    if (NULL != ida->img.data)
      free(ida->img.data);
    ida->file       = name;
    ida->img        = *img;

    viewer_autozoom(ida);
    return 0;
}

struct ida_viewer*
viewer_init(Widget widget)
{
    Colormap cmap = DefaultColormapOfScreen(XtScreen(widget));
    struct ida_viewer *ida;
    XColor white,red,dummy;
    unsigned int i;

    ida = malloc(sizeof(*ida));
    memset(ida,0,sizeof(*ida));
    ida->widget = widget;
    XtAddEventHandler(widget,ExposureMask,False,viewer_redraw,ida);
    XtAddEventHandler(widget,
                  ButtonPressMask   |
                  ButtonReleaseMask |
                  PointerMotionMask,
                  False,viewer_mouse,ida);

    ptrs[POINTER_NORMAL] = XCreateFontCursor(dpy,XC_left_ptr);
    ptrs[POINTER_BUSY]   = XCreateFontCursor(dpy,XC_watch);
    ptrs[POINTER_PICK]   = XCreateFontCursor(dpy,XC_tcross);
    ptrs[RUBBER_NEW]     = XCreateFontCursor(dpy,XC_left_ptr);
    ptrs[RUBBER_MOVE]    = XCreateFontCursor(dpy,XC_fleur);
    ptrs[RUBBER_X1]      = XCreateFontCursor(dpy,XC_sb_h_double_arrow);
    ptrs[RUBBER_X2]      = XCreateFontCursor(dpy,XC_sb_h_double_arrow);
    ptrs[RUBBER_Y1]      = XCreateFontCursor(dpy,XC_sb_v_double_arrow);
    ptrs[RUBBER_Y2]      = XCreateFontCursor(dpy,XC_sb_v_double_arrow);
    if (XAllocNamedColor(dpy,cmap,"white",&white,&dummy) &&
      XAllocNamedColor(dpy,cmap,"red",&red,&dummy))
      for (i = 0; i < sizeof(ptrs)/sizeof(Cursor); i++)
          XRecolorCursor(dpy,ptrs[i],&red,&white);

    return ida;
}

Generated by  Doxygen 1.6.0   Back to index