@@ 30,9 30,21 @@ Menu menu = {
.item = menuitems
};
+char *mimetab[] = {
+ "image/png", "png",
+ "image/jpeg", "jpg",
+ "image/ppm", "ppm",
+ "image/tiff", "tif",
+ "image/bmp", "bmp",
+
+ "audio/mpeg", "", /* bug in file(1) */
+ "image/p9bit", "",
+ nil
+};
+
int checkonly, lightmode, nslides, cslide, xm, ym;
char *file, *contents, *offset, *tfname, *hfname;
-Image *bg,*fg,*tmp;
+Image *bg,*fg,*tmp, **images;
Font *tfont, *hfont;
Slide **slides;
@@ 168,7 180,7 @@ checkerr(Slide *s, char *msg, ...)
va_start(args, msg);
- fprint(2,"%s:%d: %s: ", file, s->linum, s->cmd);
+ fprint(2,"%s:%d: %%%s: ", file, s->linum, s->cmd);
vfprint(2,msg, args);
fprint(2,"\n");
}
@@ 196,6 208,8 @@ checkfile(void)
continue;
else if(strcmp(s->cmd, "text") == 0)
continue;
+ else if(strcmp(s->cmd, "gallery") == 0)
+ continue;
else if(strcmp(s->cmd, "title") == 0){
if(s->arg == nil){
waserr = 1;
@@ 211,6 225,154 @@ checkfile(void)
exits("checkfile");
}
+// FIXME: some of this could be done in-process but i am lazy
+// TODO: should check image formats in checkimage() instead
+void
+loadimages(void){
+ const Slide *s;
+ Image **nextimg, *cimg;
+ Waitmsg *wm;
+ Point idims, sdims;
+ int i, j, n, cols, rows, p[2], fd;
+ char buf[64], buf2[64], *conv;
+
+ if(images != nil)
+ return;
+
+ s = slides[cslide];
+
+ images = calloc(s->nlines, sizeof(Image*));
+ nextimg = images;
+
+ pipe(p);
+
+ cols = 0;
+ i = 0;
+ while(i < s->nlines && *(s->lines[i]) == '\0') i++;
+ for(; i < s->nlines; i++){
+ cols++;
+ while(i < s->nlines && *(s->lines[i]) != '\0') i++;
+ while(i < s->nlines && *(s->lines[i]) == '\0') i++;
+ }
+
+ rows = 0;
+
+ for(i = 0; i < s->nlines; i++){
+ if(*(s->lines[i]) == '\0'){
+ rows = 0;
+ continue;
+ }
+ if(rows == 0){
+ j = i;
+ while(j < s->nlines && *(s->lines[j++]) != '\0')
+ rows++;
+ }
+
+ sdims = subpt(screen->r.max, screen->r.min);
+ sdims.x /= cols;
+ sdims.y /= rows;
+
+ if(fork() == 0){
+ close(1);
+ dup(p[0], 1);
+ execl("/bin/file", "file", "-m", s->lines[i], nil);
+ }
+ wm = wait();
+ if(wm->msg != nil && *wm->msg != '\0')
+ sysfatal("%s", wm->msg);
+ free(wm);
+
+ n = read(p[1], buf, sizeof(buf));
+ buf[n - 1] = '\0'; /* replace the newline */
+
+ conv = nil;
+ for(j = 0; mimetab[j] != nil; j+=2){
+ if(strcmp(buf, mimetab[j]) == 0){
+ conv = mimetab[j+1];
+ break;
+ }
+ }
+ if(conv == nil)
+ sysfatal("unknown image format '%s'", buf);
+
+ if(fork() == 0){
+ close(1);
+ dup(p[0], 1);
+ if(*conv == '\0')
+ execl("/bin/cat", "cat", s->lines[i], nil);
+ else{
+ sprint(buf, "/bin/%s", conv);
+ execl(buf, conv, "-c", s->lines[i], nil);
+ }
+ }
+ cimg = readimage(display, p[1], 0);
+ if(cimg == nil)
+ sysfatal("couldn't convert '%s': %r", s->lines[i]);
+ waitpid();
+
+ idims = subpt(cimg->r.max, cimg->r.min);
+
+ sprint(buf, "/tmp/%s.%d.img", argv0, getpid());
+ fd = create(buf, OWRITE, 0600);
+ if(fd < 0)
+ sysfatal("couldn't open tmp file: %r");
+ writeimage(fd, cimg, 0);
+ close(fd);
+
+ if(fork() == 0){
+ close(1);
+ dup(p[0], 1);
+
+ if(idims.x < idims.y || (idims.x == idims.y && sdims.x > sdims.y)){
+ sprint(buf2, "%d", sdims.x);
+ execl("/bin/resize", "resize", "-x", buf2, buf, nil);
+ }else{
+ sprint(buf2, "%d", sdims.y);
+ execl("/bin/resize", "resize", "-y", buf2, buf, nil);
+ }
+ }
+ *nextimg = readimage(display, p[1], 0);
+ if(*nextimg == nil)
+ sysfatal("couldn't scale '%s': %r", s->lines[i]);
+
+ nextimg++;
+ }
+
+ close(p[0]);
+ close(p[1]);
+}
+void
+freeimages(void){
+ const Slide *s;
+ Image **p;
+ int i;
+
+ if(images == nil)
+ return;
+
+ s = slides[cslide];
+ p = images;
+
+ for(i = 0; i < s->nlines; i++){
+ if(*(s->lines[i]) == '\0')
+ continue;
+
+ freeimage(*p);
+ p++;
+ }
+
+ free(images);
+ images = nil;
+}
+void
+rmtmp(void)
+{
+ char buf[64];
+
+ sprint(buf, "/tmp/%s.%d.img", argv0, getpid());
+ remove(buf);
+}
+
void
render(void)
{
@@ 263,7 425,11 @@ render(void)
string(screen, Pt(center.x - (width / 2), voff), fg, Pt(0,0), tfont, s->lines[i]);
voff += tfont->height;
}
-
+
+ }else if(strcmp(s->cmd, "gallery") == 0){
+ loadimages();
+ p = divpt(subpt(subpt(screen->r.max, screen->r.min), subpt(images[0]->r.max, images[0]->r.min)), -2);
+ draw(screen, screen->r, images[0], nil, p);
}
}
@@ 272,6 438,7 @@ eresized(int new)
{
if(new && getwindow(display, Refnone) < 0)
fprint(2,"can't reattach to window\n");
+ freeimages();
render();
}
@@ 348,6 515,8 @@ main(int argc, char *argv[])
if(checkonly)
exits(nil);
+ atexit(rmtmp);
+
slides = malloc(nslides*sizeof(Slide*));
for(i = 0; i < nslides; i++){
slides[i] = nextslide(&offset, &linum);
@@ 394,10 563,14 @@ main(int argc, char *argv[])
if(etype == Emouse){
m = e.mouse;
- if(m.buttons & 1 && !(lastm.buttons & 1))
+ if(m.buttons & 1 && !(lastm.buttons & 1)){
+ freeimages();
cslide--;
- if(m.buttons & 4 && !(lastm.buttons & 4))
+ }
+ if(m.buttons & 4 && !(lastm.buttons & 4)){
+ freeimages();
cslide++;
+ }
menu.lasthit = -1;
if(m.buttons & 2)
@@ 405,9 578,11 @@ main(int argc, char *argv[])
switch(menu.lasthit){
case MenuNext:
+ freeimages();
cslide++;
break;
case MenuPrev:
+ freeimages();
cslide--;
break;
case MenuExit: