source: branches/1.4/gui/src/RpSqueezer.c @ 5039

Last change on this file since 5039 was 4515, checked in by gah, 10 years ago

add new utilities (squeezer, tweener), update RpDxToVtk?.c, experimental RpDicomToVtk?.c not used yet

File size: 6.7 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpSqueezer - image distortion for "cover flow" effect.
4 *
5 *  Modifies a Tk image to squeeze one side or the other and perhaps
6 *  foreshorten the image.
7 *
8 *    squeezer ?options...? <original> <newImage>
9 *        -side left|right     << which side to squeeze
10 *        -amount <fraction>   << squeeze down to this size (0-1)
11 *        -shorten <fraction>  << squeeze horizontally to this size (0-1)
12 *        -shadow <fraction>   << apply shadow horizontally (strength 0-1)
13 *
14 * ======================================================================
15 *  AUTHOR:  Michael McLennan, Purdue University
16 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
17 *
18 *  See the file "license.terms" for information on usage and
19 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
20 * ======================================================================
21 */
22#include <string.h>
23#include <math.h>
24#include "tk.h"
25
26/*
27 * Forward declarations.
28 */
29static int RpSqueezerCmd _ANSI_ARGS_((ClientData clientData,
30    Tcl_Interp *interp, int argc, CONST char **argv));
31
32/*
33 * ------------------------------------------------------------------------
34 *  RpSqueezer_Init --
35 *
36 *  Installs the "squeezer" command in a Tcl interpreter.
37 *
38 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
39 *  message in the interp) if anything goes wrong.
40 * ------------------------------------------------------------------------
41 */
42int
43RpSqueezer_Init(interp)
44    Tcl_Interp *interp;         /* interpreter being initialized */
45{
46    /* install the widget command */
47    Tcl_CreateCommand(interp, "squeezer", RpSqueezerCmd,
48        NULL, NULL);
49
50    return TCL_OK;
51}
52
53/*
54 * ----------------------------------------------------------------------
55 * RpSqueezerCmd()
56 *
57 * Called to handle the "squeezer" command.  Returns TCL_OK on success
58 * and TCL_ERROR otherwise.
59 * ----------------------------------------------------------------------
60 */
61static int
62RpSqueezerCmd(clientData, interp, argc, argv)
63    ClientData clientData;        /* not used */
64    Tcl_Interp *interp;           /* current interpreter */
65    int argc;                     /* number of command arguments */
66    CONST char **argv;            /* command argument strings */
67{
68    int sideRight = 1;
69    double amount = 0.8;
70    double shorten = 0.7;
71    double shadow = 0.0;
72
73    int i, j, j0, j1, p, srcw, srch, destw, desth, nbytes;
74    int srci, srcj, rval, gval, bval, aval;
75    double shfac;
76    Tk_PhotoHandle srcPhoto, destPhoto;
77    Tk_PhotoImageBlock srcBlock, destBlock;
78    unsigned char* pixelPtr;
79
80   /* parse command line options */
81    i = 1;
82    while (i < argc) {
83        if (*argv[i] != '-') {
84            break;
85        }
86        if (i+1 >= argc) {
87            Tcl_AppendResult(interp, "missing value for option \"",
88                argv[i], "\"", (char*)NULL);
89            return TCL_ERROR;
90        }
91
92        if (strcmp(argv[i],"-side") == 0) {
93            if (strcmp(argv[i+1],"left") == 0) {
94                sideRight = 0;
95            } else if (strcmp(argv[i+1],"right") == 0) {
96                sideRight = 1;
97            } else {
98                Tcl_AppendResult(interp, "bad value \"",
99                    argv[i+1], "\": should be left or right", (char*)NULL);
100                return TCL_ERROR;
101            }
102        }
103        else if (strcmp(argv[i],"-amount") == 0) {
104            if (Tcl_GetDouble(interp, argv[i+1], &amount) != TCL_OK) {
105                return TCL_ERROR;
106            }
107        }
108        else if (strcmp(argv[i],"-shorten") == 0) {
109            if (Tcl_GetDouble(interp, argv[i+1], &shorten) != TCL_OK) {
110                return TCL_ERROR;
111            }
112        }
113        else if (strcmp(argv[i],"-shadow") == 0) {
114            if (Tcl_GetDouble(interp, argv[i+1], &shadow) != TCL_OK) {
115                return TCL_ERROR;
116            }
117        }
118        else {
119            Tcl_AppendResult(interp, "bad option \"", argv[i],
120                "\": should be -side, -amount, -shorten, -shadow",
121                (char*)NULL);
122            return TCL_ERROR;
123        }
124
125        i += 2;
126    }
127
128    if (i+2 != argc) {
129        Tcl_AppendResult(interp, "wrong # args: should be \"",
130            argv[0], " ?options? origImg newImg\"", (char*)NULL);
131        return TCL_ERROR;
132    }
133
134    /* get the last two args... source and destination images */
135    srcPhoto = Tk_FindPhoto(interp, argv[i]);
136    if (srcPhoto == NULL) {
137        Tcl_AppendResult(interp, "image \"", argv[i], "doesn't exist",
138            " or isn't a photo image", (char*)NULL);
139        return TCL_ERROR;
140    }
141
142    destPhoto = Tk_FindPhoto(interp, argv[i+1]);
143    if (destPhoto == NULL) {
144        Tcl_AppendResult(interp, "image \"", argv[i+1], "doesn't exist",
145            " or isn't a photo image", (char*)NULL);
146        return TCL_ERROR;
147    }
148
149    /*
150     * Update the destination image to the proper size.
151     */
152    Tk_PhotoGetSize(srcPhoto, &srcw, &srch);
153    destw = round(srcw * shorten);
154
155    /*
156     * Scan through each column along the width.  Compute the height
157     * of the shortened column and then compute the pixels along the
158     * height.
159     */
160    Tk_PhotoGetImage(srcPhoto, &srcBlock);
161
162    destBlock.width = destw;
163    destBlock.height = srch;
164    destBlock.pixelSize = 4;
165    destBlock.offset[0] = 0;
166    destBlock.offset[1] = 1;
167    destBlock.offset[2] = 2;
168    destBlock.offset[3] = 3;
169    destBlock.pitch = destBlock.pixelSize * destw;
170    nbytes = destBlock.pitch * srch;
171    destBlock.pixelPtr = (unsigned char*)ckalloc((unsigned)nbytes);
172    memset(destBlock.pixelPtr, 0, (size_t)nbytes);
173
174    for (p=0; p < destw; p++) {
175        i = (sideRight) ? p : destw-p-1;
176        desth = round(srch - srch*(1.0-amount)*p/(double)destw);
177        j0 = (srch-desth)/2;
178        j1 = j0 + desth;
179
180        /* strength of shadow */
181        shfac = 1.0 - shadow * p/(double)destw;
182
183        for (j=j0; j < j1; j++) {
184            srci = srcw * i/(double)destw;
185            srcj = srch * (j-j0)/(double)desth;
186            pixelPtr = srcBlock.pixelPtr + srcj*srcBlock.pitch
187                + srci*srcBlock.pixelSize;
188            rval = *(pixelPtr+srcBlock.offset[0]);
189            gval = *(pixelPtr+srcBlock.offset[1]);
190            bval = *(pixelPtr+srcBlock.offset[2]);
191            aval = *(pixelPtr+srcBlock.offset[3]);
192
193            pixelPtr = destBlock.pixelPtr + j*destBlock.pitch
194                + i*destBlock.pixelSize;
195            *(pixelPtr+0) = round(rval*shfac);
196            *(pixelPtr+1) = round(gval*shfac);
197            *(pixelPtr+2) = round(bval*shfac);
198            *(pixelPtr+3) = aval;
199        }
200    }
201    Tk_PhotoSetSize(destPhoto, destw, srch);
202    Tk_PhotoPutBlock(destPhoto, &destBlock, 0, 0,
203        destBlock.width, destBlock.height, TK_PHOTO_COMPOSITE_SET);
204
205    ckfree((char*)destBlock.pixelPtr);
206    return TCL_OK;
207}
Note: See TracBrowser for help on using the repository browser.