Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

xform.c

Go to the documentation of this file.
00001 /* xform.c - Image transformation functions for gifsicle.
00002    Copyright (C) 1997-9 Eddie Kohler, eddietwo@lcs.mit.edu
00003    This file is part of gifsicle.
00004 
00005    Gifsicle is free software. It is distributed under the GNU Public License,
00006    version 2 or later; you can copy, distribute, or alter it at will, as long
00007    as this notice is kept intact and this source code is made available. There
00008    is no warranty, express or implied. */
00009 
00010 #include "config.h"
00011 #include "gifsicle.h"
00012 #include <stdio.h>
00013 #include <string.h>
00014 #include <ctype.h>
00015 #include <assert.h>
00016 #include <errno.h>
00017 #include <limits.h>
00018 
00019 
00020 /******
00021  * color transforms
00022  **/
00023 
00024 Gt_ColorTransform *
00025 append_color_transform(Gt_ColorTransform *list,
00026                        color_transform_func func, void *data)
00027 {
00028   Gt_ColorTransform *trav;
00029   Gt_ColorTransform *xform = Gif_New(Gt_ColorTransform);
00030   xform->next = 0;
00031   xform->func = func;
00032   xform->data = data;
00033   
00034   for (trav = list; trav && trav->next; trav = trav->next)
00035     ;
00036   if (trav) {
00037     trav->next = xform;
00038     return list;
00039   } else
00040     return xform;
00041 }
00042 
00043 Gt_ColorTransform *
00044 delete_color_transforms(Gt_ColorTransform *list, color_transform_func func)
00045 {
00046   Gt_ColorTransform *prev = 0, *trav = list;
00047   while (trav) {
00048     Gt_ColorTransform *next = trav->next;
00049     if (trav->func == func) {
00050       if (prev) prev->next = next;
00051       else list = next;
00052       Gif_Delete(trav);
00053     } else
00054       prev = trav;
00055     trav = next;
00056   }
00057   return list;
00058 }
00059 
00060 void
00061 apply_color_transforms(Gt_ColorTransform *list, Gif_Stream *gfs)
00062 {
00063   int i;
00064   Gt_ColorTransform *xform;
00065   for (xform = list; xform; xform = xform->next) {
00066     if (gfs->global)
00067       xform->func(gfs->global, xform->data);
00068     for (i = 0; i < gfs->nimages; i++)
00069       if (gfs->images[i]->local)
00070         xform->func(gfs->images[i]->local, xform->data);
00071   }
00072 }
00073 
00074 
00075 typedef struct Gt_ColorChange {
00076   struct Gt_ColorChange *next;
00077   Gif_Color old_color;
00078   Gif_Color new_color;
00079 } Gt_ColorChange;
00080 
00081 void
00082 color_change_transformer(Gif_Colormap *gfcm, void *thunk)
00083 {
00084   int i, have;
00085   Gt_ColorChange *first_change = (Gt_ColorChange *)thunk;
00086   Gt_ColorChange *change;
00087   
00088   /* change colors named by color */
00089   for (i = 0; i < gfcm->ncol; i++)
00090     for (change = first_change; change; change = change->next) {
00091       if (!change->old_color.haspixel)
00092         have = GIF_COLOREQ(&gfcm->col[i], &change->old_color);
00093       else
00094         have = change->old_color.pixel == i;
00095       
00096       if (have) {
00097         gfcm->col[i] = change->new_color;
00098         break;                  /* ignore remaining color changes */
00099       }
00100     }
00101 }
00102 
00103 Gt_ColorTransform *
00104 append_color_change(Gt_ColorTransform *list,
00105                     Gif_Color old_color, Gif_Color new_color)
00106 {
00107   Gt_ColorTransform *xform;
00108   Gt_ColorChange *change = Gif_New(Gt_ColorChange);
00109   change->old_color = old_color;
00110   change->new_color = new_color;
00111   change->next = 0;
00112   
00113   for (xform = list; xform && xform->next; xform = xform->next)
00114     ;
00115   if (!xform || xform->func != &color_change_transformer)
00116     return append_color_transform(list, &color_change_transformer, change);
00117   else {
00118     Gt_ColorChange *prev = (Gt_ColorChange *)(xform->data);
00119     while (prev->next) prev = prev->next;
00120     prev->next = change;
00121     return list;
00122   }
00123 }
00124 
00125 
00126 void
00127 pipe_color_transformer(Gif_Colormap *gfcm, void *thunk)
00128 {
00129   int i, status;
00130   FILE *f;
00131   Gif_Color *col = gfcm->col;
00132   Gif_Colormap *new_cm = 0;
00133   char *command = (char *)thunk;
00134   char *tmp_file = tmpnam(0);
00135   char *new_command;
00136   
00137   if (!tmp_file)
00138     fatal_error("can't create temporary file!");
00139   
00140   new_command = Gif_NewArray(char, strlen(command) + strlen(tmp_file) + 4);
00141   sprintf(new_command, "%s  >%s", command, tmp_file);
00142   f = popen(new_command, "w");
00143   if (!f)
00144     fatal_error("can't run color transformation command: %s", strerror(errno));
00145   Gif_DeleteArray(new_command);
00146   
00147   for (i = 0; i < gfcm->ncol; i++)
00148     fprintf(f, "%d %d %d\n", col[i].red, col[i].green, col[i].blue);
00149   
00150   errno = 0;
00151   status = pclose(f);
00152   if (status < 0) {
00153     error("color transformation error: %s", strerror(errno));
00154     goto done;
00155   } else if (status > 0) {
00156     error("color transformation command failed");
00157     goto done;
00158   }
00159   
00160   f = fopen(tmp_file, "r");
00161   if (!f || feof(f)) {
00162     error("color transformation command generated no output", command);
00163     if (f) fclose(f);
00164     goto done;
00165   }
00166   new_cm = read_colormap_file("<color transformation>", f);
00167   fclose(f);
00168   
00169   if (new_cm) {
00170     int nc = new_cm->ncol;
00171     if (nc < gfcm->ncol) {
00172       nc = gfcm->ncol;
00173       warning("too few colors in color transformation results");
00174     } else if (nc > gfcm->ncol)
00175       warning("too many colors in color transformation results");
00176     for (i = 0; i < nc; i++)
00177       col[i] = new_cm->col[i];
00178   }
00179   
00180  done:
00181   remove(tmp_file);
00182   Gif_DeleteColormap(new_cm);
00183 }
00184 
00185 
00186 
00187 /*****
00188  * crop image; returns true if the image exists
00189  **/
00190 
00191 int
00192 crop_image(Gif_Image *gfi, Gt_Crop *crop)
00193 {
00194   int x, y, w, h, j;
00195   byte **img;
00196   
00197   if (!crop->ready) {
00198     crop->x = crop->spec_x + gfi->left;
00199     crop->y = crop->spec_y + gfi->top;
00200     crop->w = crop->spec_w <= 0 ? gfi->width + crop->spec_w : crop->spec_w;
00201     crop->h = crop->spec_h <= 0 ? gfi->height + crop->spec_h : crop->spec_h;
00202     if (crop->x < 0 || crop->y < 0 || crop->w <= 0 || crop->h <= 0
00203         || crop->x + crop->w > gfi->width
00204         || crop->y + crop->h > gfi->height) {
00205       error("cropping dimensions don't fit image");
00206       crop->ready = 2;
00207     } else
00208       crop->ready = 1;
00209   }
00210   if (crop->ready == 2)
00211     return 1;
00212   
00213   x = crop->x - gfi->left;
00214   y = crop->y - gfi->top;
00215   w = crop->w;
00216   h = crop->h;
00217   
00218   /* Check that the rectangle actually intersects with the image. */
00219   if (x < 0) w += x, x = 0;
00220   if (y < 0) h += y, y = 0;
00221   if (x + w > gfi->width) w = gfi->width - x;
00222   if (y + h > gfi->height) h = gfi->height - y;
00223   
00224   if (w > 0 && h > 0) {
00225     img = Gif_NewArray(byte *, h + 1);
00226     for (j = 0; j < h; j++)
00227       img[j] = gfi->img[y + j] + x;
00228     img[h] = 0;
00229     
00230     /* Change position of image appropriately */
00231     if (crop->whole_stream) {
00232       /* If cropping the whole stream, then this is the first frame. Position
00233          it at (0,0). */
00234       crop->left_off = x + gfi->left;
00235       crop->right_off = y + gfi->top;
00236       gfi->left = 0;
00237       gfi->top = 0;
00238       crop->whole_stream = 0;
00239     } else {
00240       gfi->left += x - crop->left_off;
00241       gfi->top += y - crop->right_off;
00242     }
00243     
00244   } else {
00245     /* Empty image */
00246     w = h = 0;
00247     img = 0;
00248   }
00249   
00250   Gif_DeleteArray(gfi->img);
00251   gfi->img = img;
00252   gfi->width = w;
00253   gfi->height = h;
00254   return gfi->img != 0;
00255 }
00256 
00257 
00258 /*****
00259  * flip and rotate
00260  **/
00261 
00262 void
00263 flip_image(Gif_Image *gfi, int screen_width, int screen_height, int is_vert)
00264 {
00265   int x, y;
00266   int width = gfi->width;
00267   int height = gfi->height;
00268   byte **img = gfi->img;
00269   
00270   /* horizontal flips */
00271   if (!is_vert) {
00272     byte *buffer = Gif_NewArray(byte, width);
00273     byte *trav;
00274     for (y = 0; y < height; y++) {
00275       memcpy(buffer, img[y], width);
00276       trav = img[y] + width - 1;
00277       for (x = 0; x < width; x++)
00278         *trav-- = buffer[x];
00279     }
00280     gfi->left = screen_width - (gfi->left + width);
00281     Gif_DeleteArray(buffer);
00282   }
00283   
00284   /* vertical flips */
00285   if (is_vert) {
00286     byte **buffer = Gif_NewArray(byte *, height);
00287     memcpy(buffer, img, height * sizeof(byte *));
00288     for (y = 0; y < height; y++)
00289       img[y] = buffer[height - y - 1];
00290     gfi->top = screen_height - (gfi->top + height);
00291     Gif_DeleteArray(buffer);
00292   }
00293 }
00294 
00295 void
00296 rotate_image(Gif_Image *gfi, int screen_width, int screen_height, int rotation)
00297 {
00298   int x, y;
00299   int width = gfi->width;
00300   int height = gfi->height;
00301   byte **img = gfi->img;
00302   byte *new_data = Gif_NewArray(byte, width * height);
00303   byte *trav = new_data;
00304   
00305   /* this function can only rotate by 90 or 270 degrees */
00306   assert(rotation == 1 || rotation == 3);
00307   
00308   if (rotation == 1) {
00309     for (x = 0; x < width; x++)
00310       for (y = height - 1; y >= 0; y--)
00311         *trav++ = img[y][x];
00312     x = gfi->left;
00313     gfi->left = screen_height - (gfi->top + height);
00314     gfi->top = x;
00315     
00316   } else {
00317     for (x = width - 1; x >= 0; x--)
00318       for (y = 0; y < height; y++)
00319         *trav++ = img[y][x];
00320     y = gfi->top;
00321     gfi->top = screen_width - (gfi->left + width);
00322     gfi->left = y;
00323   }
00324   
00325   Gif_ReleaseUncompressedImage(gfi);
00326   gfi->width = height;
00327   gfi->height = width;
00328   Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00329 }
00330 
00331 
00332 /*****
00333  * scale
00334  **/
00335 
00336 #define SCALE(d)        ((d) << 10)
00337 #define UNSCALE(d)      ((d) >> 10)
00338 #define SCALE_FACTOR    SCALE(1)
00339 
00340 void
00341 scale_image(Gif_Stream *gfs, Gif_Image *gfi, double xfactor, double yfactor)
00342 {
00343   byte *new_data;
00344   int new_left, new_top, new_right, new_bottom, new_width, new_height;
00345   
00346   int i, j, new_x, new_y;
00347   int scaled_xstep, scaled_ystep, scaled_new_x, scaled_new_y;
00348 
00349   /* Fri 9 Jan 1999: Fix problem with resizing animated GIFs: we scaled from
00350      left edge of the *subimage* to right edge of the subimage, causing
00351      consistency problems when several subimages overlap. Solution: always use
00352      scale factors relating to the *whole image* (the screen size). */
00353   
00354   /* use fixed-point arithmetic */
00355   scaled_xstep = (int)(SCALE_FACTOR * xfactor + 0.5);
00356   scaled_ystep = (int)(SCALE_FACTOR * yfactor + 0.5);
00357   
00358   /* calculate new width and height based on the four edges (left, right, top,
00359      bottom). This is better than simply multiplying the width and height by
00360      the scale factors because it avoids roundoff inconsistencies between
00361      frames on animated GIFs. Don't allow 0-width or 0-height images; GIF
00362      doesn't support them well. */
00363   new_left = UNSCALE(scaled_xstep * gfi->left);
00364   new_top = UNSCALE(scaled_ystep * gfi->top);
00365   new_right = UNSCALE(scaled_xstep * (gfi->left + gfi->width));
00366   new_bottom = UNSCALE(scaled_ystep * (gfi->top + gfi->height));
00367   
00368   new_width = new_right - new_left;
00369   new_height = new_bottom - new_top;
00370 
00371   if (new_width <= 0) new_width = 1, new_right = new_left + 1;
00372   if (new_height <= 0) new_height = 1, new_bottom = new_top + 1;
00373   if (new_width > UNSCALE(INT_MAX) || new_height > UNSCALE(INT_MAX))
00374     fatal_error("new image size is too big for me to handle");
00375   
00376   assert(gfi->img);
00377   new_data = Gif_NewArray(byte, new_width * new_height);
00378   
00379   new_y = new_top;
00380   scaled_new_y = scaled_ystep * gfi->top;
00381   
00382   for (j = 0; j < gfi->height; j++) {
00383     byte *in_line = gfi->img[j];
00384     byte *out_data;
00385     int x_delta, y_delta, yinc;
00386     
00387     scaled_new_y += scaled_ystep;
00388     /* account for images which should've had 0 height but don't */
00389     if (j == gfi->height - 1) scaled_new_y = SCALE(new_bottom);
00390     
00391     if (scaled_new_y < SCALE(new_y + 1)) continue;
00392     y_delta = UNSCALE(scaled_new_y - SCALE(new_y));
00393     
00394     new_x = new_left;
00395     scaled_new_x = scaled_xstep * gfi->left;
00396     out_data = &new_data[(new_y - new_top) * new_width + (new_x - new_left)];
00397     
00398     for (i = 0; i < gfi->width; i++) {
00399       scaled_new_x += scaled_xstep;
00400       /* account for images which should've had 0 width but don't */
00401       if (i == gfi->width - 1) scaled_new_x = SCALE(new_right);
00402       
00403       x_delta = UNSCALE(scaled_new_x - SCALE(new_x));
00404       
00405       for (; x_delta > 0; new_x++, x_delta--, out_data++)
00406         for (yinc = 0; yinc < y_delta; yinc++)
00407           out_data[yinc * new_width] = in_line[i];
00408     }
00409     
00410     new_y += y_delta;
00411   }
00412   
00413   Gif_ReleaseUncompressedImage(gfi);
00414   Gif_ReleaseCompressedImage(gfi);
00415   gfi->width = new_width;
00416   gfi->height = new_height;
00417   gfi->left = UNSCALE(scaled_xstep * gfi->left);
00418   gfi->top = UNSCALE(scaled_ystep * gfi->top);
00419   Gif_SetUncompressedImage(gfi, new_data, Gif_DeleteArrayFunc, 0);
00420 }
00421 
00422 void
00423 resize_stream(Gif_Stream *gfs, int new_width, int new_height)
00424 {
00425   double xfactor, yfactor;
00426   int i;
00427 
00428   if (new_width <= 0)
00429     new_width = (int)(((double)gfs->screen_width / gfs->screen_height) * new_height);
00430   if (new_height <= 0)
00431     new_height = (int)(((double)gfs->screen_height / gfs->screen_width) * new_width);
00432   
00433   Gif_CalculateScreenSize(gfs, 0);
00434   xfactor = (double)new_width / gfs->screen_width;
00435   yfactor = (double)new_height / gfs->screen_height;
00436   for (i = 0; i < gfs->nimages; i++)
00437     scale_image(gfs, gfs->images[i], xfactor, yfactor);
00438   
00439   gfs->screen_width = new_width;
00440   gfs->screen_height = new_height;
00441 }
 

Powered by Plone

This site conforms to the following standards: