/* Built with libmng-1.0.9 * Compiled on linux with gcc-3.3.4 * james@blastwave.org suggested the single step mode and wrote: * "xmngview works on Solaris both Sparc and Intel and compiles with Sun's cc" * * * This program my be redistributed under the terms of the * GNU General Public Licence, version 2, or at your preference, * any later version. * * For more information about libmng please visit: * * The official libmng web-site: * http://www.libmng.com * * Libmng on SourceForge: * http://libmng.sourceforge.net * * The official MNG homepage: * http://www.libpng.org/pub/mng * * The official PNG homepage: * http://www.libpng.org/pub/png */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xmng.h" #define DEFAULT_BACKGROUND "grey77" static char version[]={"0.6"}; static void run_viewer(FILE *reader, char *read_idf); static mng_handle user_handle; static ImageInfo img; static struct timeval start_tv, now_tv; static XtIntervalId timeout_ID; static char *prg_idf; static XtAppContext app_context; static Widget toplevel, main_form, canvas, file_label; static XmFontList file_font; static Dimension start_width; #define SLASH '/' /* * Cnf: XQueryColor(3X11) */ static char *parse_rgb_color(char *val) { char *s, *d; int ch; char status, rgb_type; char r[6], g[6], b[6], rgb[24]; rgb_type = 0; status = 1; s = val; memset(r, 0, 6); memset(g, 0, 6); memset(b, 0, 6); if(strncasecmp(s, "rgb:", 4) == 0) { rgb_type = 1; s += 4; if((d = strchr(s, SLASH))) { *d = 0; if(d - s > 4) s[4] = 0; strcpy(r, s); s = ++d; if((d = strchr(s, SLASH))) { *d = 0; if(d - s > 4) s[4] = 0; strcpy(g, s); s = d + 1; while((ch = *++d) && isxdigit(ch)); *d = 0; if(d - s > 4) s[4] = 0; strcpy(b, s); } if(*r == 0 || *g == 0 || *b == 0) return NULL; s = r - 1; while((ch = *++s)) { if(isxdigit(ch)) continue; status = rgb_type = 0; break; } s = g - 1; while((ch = *++s)) { if(isxdigit(ch)) continue; status = rgb_type = 0; break; } s = b - 1; while((ch = *++s)) { if(isxdigit(ch)) continue; status = rgb_type = 0; break; } if(status) { strcpy(rgb, "rgb:"); d = rgb + 4; s = r; while(*s) *d++ = *s++; *d++ = SLASH; s = g; while(*s) *d++ = *s++; *d++ = SLASH; s = b; while(*s) *d++ = *s++; *d = 0; return strdup(rgb); } } /* if((slash = strchr(s, SLASH))) */ return NULL; } s = val; if(*s == '#' || isdigit(*s)) { if(*s != '#') --s; while((ch = *++s)) { if(isxdigit(ch)) continue; status = 0; break; } if(status) { d = rgb; s = val; if(*s == '#') ++s; /* * #RGB (4 bits each) * #RRGGBB (8 bits each) * #RRRGGGBBB (12 bits each) * #RRRRGGGGBBBB (16 bits each) */ if(strlen(s) > 12) s[12] = 0; *d++ = '#'; strcpy(d, s); return strdup(rgb); } return NULL; } /* * 'white', 'LavenderBlush', 'dark slate gray', 'grey12' */ s = val - 1; while((ch = *++s)) { if(isalnum(ch) || isspace(ch)) continue; status = 0; break; } if(!status) return NULL; return strdup(val); }/* parse_rgb_color() */ static void set_bg_pixel(ImageInfo *img) { XColor xcolor; Widget w; char *s, *d; int found; w = img->canvas; if(!img->has_bg_pixel) { if(img->has_bg_color) { s = strdup(img->bg_color); d = parse_rgb_color(s); free(s); if(d) { strcpy(img->bg_color, d); free(d); } else img->has_bg_color = 0; } if(!img->has_bg_color) { strcpy(img->bg_color, DEFAULT_BACKGROUND); img->has_bg_color = 1; } found = XParseColor(img->dpy, DefaultColormap(img->dpy, DefaultScreen(img->dpy)), img->bg_color, &xcolor); if(!found) { strcpy(img->bg_color, DEFAULT_BACKGROUND); found = XParseColor(img->dpy, DefaultColormap(img->dpy, DefaultScreen(img->dpy)), img->bg_color, &xcolor); } xcolor.flags = DoRed | DoGreen | DoBlue; XAllocColor(img->dpy, DefaultColormap(img->dpy, DefaultScreen(img->dpy)), &xcolor); } else { xcolor.pixel = img->bg_pixel; xcolor.flags = DoRed|DoGreen|DoBlue; found = XQueryColor(img->dpy, DefaultColormap(img->dpy, DefaultScreen(img->dpy)), &xcolor); } img->bg_pixel = xcolor.pixel; img->xbg_red = xcolor.red; img->xbg_green = xcolor.green; img->xbg_blue = xcolor.blue; img->bg_red = (unsigned char)xcolor.red&0xff; img->bg_green = (unsigned char)xcolor.green&0xff; img->bg_blue = (unsigned char)xcolor.blue&0xff; img->has_bg_pixel = 1; }/* set_bg_pixel() */ static void fsb_cancel_cb(Widget w, XtPointer client, XtPointer call) { XtUnmanageChild(w); } void create_file_dialog(Widget w, char *button_text, char *title_text, void(*fsb_select_cb)(Widget,XtPointer,XtPointer)) { Arg args[4]; int cnt; Widget dialog; XmString button_str, title_str, filter; Widget child; cnt = 0; dialog = XmCreateFileSelectionDialog(w, "Files", args, cnt); XtUnmanageChild(XmFileSelectionBoxGetChild(dialog,XmDIALOG_HELP_BUTTON)); XtAddCallback(dialog, XmNcancelCallback, fsb_cancel_cb, NULL); XtAddCallback(dialog, XmNokCallback, fsb_select_cb, NULL); button_str = XmStringCreateLocalized(button_text); title_str = XmStringCreateLocalized(title_text); filter = XmStringCreateLocalized("*.[jmp]ng"); XtVaSetValues(dialog, XmNokLabelString, button_str, XmNdialogTitle, title_str, XmNpattern, filter, XmNfileFilterStyle, XmFILTER_NONE, NULL); XmStringFree(button_str); XmStringFree(title_str); XmStringFree(filter); child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_FILTER_TEXT); XtVaSetValues(child, XmNfontList, file_font, NULL); child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST); XtVaSetValues(child, XmNfontList, file_font, NULL); child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST); XtVaSetValues(child, XmNfontList, file_font, NULL); child = XmFileSelectionBoxGetChild(dialog, XmDIALOG_TEXT); XtVaSetValues(child, XmNfontList, file_font, NULL); XtManageChild(dialog); XMapRaised(XtDisplay (dialog), XtWindow (XtParent (dialog))); } void run_mng_file_cb(Widget w, XtPointer client, XtPointer call) { XmFileSelectionBoxCallbackStruct *fsb; char *read_idf; FILE *reader; XtUnmanageChild(w); fsb = (XmFileSelectionBoxCallbackStruct *)call; XmStringGetLtoR(fsb->value, XmSTRING_DEFAULT_CHARSET, &read_idf); if(read_idf == NULL || *read_idf == 0) return; reader = fopen(read_idf, "r"); if(reader == NULL) { perror(read_idf); fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf); return; } run_viewer(reader, read_idf); free(read_idf); } static void user_reset_data(void) { if(timeout_ID) XtRemoveTimeOut(timeout_ID); timeout_ID = 0; mng_cleanup(&img.user_handle); img.read_pos = 0; free(img.read_buf); img.read_buf = NULL; img.read_len = 0; img.img_width = 0; img.img_height = 0; img.mng_bytes_per_line = 0; img.read_idf = NULL; img.frozen = 0; img.restarted = 0; img.single_step_wanted = 0; img.single_step_served = 0; XClearWindow(img.dpy, img.win); } void browse_file_cb(Widget w, XtPointer client, XtPointer call) { if(img.user_handle) user_reset_data(); img.stopped = 0; img.frozen = 0; img.restarted = 0; create_file_dialog(w, "Select", "Select MNG file", run_mng_file_cb); } void Viewer_postlude(void) { if(timeout_ID) XtRemoveTimeOut(timeout_ID); mng_cleanup(&img.user_handle); if(img.reader) fclose(img.reader); if(img.ximage) XDestroyImage(img.ximage); if(img.read_buf) free(img.read_buf); if(img.mng_buf) free(img.mng_buf); if(img.dither_line) free(img.dither_line); if(!img.external_win && img.dpy) XtCloseDisplay(img.dpy); fputc('\n', stderr); } static void user_init_data(ImageInfo *img) { unsigned int depth; int screen; Display *dpy; dpy = img->dpy; screen = DefaultScreen(dpy); depth = DefaultDepth(dpy, screen); img->depth = depth; if(!img->visual) { img->visual = DefaultVisual(dpy, screen); img->gc = DefaultGC(dpy, DefaultScreen(dpy)); } else { if(img->mng_buf) free(img->mng_buf); if(img->dither_line) free(img->dither_line); x11_destroy_ximage(img); } set_bg_pixel(img); mng_set_bgcolor(img->user_handle, img->xbg_red, img->xbg_green, img->xbg_blue); img->mng_bytes_per_line = img->img_width * img->mng_rgb_size; img->mng_buf = (unsigned char*) calloc(1, img->mng_bytes_per_line * img->img_height); img->dither_line = (unsigned char*) calloc(1, img->mng_bytes_per_line); if(!img->x11_init) { x11_init_color(img); img->x11_init = 1; } img->ximage = x11_create_ximage(img); if(img->ximage == NULL) { Viewer_postlude(); exit(0); } } static void player_exit_cb(Widget w, XtPointer client, XtPointer call) { Viewer_postlude(); exit(0); } static void player_stop_cb(Widget w, XtPointer client, XtPointer call) { if(img.type != MNG_TYPE) return; if(!img.user_handle) return; if(img.stopped) return; user_reset_data(); img.stopped = 1; } static void player_single_step_cb(Widget w, XtPointer client, XtPointer call) { if(img.type != MNG_TYPE) return; if(!img.user_handle) return; if(img.stopped) return; if(img.single_step_served) { img.single_step_served = 0; img.frozen = 0; img.single_step_wanted = 1; return; } if(timeout_ID) XtRemoveTimeOut(timeout_ID); timeout_ID = 0; img.single_step_wanted = 1; mng_display_resume(img.user_handle); } static void player_pause_cb(Widget w, XtPointer client, XtPointer call) { if(img.type != MNG_TYPE) return; if(!img.user_handle) return; if(img.stopped) return; if(img.frozen) return; if(timeout_ID) XtRemoveTimeOut(timeout_ID); timeout_ID = 0; img.frozen = 1; img.single_step_served = 0; img.single_step_wanted = 0; } static void player_resume_cb(Widget w, XtPointer client, XtPointer call) { if(img.type != MNG_TYPE) return; if(!img.user_handle) return; if(img.stopped) return; if(!img.frozen && !img.single_step_served) return; img.frozen = 0; if(img.single_step_served || img.single_step_wanted) { img.single_step_served = 0; img.single_step_wanted = 0; if(timeout_ID) XtRemoveTimeOut(timeout_ID); timeout_ID = 0; } mng_display_resume(img.user_handle); } static void player_restart_cb(Widget w, XtPointer client, XtPointer call) { if(img.type != MNG_TYPE) return; if(!img.user_handle) return; if(img.stopped) return; img.frozen = 1; if(timeout_ID) XtRemoveTimeOut(timeout_ID); timeout_ID = 0; img.frozen = 0; img.single_step_served = 0; img.single_step_wanted = 0; img.read_pos = 0; mng_reset(img.user_handle); img.restarted = 1; gettimeofday(&start_tv, NULL); mng_read(img.user_handle); mng_display(img.user_handle); } static void release_event_cb(Widget w, XtPointer client, XEvent *event, Boolean *cont) { Viewer_postlude(); exit(0); } static void redraw(int type) { if((type == Expose || type == GraphicsExpose) && img.ximage) { XPutImage(img.dpy, img.win, img.gc, img.ximage, 0, 0, 0, 0, img.img_width, img.img_height); } } static void exposures_cb(Widget w, XtPointer client, XmDrawingAreaCallbackStruct *cbs) { redraw(cbs->event->xany.type); } static mng_ptr user_alloc(mng_size_t len) { return calloc(1, len + 2); } static void user_free(mng_ptr buf, mng_size_t len) { free(buf); } static mng_bool user_read(mng_handle user_handle, mng_ptr out_buf, mng_uint32 req_len, mng_uint32 *out_len) { mng_uint32 more; ImageInfo *img; img = (ImageInfo *)mng_get_userdata(user_handle); more = img->read_len - img->read_pos; if(more > 0 && img->read_buf != NULL) { if(req_len < more) more = req_len; memcpy(out_buf, img->read_buf + img->read_pos, more); img->read_pos += more; *out_len = more; return MNG_TRUE; } return MNG_FALSE; } static mng_bool user_open_stream(mng_handle user_handle) { return MNG_TRUE; } static mng_bool user_close_stream(mng_handle user_handle) { return MNG_TRUE; } static void create_widgets(mng_uint32 width, mng_uint32 height) { Widget but_rc, but_frame, canvas_frame; Widget but1, but2, but3, but4, but5, but6, but7; toplevel = XtAppInitialize(&app_context, "xmngview", NULL, 0, img.argc_ptr, img.argv, 0, 0, 0); main_form = XtVaCreateManagedWidget("main_form", xmFormWidgetClass, toplevel, XmNhorizontalSpacing, SPACE_X, XmNverticalSpacing, SPACE_Y, XmNresizable, True, NULL); but_frame = XtVaCreateManagedWidget("but_frame", xmFrameWidgetClass, main_form, XmNshadowType, XmSHADOW_ETCHED_OUT, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNshadowThickness, FRAME_SHADOW_WIDTH, NULL); but_rc = XtVaCreateManagedWidget("but_rc", xmRowColumnWidgetClass, but_frame, XmNentryAlignment, XmALIGNMENT_CENTER, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, XmNnumColumns, 1, XmNresizeWidth, True, XmNentryBorder, BUT_ENTRY_BORDER, NULL); but1 = XtVaCreateManagedWidget("Exit", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but1, XmNactivateCallback, player_exit_cb, (XtPointer)toplevel); but2 = XtVaCreateManagedWidget("Pause", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but2, XmNactivateCallback, player_pause_cb, (XtPointer)toplevel); but3 = XtVaCreateManagedWidget("GoOn", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but3, XmNactivateCallback, player_resume_cb, NULL); but4 = XtVaCreateManagedWidget("Restart", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but4, XmNactivateCallback, player_restart_cb, NULL); but5 = XtVaCreateManagedWidget("Step", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but5, XmNactivateCallback, player_single_step_cb, NULL); but6 = XtVaCreateManagedWidget("Finish", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but6, XmNactivateCallback, player_stop_cb, NULL); but7 = XtVaCreateManagedWidget("Browse", xmPushButtonWidgetClass, but_rc, NULL); XtAddCallback(but7, XmNactivateCallback, browse_file_cb, NULL); file_label = XtVaCreateManagedWidget("FILE: ", xmLabelWidgetClass, main_form, XmNalignment, XmALIGNMENT_BEGINNING, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, but_frame, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); canvas_frame = XtVaCreateManagedWidget("canvas_frame", xmFrameWidgetClass, main_form, XmNshadowType, XmSHADOW_ETCHED_OUT, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, file_label, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); canvas = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass, canvas_frame, XmNheight, height, XmNwidth, width, NULL); XtAddEventHandler(canvas, ButtonReleaseMask|ButtonPressMask, False, release_event_cb, (XtPointer)toplevel); XtAddCallback(canvas, XmNexposeCallback, (XtCallbackProc)exposures_cb, (XtPointer)&img); XtRealizeWidget(toplevel); if(start_width == 0) { width = height = 0; start_width = (FRAME_SHADOW_WIDTH<<1); XtVaGetValues(but1, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH; XtVaGetValues(but2, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH; XtVaGetValues(but3, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH; XtVaGetValues(but4, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH; XtVaGetValues(but5, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1) + ANY_WIDTH; XtVaGetValues(but6, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1); XtVaGetValues(but7, XmNwidth, &width, NULL); start_width += width + (BUT_ENTRY_BORDER<<1); } img.canvas = canvas; img.dpy = XtDisplay(img.canvas); img.win = XtWindow(img.canvas); file_font = XmFontListAppendEntry(NULL, XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT, XLoadQueryFont(img.dpy, "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1"))); } static mng_bool user_process_header(mng_handle user_handle, mng_uint32 width, mng_uint32 height) { ImageInfo *img; Dimension cw, ch, tw, th, dh, dw, fw, fh; XmString xmstr; char *s, buf[128]; img = (ImageInfo*)mng_get_userdata(user_handle); if(img->restarted) { img->restarted = 0; return MNG_TRUE; } img->img_width = width; img->img_height = height; if(!img->external_win) { if(!img->canvas) create_widgets(width, height); else { tw = th = fw = fh = cw = ch = 0; XtVaGetValues(toplevel, XmNwidth, &tw, XmNheight, &th, NULL); XtVaGetValues(main_form, XmNwidth, &fw, XmNheight, &fh, NULL); XtVaGetValues(img->canvas, XmNwidth, &cw, XmNheight, &ch, NULL); if(height > ch) { dh = height - ch; th += dh; fh += dh; } else if(ch > height) { dh = ch - height; th -= dh; fh -= dh; } if(width > cw) { dw = width - cw; tw += dw; fw += dw; } else if(cw > width) { if(width > start_width) dw = cw - width; else dw = cw - start_width; tw -= dw; fw -= dw; } if(fw < start_width) { tw = start_width + (SPACE_X<<1); fw = start_width; } XtVaSetValues(toplevel, XmNwidth,tw , XmNheight,th , NULL); XtVaSetValues(main_form, XmNwidth,fw , XmNheight,fh , NULL); XtVaSetValues(img->canvas, XmNwidth,width , XmNheight,height , NULL); } } else if(img->external_win) { Display *dpy; XtToolkitInitialize(); app_context = XtCreateApplicationContext(); dpy = XtOpenDisplay(app_context, NULL,NULL,"xmngview", NULL, 0, img->argc_ptr, img->argv); img->dpy = dpy; img->win = img->external_win; XSelectInput(dpy, img->win, ExposureMask); } user_init_data(img); if(img->canvas) { s = strrchr(img->read_idf, '/'); if(s == NULL) s = img->read_idf; else ++s; s = strdup(s); if(strlen(s) > 64) s[64] = 0; sprintf(buf, "%s (%d x %d)", s, img->img_width, img->img_height); xmstr = XmStringCreateLtoR((char*)buf, XmSTRING_DEFAULT_CHARSET); XtVaSetValues(file_label, XmNlabelString, xmstr, NULL); XmStringFree(xmstr); free(s); } gettimeofday(&start_tv, NULL); return MNG_TRUE; } static void wait_cb(XtPointer client, XtIntervalId * id) { timeout_ID = 0; if(img.frozen || img.single_step_served) { // gettimeofday(&start_tv, NULL); timeout_ID = XtAppAddTimeOut(app_context, img.delay, wait_cb, NULL); } else { mng_display_resume(img.user_handle); } } static mng_bool user_set_timer(mng_handle user_handle, mng_uint32 delay) { ImageInfo *img; img = (ImageInfo*)mng_get_userdata(user_handle); img->delay = delay; timeout_ID = XtAppAddTimeOut(app_context, delay, wait_cb, NULL); return MNG_TRUE; } static mng_uint32 user_get_tick_count(mng_handle user_handle) { double sec, usec; mng_uint32 ticks; gettimeofday(&now_tv, NULL); sec = (double)(now_tv.tv_sec - start_tv.tv_sec); usec = (double)now_tv.tv_usec - (double)start_tv.tv_usec; ticks = (mng_uint32)(sec * 1000.0 + usec/1000.0); //fprintf(stderr,"TICKS %u (%f:%f)\n", ticks, sec, usec); return ticks; } static mng_ptr user_get_canvas_line(mng_handle user_handle, mng_uint32 line) { ImageInfo *img; img = (ImageInfo*)mng_get_userdata(user_handle); return img->mng_buf + img->mng_bytes_per_line * line; } static mng_bool user_refresh(mng_handle user_handle, mng_uint32 x, mng_uint32 y, mng_uint32 width, mng_uint32 height) { ImageInfo *img; mng_uint32 src_len; unsigned char *src_start, *src_buf; int row, max_row; Display *dpy; GC gc; Window win; XImage *ximage; Visual *visual; int have_shmem; img = (ImageInfo*)mng_get_userdata(user_handle); if(img->single_step_wanted) img->single_step_served = 1; win = img->win; gc = img->gc; dpy = img->dpy; ximage = img->ximage; visual = img->visual; have_shmem = img->have_shmem; max_row = y + height; row = y; src_len = img->mng_bytes_per_line; src_buf = src_start = img->mng_buf + img->mng_rgb_size * x + y * src_len; while(row < max_row) { viewer_renderline(img, src_start, row, x, width); ++row; src_start += src_len; } XPUTIMAGE(dpy, win, gc, ximage, x, y, x, y, width, height); XSync(dpy, False); return MNG_TRUE; } static mng_bool user_error(mng_handle user_handle, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text) { ImageInfo *img; unsigned char chunk[5]; img = (ImageInfo*)mng_get_userdata(user_handle); chunk[0] = (char)((chunktype >> 24) & 0xFF); chunk[1] = (char)((chunktype >> 16) & 0xFF); chunk[2] = (char)((chunktype >> 8) & 0xFF); chunk[3] = (char)((chunktype ) & 0xFF); chunk[4] = '\0'; fprintf(stderr, "\n\n%s: error playing(%s) chunk[%d]'%s':\n", prg_idf, img->read_idf, chunkseq, chunk); fprintf(stderr, "code(%d) severity(%d) extra1(%d) extra2(%d)" "\ntext:'%s'\n\n", code, severity, extra1, extra2, text); return 0; } static mng_bool prelude(void) { #define MAXBUF 8 unsigned char buf[MAXBUF]; if(fread(buf, 1, MAXBUF, img.reader) != MAXBUF) { fprintf(stderr,"\n%s:prelude\n\tcannot read signature \n", prg_idf); return MNG_FALSE; } if(memcmp(buf, MNG_MAGIC, 8) == 0) img.type = MNG_TYPE; else if(memcmp(buf, JNG_MAGIC, 8) == 0) img.type = JNG_TYPE; else if(memcmp(buf, PNG_MAGIC, 8) == 0) img.type = PNG_TYPE; if(!img.type) { fprintf(stderr,"\n%s:'%s' is no MNG / JNG / PNG file\n", prg_idf, img.read_idf); return MNG_FALSE; } fseek(img.reader, 0, SEEK_SET); fseek(img.reader, 0, SEEK_END); img.read_len = ftell(img.reader); fseek(img.reader, 0, SEEK_SET); if(!img.user_handle) { user_handle = mng_initialize(&img, user_alloc, user_free, MNG_NULL); if(user_handle == MNG_NULL) { fprintf(stderr, "\n%s: cannot initialize libmng.\n", prg_idf); return MNG_FALSE; } img.user_handle = user_handle; mng_set_canvasstyle(user_handle, MNG_CANVAS_RGB8); img.mng_rgb_size = CANVAS_RGB8_SIZE; if(mng_setcb_openstream(user_handle, user_open_stream) != OK || mng_setcb_closestream(user_handle, user_close_stream) != OK || mng_setcb_readdata(user_handle, user_read) != OK || mng_setcb_settimer(user_handle, user_set_timer) != OK || mng_setcb_gettickcount(user_handle, user_get_tick_count) != OK || mng_setcb_processheader(user_handle, user_process_header) != OK || mng_setcb_getcanvasline(user_handle, user_get_canvas_line) != OK || mng_setcb_refresh(user_handle, user_refresh) != OK || mng_setcb_errorproc(user_handle, user_error) != OK ) { fprintf(stderr,"\n%s: cannot set callbacks for libmng.\n", prg_idf); return MNG_FALSE; } } img.read_buf = (unsigned char*)calloc(1, img.read_len + 2); fread(img.read_buf, 1, img.read_len, img.reader); fclose(img.reader); img.reader = NULL; return MNG_TRUE; } static void run_viewer(FILE *reader, char *read_idf) { XEvent event; img.read_idf = read_idf; img.reader = reader; if(read_idf != NULL) { if(prelude() == MNG_FALSE) return ; gettimeofday(&start_tv, NULL); mng_read(img.user_handle); mng_display(img.user_handle); } if(!img.external_win) { XtAppMainLoop(app_context); } else while(1) { XtAppNextEvent(app_context, &event); redraw(event.type); } } static void usage(const char *prg) { const char *bar= "\n------------------------------------------------------------------------\n"; fputs(bar, stderr); fprintf(stderr,"%s version %s\n" "USAGE: %s [--w WINDOW] [--bg BACKGROUND_COLOR] [FILE]\n", prg, version, prg); fputs("\twith BACKGROUND_COLOR = " "(\"TEXT\" | \"#RGB\" | \"rgb:R/G/B\" | \"PIXEL\")\n" "\te.g.\n\t(--bg \"red\" | --bg \"#ff0000\" " "| --bg \"rgb:ff/00/00\" | --bg \"0xf800\")\n" "\twith FILE=(idf.mng | idf.jng | idf.png)",stderr); fputs(bar, stderr); } static void shrink_name(char *buf) { char *s, *d; int ch; s = d = buf; while((ch = *s++)) { if(isspace(ch)) continue; *d++ = tolower(ch); } *d = 0; } int main(int argc, char **argv) { FILE *reader; char *read_idf, *s; char *ok; int i; unsigned char has_bg_color, has_bg_pixel; Window external_win; Pixel bg_pixel; if((prg_idf = strrchr(argv[0], '/')) == NULL) prg_idf = argv[0]; else ++prg_idf; memset(&img, 0, sizeof(ImageInfo)); external_win = 0; read_idf = NULL; reader = NULL; has_bg_color = has_bg_pixel = 0; bg_pixel = 0; i = 0; while(++i < argc) { s = argv[i]; if(strcmp(s, "--help") == 0 || strcmp(s, "-help") == 0 || *s == '?') { usage(prg_idf); return 0; } if(strcasecmp(s, "--w") == 0) { ++i; s = argv[i]; external_win = strtoul(s, &ok, 10); if(*ok) return 0; continue; } if(strcasecmp(s, "--bg") == 0) { ++i; s = argv[i]; if(*s == '#' || strncasecmp(s, "rgb:", 4) == 0 || isalpha(*s)) { strncpy(img.bg_color, s, MAX_COLORBUF); img.bg_color[MAX_COLORBUF] = 0; has_bg_color = 1; if(*s != '#') shrink_name(img.bg_color); continue; } bg_pixel = strtoul(s, &ok, 16); if(*ok == 0) has_bg_pixel = 1; continue; } if(*s != '-') { read_idf = s; continue; } } if(read_idf != NULL) { reader = fopen(read_idf, "rb"); if(reader == NULL) { perror(read_idf); fprintf(stderr, "\n\n%s: cannot open file '%s'\n\n", prg_idf, read_idf); return 0; } } img.argv = argv; img.argc_ptr = &argc; img.external_win = external_win; img.has_bg_pixel = has_bg_pixel; img.bg_pixel = bg_pixel; img.has_bg_color = has_bg_color; if(!has_bg_pixel && !has_bg_color) { strcpy(img.bg_color, DEFAULT_BACKGROUND); img.has_bg_color = 1; } if(read_idf == NULL && external_win == 0) create_widgets(5,5); run_viewer(reader, read_idf); Viewer_postlude(); return 0; }