home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1993 Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "vg.h"
- #include "image.h"
- #include "video/video.h"
-
- #ifndef STATIC
- #define STATIC static
- #endif
-
- /*
- * Photo CD file definitions
- */
- #define MAX_WIDTH 768
- #define MAX_HEIGHT 512
-
- /*
- * Photo CD image orientations
- */
-
- #define ROTATE_0 0
- #define ROTATE_90 1
- #define ROTATE_180 2
- #define ROTATE_270 3
-
-
- STATIC image_t *PCDImage;
-
- STATIC int pcdLoadImage(FILE *fp, int x, int y, int w, int h, int rotate);
-
- char *
- pcdInfo(
- FILE *fp
- )
- {
- static char info[80];
- unsigned char buf[4096];
-
- if (fread(buf, 4096, 1, fp) != 1)
- return NULL;
-
- if (strcmp(buf+ 0x800, "PCD_IPI") == 0)
- return "Kodak Photo CD image";
-
- if (strcmp(buf, "PCD_OPA") == 0)
- {
- int n;
-
- n = (buf[10] << 8) | buf[11];
- sprintf(info, "Kodak Photo CD overview of %d images", n);
- return info;
- }
-
- return NULL;
- }
-
- int
- pcdRead(
- char *name,
- FILE *fp
- )
- {
- unsigned char buf[4096];
-
- if (fread(buf, 4096, 1, fp) != 1)
- return imageError("can't read PCD image header");
-
- if (strcmp(buf+ 0x800, "PCD_IPI") == 0)
- return pcdShowImage(name, fp, buf[0xe02] & 0x03);
-
- if (strcmp(buf, "PCD_OPA") == 0)
- {
- int n;
-
- n = (buf[10] << 8) | buf[11];
- return pcdShowOverview(name, fp, n);
- }
-
- return imageError("not a PCD image file");
- }
-
- int
- pcdShowImage(
- char *name,
- FILE *fp,
- int rotate
- )
- {
- int r;
- int w, h;
-
- switch (rotate)
- {
- case 0: /* no rotation */
- case 2: /* rotate 180 degrees */
- w = 768;
- h = 512;
- break;
-
- case 1: /* rotate 90 degrees left */
- case 3: /* rotate 90 degrees right */
- w = 512;
- h = 768;
- break;
- }
-
- if ((PCDImage = imageStart(name, w, h, 24, 0)) == NULL)
- return imageError("can't allocate %dx%d 24 bit Photo-CD image", w, h);
-
- imageShowInfo(1);
-
- /*
- * seek to start of image
- */
- fseek(fp, 96 * 2048L, 0);
- pcdLoadImage(fp, 0, 0, 768, 512, rotate);
-
- return imageEnd();
- }
-
- int
- pcdShowOverview(
- char *name,
- FILE *fp,
- int n
- )
- {
- int i;
- int r;
- int rows, cols, page, pages;
- int h_border, v_border;
- int images_per_page;
- int width, height;
- char buf[80];
- char sbuf[2048];
- vmode_t *m;
-
- rewind(fp);
- if (fread(sbuf, 2048, 1, fp) != 1)
- return imageError("can't read PCD image header");
-
- /*
- * calculate overview image layout
- */
- /*
- * calculate rows and columns needed to display
- * overview images in a 4 x 3 format
- */
- rows =
- cols = (n + 11) / 12;
- rows *= 3;
- cols *= 4;
-
- /*
- * find the best mode for displaying that number of 192x192 images
- */
- i = bestDisplayMode(V_GRAPHICS_MODE, cols * 192, rows * 192, 24);
- m = vidModeInfo(i);
- width = m->width;
- height = m->height;
-
- /*
- * given the actual display mode available calculate how many rows and
- * colums will fit on one screen and how many screens we will need
- */
- rows = height / 192;
- cols = width / 192;
- images_per_page = rows * cols;
- pages = (n + images_per_page - 1) / images_per_page;
-
- /*
- * calculate the horizontal and vertical border width between images
- */
- h_border = (width - (cols * 192)) / cols;
- v_border = (height - (rows * 192)) / rows;
-
- page = 0;
-
- for (;;)
- {
- int first_image;
- int last_image;
- int x, y;
- int row, col;
- int rotate;
-
- first_image = page * images_per_page;
- last_image = first_image + images_per_page - 1;
- if (last_image > n)
- last_image = n;
-
- sprintf(buf, "%s images %d - %d", name, first_image+1, last_image+1);
-
- if ((PCDImage = imageStart(buf, width, height, 24, 0)) == NULL)
- return imageError("can't allocate %dx%d 24 bit image",
- width, height);
-
- imageShowInfo(1);
-
- /*
- * load the images here ....
- */
- i = first_image;
- y = v_border / 2;
-
- for (row = 0; row < rows && i <= last_image; row++)
- {
- x = h_border / 2;
- for (col = 0; col < cols && i <= last_image; col++)
- {
- fseek(fp, (5 + 18 * i) * 2048L, 0);
- rotate = sbuf[12 + i] & 0x03;
- if (rotate & 0x01)
- pcdLoadImage(fp, x+32, y, 192, 128, rotate);
- else
- pcdLoadImage(fp, x, y+32, 192, 128, rotate);
-
- x += 192 + h_border;
- i++;
- }
- y += 192 + v_border;
-
- }
-
- r = imageEnd();
-
- switch (r)
- {
- case F_NEXT:
- if (++page >= pages)
- return F_NEXT;
- break;
-
- case F_PREV:
- if (--page < 0)
- return F_PREV;
- break;
-
- case F_REDRAW:
- break;
-
- case F_ESC:
- default:
- return r;
- }
- }
- /*NOTREACHED*/
- }
-
- STATIC int
- pcdLoadImage(
- FILE *fp,
- int x,
- int y,
- int width,
- int height,
- int rotate
- )
- {
- int dx;
- int dy;
- int i;
- int r;
- unsigned char buf[MAX_WIDTH*3];
- unsigned char Cb[MAX_WIDTH];
- unsigned char Cr[MAX_WIDTH];
- unsigned char *Y, *Y0, *Y1, *Cb0, *Cr0;
-
- memset(Cb, 0x80, MAX_WIDTH);
- memset(Cr, 0x80, MAX_WIDTH);
- /*
- * deal with the image orientation
- */
- switch (rotate)
- {
- default: /* "can't happen" */
- return -1;
-
- case ROTATE_0:
- dx = 0;
- dy = 1;
- break;
-
- case ROTATE_90:
- y += width - 1;
- dx = 1;
- dy = 0;
- break;
-
- case ROTATE_180:
- x += width - 1;
- y += height - 1;
- dx = 0;
- dy = -1;
- break;
-
- case ROTATE_270:
- x += height - 1;
- dx = -1;
- dy = 0;
- break;
- }
-
- Y0 = buf;
- Y1 = buf + width;
- Cb0 = Y1 + width;
- Cr0 = Cb0 + width / 2;
-
- for (i = 0; i < height; i++)
- {
- if ((i & 1) == 0)
- {
- if (fread(buf, width, 3, fp) != 3)
- return -1;
- Y = Y0;
-
- expand(Cb0, Cb, width/2);
- expand(Cr0, Cr, width/2);
-
- }
- else
- {
- Y = Y1;
- }
- if ((r = pcdPutPixels(x, y, Y, Cb, Cr, width, rotate)) != 0)
- return r;
-
- x += dx;
- y += dy;
- }
-
- return 0;
- }
-
- int
- pcdPutPixels(
- int x,
- int y,
- void *Y,
- void *Cb,
- void *Cr,
- int n,
- int rotate
- )
- {
- unsigned char **pp;
- unsigned char *p;
- unsigned char *rgb;
- int i;
- int r = 0;
-
- switch (rotate)
- {
- default:
- r = -1;
- break;
-
- case ROTATE_0:
- pcd_to_rgb(Y, Cb, Cr, PCDImage->pixels[y] + x * 3, n);
- r = imageRefresh(x, y, n, 1);
- break;
-
- case ROTATE_90:
- rgb = alloca(n * 3);
- pcd_to_rgb(Y, Cb, Cr, rgb, n);
- pp = PCDImage->pixels;
- for (i = 0; i < n; i++)
- {
- p = &pp[y--][3*x];
- *p++ = *rgb++;
- *p++ = *rgb++;
- *p++ = *rgb++;
- }
- if ((x & 7) == 7)
- r = imageRefresh(x & ~7, y+1, 8, n);
- break;
-
- case ROTATE_180:
- rgb = alloca(n * 3);
- pcd_to_rgb(Y, Cb, Cr, rgb, n);
- pp = PCDImage->pixels;
- for (i = 0; i < n; i++)
- {
- p = &pp[y][3*x--];
- *p++ = *rgb++;
- *p++ = *rgb++;
- *p++ = *rgb++;
- }
- r = imageRefresh(x+1, y, n, 1);
- break;
-
- case ROTATE_270:
- rgb = alloca(n * 3);
- pcd_to_rgb(Y, Cb, Cr, rgb, n);
- pp = PCDImage->pixels;
- for (i = 0; i < n; i++)
- {
- p = &pp[i][3*x];
- *p++ = *rgb++;
- *p++ = *rgb++;
- *p++ = *rgb++;
- }
- if ((x & 7) == 7)
- r = imageRefresh(x & ~7, y, 8, n);
- break;
-
- }
-
- return r;
- }
-
- expand(
- unsigned char *src,
- unsigned char *dst,
- int count
- )
- {
- while (--count >= 0)
- {
- unsigned char c;
-
- c = *src++;
- *dst++ = c;
- *dst++ = c;
- }
- }
-