source: branches/r9/packages/squeezer/RpSqueezer.c @ 4852

Last change on this file since 4852 was 4852, checked in by gah, 10 years ago
File size: 7.1 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 * ----------------------------------------------------------------------
35 * RpSqueezerCmd()
36 *
37 * Called to handle the "squeezer" command.  Returns TCL_OK on success
38 * and TCL_ERROR otherwise.
39 * ----------------------------------------------------------------------
40 */
41static int
42RpSqueezerCmd(clientData, interp, argc, argv)
43    ClientData clientData;        /* not used */
44    Tcl_Interp *interp;           /* current interpreter */
45    int argc;                     /* number of command arguments */
46    CONST char **argv;            /* command argument strings */
47{
48    int sideRight = 1;
49    double amount = 0.8;
50    double shorten = 0.7;
51    double shadow = 0.0;
52
53    int i, j, j0, j1, p, srcw, srch, destw, desth, nbytes;
54    int srci, srcj, rval, gval, bval, aval;
55    double shfac;
56    Tk_PhotoHandle srcPhoto, destPhoto;
57    Tk_PhotoImageBlock srcBlock, destBlock;
58    unsigned char* pixelPtr;
59
60   /* parse command line options */
61    i = 1;
62    while (i < argc) {
63        if (*argv[i] != '-') {
64            break;
65        }
66        if (i+1 >= argc) {
67            Tcl_AppendResult(interp, "missing value for option \"",
68                argv[i], "\"", (char*)NULL);
69            return TCL_ERROR;
70        }
71
72        if (strcmp(argv[i],"-side") == 0) {
73            if (strcmp(argv[i+1],"left") == 0) {
74                sideRight = 0;
75            } else if (strcmp(argv[i+1],"right") == 0) {
76                sideRight = 1;
77            } else {
78                Tcl_AppendResult(interp, "bad value \"",
79                    argv[i+1], "\": should be left or right", (char*)NULL);
80                return TCL_ERROR;
81            }
82        }
83        else if (strcmp(argv[i],"-amount") == 0) {
84            if (Tcl_GetDouble(interp, argv[i+1], &amount) != TCL_OK) {
85                return TCL_ERROR;
86            }
87        }
88        else if (strcmp(argv[i],"-shorten") == 0) {
89            if (Tcl_GetDouble(interp, argv[i+1], &shorten) != TCL_OK) {
90                return TCL_ERROR;
91            }
92        }
93        else if (strcmp(argv[i],"-shadow") == 0) {
94            if (Tcl_GetDouble(interp, argv[i+1], &shadow) != TCL_OK) {
95                return TCL_ERROR;
96            }
97        }
98        else {
99            Tcl_AppendResult(interp, "bad option \"", argv[i],
100                "\": should be -side, -amount, -shorten, -shadow",
101                (char*)NULL);
102            return TCL_ERROR;
103        }
104
105        i += 2;
106    }
107
108    if (i+2 != argc) {
109        Tcl_AppendResult(interp, "wrong # args: should be \"",
110            argv[0], " ?options? origImg newImg\"", (char*)NULL);
111        return TCL_ERROR;
112    }
113
114    /* get the last two args... source and destination images */
115    srcPhoto = Tk_FindPhoto(interp, argv[i]);
116    if (srcPhoto == NULL) {
117        Tcl_AppendResult(interp, "image \"", argv[i], "doesn't exist",
118            " or isn't a photo image", (char*)NULL);
119        return TCL_ERROR;
120    }
121
122    destPhoto = Tk_FindPhoto(interp, argv[i+1]);
123    if (destPhoto == NULL) {
124        Tcl_AppendResult(interp, "image \"", argv[i+1], "doesn't exist",
125            " or isn't a photo image", (char*)NULL);
126        return TCL_ERROR;
127    }
128
129    /*
130     * Update the destination image to the proper size.
131     */
132    Tk_PhotoGetSize(srcPhoto, &srcw, &srch);
133    destw = round(srcw * shorten);
134
135    /*
136     * Scan through each column along the width.  Compute the height
137     * of the shortened column and then compute the pixels along the
138     * height.
139     */
140    Tk_PhotoGetImage(srcPhoto, &srcBlock);
141
142    destBlock.width = destw;
143    destBlock.height = srch;
144    destBlock.pixelSize = 4;
145    destBlock.offset[0] = 0;
146    destBlock.offset[1] = 1;
147    destBlock.offset[2] = 2;
148    destBlock.offset[3] = 3;
149    destBlock.pitch = destBlock.pixelSize * destw;
150    nbytes = destBlock.pitch * srch;
151    destBlock.pixelPtr = (unsigned char*)ckalloc((unsigned)nbytes);
152    memset(destBlock.pixelPtr, 0, (size_t)nbytes);
153
154    for (p=0; p < destw; p++) {
155        i = (sideRight) ? p : destw-p-1;
156        desth = round(srch - srch*(1.0-amount)*p/(double)destw);
157        j0 = (srch-desth)/2;
158        j1 = j0 + desth;
159
160        /* strength of shadow */
161        shfac = 1.0 - shadow * p/(double)destw;
162
163        for (j=j0; j < j1; j++) {
164            srci = srcw * i/(double)destw;
165            srcj = srch * (j-j0)/(double)desth;
166            pixelPtr = srcBlock.pixelPtr + srcj*srcBlock.pitch
167                + srci*srcBlock.pixelSize;
168            rval = *(pixelPtr+srcBlock.offset[0]);
169            gval = *(pixelPtr+srcBlock.offset[1]);
170            bval = *(pixelPtr+srcBlock.offset[2]);
171            aval = *(pixelPtr+srcBlock.offset[3]);
172
173            pixelPtr = destBlock.pixelPtr + j*destBlock.pitch
174                + i*destBlock.pixelSize;
175            *(pixelPtr+0) = round(rval*shfac);
176            *(pixelPtr+1) = round(gval*shfac);
177            *(pixelPtr+2) = round(bval*shfac);
178            *(pixelPtr+3) = aval;
179        }
180    }
181#if (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION >= 5)
182    if (Tk_PhotoSetSize(interp, destPhoto, destw, srch) != TCL_OK) {
183        return TCL_ERROR;
184    }
185    if (Tk_PhotoPutBlock(interp, destPhoto, &destBlock, 0, 0, destBlock.width,
186                destBlock.height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) {
187        return TCL_ERROR;
188    }
189#else
190    Tk_PhotoSetSize(destPhoto, destw, srch);
191    Tk_PhotoPutBlock(destPhoto, &destBlock, 0, 0,
192        destBlock.width, destBlock.height, TK_PHOTO_COMPOSITE_SET);
193#endif
194    ckfree((char*)destBlock.pixelPtr);
195    return TCL_OK;
196}
197
198/*
199 * ------------------------------------------------------------------------
200 *  RapptureSqueezer_Init --
201 *
202 *  Installs the "squeezer" command in a Tcl interpreter.
203 *
204 *  Returns TCL_OK if successful, or TCL_ERROR (along with an error
205 *  message in the interp) if anything goes wrong.
206 * ------------------------------------------------------------------------
207 */
208int
209RapptureSqueezer_Init(interp)
210    Tcl_Interp *interp;         /* interpreter being initialized */
211{
212    /* install the widget command */
213    Tcl_CreateCommand(interp, "squeezer", RpSqueezerCmd,
214        NULL, NULL);
215
216    return TCL_OK;
217}
Note: See TracBrowser for help on using the repository browser.