source: branches/r9/packages/Squeezer/RpSqueezer.c @ 4841

Last change on this file since 4841 was 4841, checked in by gah, 9 years ago
File size: 6.7 KB
RevLine 
[4841]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.