OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkImgPPM.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkImgPPM.c --
3
 *
4
 *      A photo image file handler for PPM (Portable PixMap) files.
5
 *
6
 * Copyright (c) 1994 The Australian National University.
7
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * Author: Paul Mackerras (paulus@cs.anu.edu.au),
13
 *         Department of Computer Science,
14
 *         Australian National University.
15
 *
16
 * RCS: @(#) $Id: tkImgPPM.c,v 1.1.1.1 2002-01-16 10:25:52 markom Exp $
17
 */
18
 
19
#include "tkInt.h"
20
#include "tkPort.h"
21
 
22
/*
23
 * The maximum amount of memory to allocate for data read from the
24
 * file.  If we need more than this, we do it in pieces.
25
 */
26
 
27
#define MAX_MEMORY      10000           /* don't allocate > 10KB */
28
 
29
/*
30
 * Define PGM and PPM, i.e. gray images and color images.
31
 */
32
 
33
#define PGM 1
34
#define PPM 2
35
 
36
/*
37
 * The format record for the PPM file format:
38
 */
39
 
40
static int              FileMatchPPM _ANSI_ARGS_((Tcl_Channel chan,
41
                            char *fileName, char *formatString,
42
                            int *widthPtr, int *heightPtr));
43
static int              FileReadPPM  _ANSI_ARGS_((Tcl_Interp *interp,
44
                            Tcl_Channel chan, char *fileName,
45
                            char *formatString, Tk_PhotoHandle imageHandle,
46
                            int destX, int destY, int width, int height,
47
                            int srcX, int srcY));
48
static int              FileWritePPM _ANSI_ARGS_((Tcl_Interp *interp,
49
                            char *fileName, char *formatString,
50
                            Tk_PhotoImageBlock *blockPtr));
51
 
52
Tk_PhotoImageFormat tkImgFmtPPM = {
53
    "PPM",                      /* name */
54
    FileMatchPPM,               /* fileMatchProc */
55
    NULL,                       /* stringMatchProc */
56
    FileReadPPM,                /* fileReadProc */
57
    NULL,                       /* stringReadProc */
58
    FileWritePPM,               /* fileWriteProc */
59
    NULL,                       /* stringWriteProc */
60
};
61
 
62
/*
63
 * Prototypes for local procedures defined in this file:
64
 */
65
 
66
static int              ReadPPMFileHeader _ANSI_ARGS_((Tcl_Channel chan,
67
                            int *widthPtr, int *heightPtr,
68
                            int *maxIntensityPtr));
69
 
70
/*
71
 *----------------------------------------------------------------------
72
 *
73
 * FileMatchPPM --
74
 *
75
 *      This procedure is invoked by the photo image type to see if
76
 *      a file contains image data in PPM format.
77
 *
78
 * Results:
79
 *      The return value is >0 if the first characters in file "f" look
80
 *      like PPM data, and 0 otherwise.
81
 *
82
 * Side effects:
83
 *      The access position in f may change.
84
 *
85
 *----------------------------------------------------------------------
86
 */
87
 
88
static int
89
FileMatchPPM(chan, fileName, formatString, widthPtr, heightPtr)
90
    Tcl_Channel chan;           /* The image file, open for reading. */
91
    char *fileName;             /* The name of the image file. */
92
    char *formatString;         /* User-specified format string, or NULL. */
93
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
94
                                 * returned here if the file is a valid
95
                                 * raw PPM file. */
96
{
97
    int dummy;
98
 
99
    return ReadPPMFileHeader(chan, widthPtr, heightPtr, &dummy);
100
}
101
 
102
/*
103
 *----------------------------------------------------------------------
104
 *
105
 * FileReadPPM --
106
 *
107
 *      This procedure is called by the photo image type to read
108
 *      PPM format data from a file and write it into a given
109
 *      photo image.
110
 *
111
 * Results:
112
 *      A standard TCL completion code.  If TCL_ERROR is returned
113
 *      then an error message is left in interp->result.
114
 *
115
 * Side effects:
116
 *      The access position in file f is changed, and new data is
117
 *      added to the image given by imageHandle.
118
 *
119
 *----------------------------------------------------------------------
120
 */
121
 
122
static int
123
FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY,
124
        width, height, srcX, srcY)
125
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
126
    Tcl_Channel chan;           /* The image file, open for reading. */
127
    char *fileName;             /* The name of the image file. */
128
    char *formatString;         /* User-specified format string, or NULL. */
129
    Tk_PhotoHandle imageHandle; /* The photo image to write into. */
130
    int destX, destY;           /* Coordinates of top-left pixel in
131
                                 * photo image to be written to. */
132
    int width, height;          /* Dimensions of block of photo image to
133
                                 * be written to. */
134
    int srcX, srcY;             /* Coordinates of top-left pixel to be used
135
                                 * in image being read. */
136
{
137
    int fileWidth, fileHeight, maxIntensity;
138
    int nLines, nBytes, h, type, count;
139
    unsigned char *pixelPtr;
140
    Tk_PhotoImageBlock block;
141
 
142
    type = ReadPPMFileHeader(chan, &fileWidth, &fileHeight, &maxIntensity);
143
    if (type == 0) {
144
        Tcl_AppendResult(interp, "couldn't read raw PPM header from file \"",
145
                fileName, "\"", NULL);
146
        return TCL_ERROR;
147
    }
148
    if ((fileWidth <= 0) || (fileHeight <= 0)) {
149
        Tcl_AppendResult(interp, "PPM image file \"", fileName,
150
                "\" has dimension(s) <= 0", (char *) NULL);
151
        return TCL_ERROR;
152
    }
153
    if ((maxIntensity <= 0) || (maxIntensity >= 256)) {
154
        char buffer[30];
155
 
156
        sprintf(buffer, "%d", maxIntensity);
157
        Tcl_AppendResult(interp, "PPM image file \"", fileName,
158
                "\" has bad maximum intensity value ", buffer,
159
                (char *) NULL);
160
        return TCL_ERROR;
161
    }
162
 
163
    if ((srcX + width) > fileWidth) {
164
        width = fileWidth - srcX;
165
    }
166
    if ((srcY + height) > fileHeight) {
167
        height = fileHeight - srcY;
168
    }
169
    if ((width <= 0) || (height <= 0)
170
        || (srcX >= fileWidth) || (srcY >= fileHeight)) {
171
        return TCL_OK;
172
    }
173
 
174
    if (type == PGM) {
175
        block.pixelSize = 1;
176
        block.offset[0] = 0;
177
        block.offset[1] = 0;
178
        block.offset[2] = 0;
179
    }
180
    else {
181
        block.pixelSize = 3;
182
        block.offset[0] = 0;
183
        block.offset[1] = 1;
184
        block.offset[2] = 2;
185
    }
186
    block.width = width;
187
    block.pitch = block.pixelSize * fileWidth;
188
 
189
    Tk_PhotoExpand(imageHandle, destX + width, destY + height);
190
 
191
    if (srcY > 0) {
192
        Tcl_Seek(chan, (srcY * block.pitch), SEEK_CUR);
193
    }
194
 
195
    nLines = (MAX_MEMORY + block.pitch - 1) / block.pitch;
196
    if (nLines > height) {
197
        nLines = height;
198
    }
199
    if (nLines <= 0) {
200
        nLines = 1;
201
    }
202
    nBytes = nLines * block.pitch;
203
    pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
204
    block.pixelPtr = pixelPtr + srcX * block.pixelSize;
205
 
206
    for (h = height; h > 0; h -= nLines) {
207
        if (nLines > h) {
208
            nLines = h;
209
            nBytes = nLines * block.pitch;
210
        }
211
        count = Tcl_Read(chan, (char *) pixelPtr, nBytes);
212
        if (count != nBytes) {
213
            Tcl_AppendResult(interp, "error reading PPM image file \"",
214
                    fileName, "\": ",
215
                    Tcl_Eof(chan) ? "not enough data" : Tcl_PosixError(interp),
216
                    (char *) NULL);
217
            ckfree((char *) pixelPtr);
218
            return TCL_ERROR;
219
        }
220
        if (maxIntensity != 255) {
221
            unsigned char *p;
222
 
223
            for (p = pixelPtr; count > 0; count--, p++) {
224
                *p = (((int) *p) * 255)/maxIntensity;
225
            }
226
        }
227
        block.height = nLines;
228
        Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines);
229
        destY += nLines;
230
    }
231
 
232
    ckfree((char *) pixelPtr);
233
    return TCL_OK;
234
}
235
 
236
/*
237
 *----------------------------------------------------------------------
238
 *
239
 * FileWritePPM --
240
 *
241
 *      This procedure is invoked to write image data to a file in PPM
242
 *      format.
243
 *
244
 * Results:
245
 *      A standard TCL completion code.  If TCL_ERROR is returned
246
 *      then an error message is left in interp->result.
247
 *
248
 * Side effects:
249
 *      Data is written to the file given by "fileName".
250
 *
251
 *----------------------------------------------------------------------
252
 */
253
 
254
static int
255
FileWritePPM(interp, fileName, formatString, blockPtr)
256
    Tcl_Interp *interp;
257
    char *fileName;
258
    char *formatString;
259
    Tk_PhotoImageBlock *blockPtr;
260
{
261
    Tcl_Channel chan;
262
    int w, h;
263
    int greenOffset, blueOffset, nBytes;
264
    unsigned char *pixelPtr, *pixLinePtr;
265
    char header[30];
266
 
267
    chan = Tcl_OpenFileChannel(interp, fileName, "w", 0666);
268
    if (chan == NULL) {
269
        return TCL_ERROR;
270
    }
271
 
272
    sprintf(header, "P6\n%d %d\n255\n", blockPtr->width, blockPtr->height);
273
    Tcl_Write(chan, header, -1);
274
 
275
    pixLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
276
    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
277
    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
278
 
279
    if ((greenOffset == 1) && (blueOffset == 2) && (blockPtr->pixelSize == 3)
280
            && (blockPtr->pitch == (blockPtr->width * 3))) {
281
        nBytes = blockPtr->height * blockPtr->pitch;
282
        if (Tcl_Write(chan, (char *) pixLinePtr, nBytes) != nBytes) {
283
            goto writeerror;
284
        }
285
    } else {
286
        for (h = blockPtr->height; h > 0; h--) {
287
            pixelPtr = pixLinePtr;
288
            for (w = blockPtr->width; w > 0; w--) {
289
                if ((Tcl_Write(chan, (char *) &pixelPtr[0], 1) == -1)
290
                        || (Tcl_Write(chan, (char *) &pixelPtr[greenOffset], 1) == -1)
291
                        || (Tcl_Write(chan, (char *) &pixelPtr[blueOffset], 1) == -1)) {
292
                    goto writeerror;
293
                }
294
                pixelPtr += blockPtr->pixelSize;
295
            }
296
            pixLinePtr += blockPtr->pitch;
297
        }
298
    }
299
 
300
    if (Tcl_Close(NULL, chan) == 0) {
301
        return TCL_OK;
302
    }
303
    chan = NULL;
304
 
305
 writeerror:
306
    Tcl_AppendResult(interp, "error writing \"", fileName, "\": ",
307
            Tcl_PosixError(interp), (char *) NULL);
308
    if (chan != NULL) {
309
        Tcl_Close(NULL, chan);
310
    }
311
    return TCL_ERROR;
312
}
313
 
314
/*
315
 *----------------------------------------------------------------------
316
 *
317
 * ReadPPMFileHeader --
318
 *
319
 *      This procedure reads the PPM header from the beginning of a
320
 *      PPM file and returns information from the header.
321
 *
322
 * Results:
323
 *      The return value is PGM if file "f" appears to start with
324
 *      a valid PGM header, PPM if "f" appears to start with a valid
325
 *      PPM header, and 0 otherwise.  If the header is valid,
326
 *      then *widthPtr and *heightPtr are modified to hold the
327
 *      dimensions of the image and *maxIntensityPtr is modified to
328
 *      hold the value of a "fully on" intensity value.
329
 *
330
 * Side effects:
331
 *      The access position in f advances.
332
 *
333
 *----------------------------------------------------------------------
334
 */
335
 
336
static int
337
ReadPPMFileHeader(chan, widthPtr, heightPtr, maxIntensityPtr)
338
    Tcl_Channel chan;           /* Image file to read the header from */
339
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
340
                                 * returned here. */
341
    int *maxIntensityPtr;       /* The maximum intensity value for
342
                                 * the image is stored here. */
343
{
344
#define BUFFER_SIZE 1000
345
    char buffer[BUFFER_SIZE];
346
    int i, numFields, firstInLine;
347
    int type = 0;
348
    char c;
349
 
350
    /*
351
     * Read 4 space-separated fields from the file, ignoring
352
     * comments (any line that starts with "#").
353
     */
354
 
355
    if (Tcl_Read(chan, &c, 1) != 1) {
356
        return 0;
357
    }
358
    firstInLine = 1;
359
    i = 0;
360
    for (numFields = 0; numFields < 4; numFields++) {
361
        /*
362
         * Skip comments and white space.
363
         */
364
 
365
        while (1) {
366
            while (isspace(UCHAR(c))) {
367
                firstInLine = (c == '\n');
368
                if (Tcl_Read(chan, &c, 1) != 1) {
369
                    return 0;
370
                }
371
            }
372
            if (c != '#') {
373
                break;
374
            }
375
            do {
376
                if (Tcl_Read(chan, &c, 1) != 1) {
377
                    return 0;
378
                }
379
            } while (c != '\n');
380
            firstInLine = 1;
381
        }
382
 
383
        /*
384
         * Read a field (everything up to the next white space).
385
         */
386
 
387
        while (!isspace(UCHAR(c))) {
388
            if (i < (BUFFER_SIZE-2)) {
389
                buffer[i] = c;
390
                i++;
391
            }
392
            if (Tcl_Read(chan, &c, 1) != 1) {
393
                goto done;
394
            }
395
        }
396
        if (i < (BUFFER_SIZE-1)) {
397
            buffer[i] = ' ';
398
            i++;
399
        }
400
        firstInLine = 0;
401
    }
402
    done:
403
    buffer[i] = 0;
404
 
405
    /*
406
     * Parse the fields, which are: id, width, height, maxIntensity.
407
     */
408
 
409
    if (strncmp(buffer, "P6 ", 3) == 0) {
410
        type = PPM;
411
    } else if (strncmp(buffer, "P5 ", 3) == 0) {
412
        type = PGM;
413
    } else {
414
        return 0;
415
    }
416
    if (sscanf(buffer+3, "%d %d %d", widthPtr, heightPtr, maxIntensityPtr)
417
            != 3) {
418
        return 0;
419
    }
420
    return type;
421
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.