picture_t * gli_picture_scale(picture_t *src, int newcols, int newrows) { /* pnmscale.c - read a portable anymap and scale it * * Copyright (C) 1989, 1991 by Jef Poskanzer. * * 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. */ #define SCALE 4096 #define HALFSCALE 2048 #define maxval 255 picture_t *dst; dst = gli_picture_retrieve(src->id, 1); if (dst && dst->w == newcols && dst->h == newrows) return dst; unsigned char *xelrow; unsigned char *tempxelrow; unsigned char *newxelrow; register unsigned char *xP; register unsigned char *nxP; register int row, col; int rowsread, needtoreadrow; int cols = src->w; int rows = src->h; float xscale, yscale; long sxscale, syscale; register long fracrowtofill, fracrowleft; long *rs; long *gs; long *bs; long *as; /* Allocate destination image and scratch space */ dst = malloc(sizeof(picture_t)); dst->refcount = 1; dst->w = newcols; dst->h = newrows; dst->rgba = malloc(newcols * newrows * 4); dst->id = src->id; dst->scaled = TRUE; xelrow = src->rgba; newxelrow = dst->rgba; tempxelrow = malloc(cols * 4); rs = malloc((cols + 1) * sizeof(long)); gs = malloc((cols + 1) * sizeof(long)); bs = malloc((cols + 1) * sizeof(long)); as = malloc((cols + 1) * sizeof(long)); /* Compute all sizes and scales. */ xscale = (float) newcols / (float) cols; yscale = (float) newrows / (float) rows; sxscale = xscale * SCALE; syscale = yscale * SCALE; rowsread = 1; fracrowleft = syscale; needtoreadrow = 0; for ( col = 0; col < cols; ++col ) rs[col] = gs[col] = bs[col] = as[col] = HALFSCALE; fracrowtofill = SCALE; for ( row = 0; row < newrows; ++row ) { /* First scale Y from xelrow into tempxelrow. */ { while ( fracrowleft < fracrowtofill ) { if ( needtoreadrow ) if ( rowsread < rows ) { xelrow += src->w * 4; ++rowsread; /* needtoreadrow = 0; */ } for ( col = 0, xP = xelrow; col < cols; ++col, xP += 4 ) { rs[col] += fracrowleft * xP[0] * xP[3]; gs[col] += fracrowleft * xP[1] * xP[3]; bs[col] += fracrowleft * xP[2] * xP[3]; as[col] += fracrowleft * xP[3]; } fracrowtofill -= fracrowleft; fracrowleft = syscale; needtoreadrow = 1; } /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */ if ( needtoreadrow ) if ( rowsread < rows ) { xelrow += src->w * 4; ++rowsread; needtoreadrow = 0; } for ( col = 0, xP = xelrow, nxP = tempxelrow; col < cols; ++col, xP += 4, nxP += 4) { register long r, g, b, a; r = rs[col] + fracrowtofill * xP[0] * xP[3]; g = gs[col] + fracrowtofill * xP[1] * xP[3]; b = bs[col] + fracrowtofill * xP[2] * xP[3]; a = as[col] + fracrowtofill * xP[3]; if (!a) { r = g = b = a; } else { r /= a; if ( r > maxval ) r = maxval; g /= a; if ( g > maxval ) g = maxval; b /= a; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; } nxP[0] = r; nxP[1] = g; nxP[2] = b; nxP[3] = a; rs[col] = gs[col] = bs[col] = as[col] = HALFSCALE; } fracrowleft -= fracrowtofill; if ( fracrowleft == 0 ) { fracrowleft = syscale; needtoreadrow = 1; } fracrowtofill = SCALE; } /* Now scale X from tempxelrow into newxelrow and write it out. */ { register long r, g, b, a; register long fraccoltofill, fraccolleft; register int needcol; nxP = newxelrow; fraccoltofill = SCALE; r = g = b = a = HALFSCALE; needcol = 0; for ( col = 0, xP = tempxelrow; col < cols; ++col, xP += 4 ) { fraccolleft = sxscale; while ( fraccolleft >= fraccoltofill ) { if ( needcol ) { nxP += 4; r = g = b = a = HALFSCALE; } r += fraccoltofill * xP[0] * xP[3]; g += fraccoltofill * xP[1] * xP[3]; b += fraccoltofill * xP[2] * xP[3]; a += fraccoltofill * xP[3]; if (!a) { r = g = b = a; } else { r /= a; if ( r > maxval ) r = maxval; g /= a; if ( g > maxval ) g = maxval; b /= a; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; } nxP[0] = r; nxP[1] = g; nxP[2] = b; nxP[3] = a; fraccolleft -= fraccoltofill; fraccoltofill = SCALE; needcol = 1; } if ( fraccolleft > 0 ) { if ( needcol ) { nxP += 4; r = g = b = a = HALFSCALE; needcol = 0; } r += fraccolleft * xP[0] * xP[3]; g += fraccolleft * xP[1] * xP[3]; b += fraccolleft * xP[2] * xP[3]; a += fraccolleft * xP[3]; fraccoltofill -= fraccolleft; } } if ( fraccoltofill > 0 ) { xP -= 4; r += fraccoltofill * xP[0] * xP[3]; g += fraccoltofill * xP[1] * xP[3]; b += fraccoltofill * xP[2] * xP[3]; a += fraccoltofill * xP[3]; } if ( ! needcol ) { if (!a) { r = g = b = a; } else { r /= a; if ( r > maxval ) r = maxval; g /= a; if ( g > maxval ) g = maxval; b /= a; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; } nxP[0] = r; nxP[1] = g; nxP[2] = b; nxP[3] = a; } newxelrow += dst->w * 4; } } free(as); free(bs); free(gs); free(rs); free(tempxelrow); gli_picture_store(dst); return dst; }
picture_t *gli_picture_load(unsigned long id) { picture_t *pic; FILE *fl; int closeafter; glui32 chunktype; pic = gli_picture_retrieve(id, 0); if (pic) return pic; if (!giblorb_is_resource_map()) { char filename[1024]; unsigned char buf[8]; sprintf(filename, "%s/PIC%lu", gli_workdir, id); closeafter = TRUE; fl = fopen(filename, "rb"); if (!fl) return NULL; if (fread(buf, 1, 8, fl) != 8) { /* Can't read the first few bytes. Forget it. */ fclose(fl); return NULL; } if (!png_sig_cmp(buf, 0, 8)) { chunktype = giblorb_ID_PNG; } else if (buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF) { chunktype = giblorb_ID_JPEG; } else { /* Not a readable file. Forget it. */ fclose(fl); return NULL; } fseek(fl, 0, 0); } else { long pos; giblorb_get_resource(giblorb_ID_Pict, id, &fl, &pos, NULL, &chunktype); if (!fl) return NULL; fseek(fl, pos, 0); closeafter = FALSE; } pic = malloc(sizeof(picture_t)); pic->refcount = 1; pic->w = 0; pic->h = 0; pic->rgba = NULL; pic->id = id; pic->scaled = FALSE; if (chunktype == giblorb_ID_PNG) load_image_png(fl, pic); if (chunktype == giblorb_ID_JPEG) load_image_jpeg(fl, pic); if (closeafter) fclose(fl); if (!pic->rgba) { free(pic); return NULL; } gli_picture_store(pic); return pic; }