BRL-CAD
tkImgFmtPIX.c
Go to the documentation of this file.
1 /* T K I M G F M T P I X . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1994-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  *
19  * 3. The name of the author may not be used to endorse or promote
20  * products derived from this software without specific prior written
21  * permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /** @file libtclcad/tkImgFmtPIX.c
36  *
37  * A photo image file handler for BRL-CAD(tm) ".pix" format files.
38  *
39  * Based on:
40  * tkImgFmtPPM.c --
41  *
42  * A photo image file handler for PPM (Portable PixMap) files.
43  *
44  * Questionable whether they actually hold copyright or are simply
45  * being given credit:
46  *
47  * Copyright (c) 1994 The Australian National University.
48  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
49  *
50  * Author: Paul Mackerras (paulus@cs.anu.edu.au),
51  * Department of Computer Science,
52  * Australian National University.
53  */
54 
55 #include "common.h"
56 
57 /* make sure we have tk if we're going to compile this up */
58 #ifdef HAVE_TK
59 
60 #include <stdio.h>
61 #include <string.h>
62 
63 #include "vmath.h"
64 #include "bu/malloc.h"
65 #include "bn.h"
66 #include "fb.h"
67 #include "tk.h"
68 
69 
70 /* we need tk version numbers for compatibility compilation */
71 #if !defined(TK_MAJOR_VERSION) || (TK_MAJOR_VERSION != 8)
72 # error "Expecting Tk 8"
73 #endif
74 
75 
76 /*
77  * The format record for the PIX file format:
78  */
79 
80 static int FileMatchPIX _ANSI_ARGS_((Tcl_Channel chan,
81  const char *fileName,
82  Tcl_Obj *format, int *widthPtr,
83  int *heightPtr, Tcl_Interp *interp));
84 static int FileReadPIX _ANSI_ARGS_((Tcl_Interp *interp,
85  Tcl_Channel chan,
86  const char *fileName, Tcl_Obj *formatString,
87  Tk_PhotoHandle imageHandle, int destX, int destY,
88  int width, int height, int srcX, int srcY));
89 static int FileWritePIX _ANSI_ARGS_((Tcl_Interp *interp,
90  const char *fileName, Tcl_Obj *formatString,
91  Tk_PhotoImageBlock *blockPtr));
92 
93 Tk_PhotoImageFormat tkImgFmtPIX = {
94  "PIX", /* name */
95  FileMatchPIX, /* fileMatchProc */
96  NULL, /* stringMatchProc */
97  FileReadPIX, /* fileReadProc */
98  NULL, /* stringReadProc */
99  FileWritePIX, /* fileWriteProc */
100  NULL, /* stringWriteProc */
101  NULL /* nextPtr/tk-private */
102 };
103 
104 /*
105  * Prototypes for local procedures defined in this file:
106  */
107 
108 
109 /*
110  *----------------------------------------------------------------------
111  *
112  * FileMatchPIX --
113  *
114  * This procedure is invoked by the photo image type to see if
115  * a file contains image data in PIX format.
116  *
117  * Results:
118  * The return value is >0 if the format option seems to be requesting
119  * the PIX image type.
120  *
121  * Side effects:
122  * The access position in f may change.
123  *
124  *----------------------------------------------------------------------
125  */
126 
127 static int
128 FileMatchPIX(Tcl_Channel UNUSED(chan), const char *fileName, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp)
129 
130  /* The name of the image file. */
131  /* User-specified format string, or NULL. */
132  /* The dimensions of the image are
133  * returned here if the file is a valid
134  * raw PIX file. */
135 
136 {
137  /* The format string must be nonnull and it must contain the word "pix". */
138  /* If the user also specified the dimensions in the format string,
139  use those. Otherwise, guess from the file size. */
140  char *formatString;
141  int len;
142  size_t width, height;
143 
144  if (format == NULL || interp == NULL)
145  return 0;
146 
147  formatString = Tcl_GetStringFromObj(format, &len);
148  if (formatString == NULL) return 0;
149 
150  if (strstr(formatString, "pix") == NULL &&
151  strstr(formatString, "PIX") == NULL)
152  return 0;
153 
154  if (fb_common_name_size(&width, &height, formatString) <= 0) {
155  if (fb_common_file_size(&width, &height, fileName, 3) <= 0) {
156  return 0;
157  }
158  }
159 
160  *widthPtr = (int)width;
161  *heightPtr = (int)height;
162 
163  return 1;
164 }
165 
166 /*
167  *----------------------------------------------------------------------
168  *
169  * FileReadPIX --
170  *
171  * This procedure is called by the photo image type to read
172  * PIX format data from a file and write it into a given
173  * photo image.
174  *
175  * Results:
176  * A standard TCL completion code. If TCL_ERROR is returned
177  * then an error message is left in interp.
178  *
179  * Side effects:
180  * The access position in file f is changed, and new data is
181  * added to the image given by imageHandle.
182  *
183  *----------------------------------------------------------------------
184  */
185 
186 static int
187 FileReadPIX(Tcl_Interp *interp, Tcl_Channel chan, const char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height, int srcX, int srcY)
188  /* Interpreter to use for reporting errors. */
189 
190  /* The name of the image file. */
191  /* User-specified format string, or NULL. */
192  /* The photo image to write into. */
193  /* Coordinates of top-left pixel in
194  * photo image to be written to. */
195  /* Dimensions of block of photo image to
196  * be written to. */
197  /* Coordinates of top-left pixel to be used
198  * in image being read. */
199 {
200  size_t fileWidth, fileHeight;
201  int nBytes, h, count;
202  unsigned char *pixelPtr;
203  Tk_PhotoImageBlock block;
204  char *formatString;
205  int len;
206 
207  /* Determine dimensions of file. */
208 
209  formatString = Tcl_GetStringFromObj(format, &len);
210 
211  if (fb_common_name_size(&fileWidth, &fileHeight, formatString) <= 0)
212  if (fb_common_file_size(&fileWidth, &fileHeight, fileName, 3) <= 0) {
213  Tcl_AppendResult(interp, "cannot determine dimensions of \"",
214  fileName, "\": please use -format pix-w#-n#",
215  NULL);
216  return TCL_ERROR;
217  }
218 
219  if ((fileWidth <= 0) || (fileHeight <= 0)) {
220  Tcl_AppendResult(interp, "PIX image file \"", fileName,
221  "\" has dimension(s) <= 0", (char *) NULL);
222  return TCL_ERROR;
223  }
224 
225  if ((size_t)(srcX + width) > fileWidth) {
226  width = fileWidth - srcX;
227  }
228  if ((size_t)(srcY + height) > fileHeight) {
229  height = fileHeight - srcY;
230  }
231  if ((width <= 0) || (height <= 0)
232  || ((size_t)srcX >= fileWidth) || ((size_t)srcY >= fileHeight)) {
233  return TCL_OK;
234  }
235 
236  block.pixelSize = 3;
237  block.offset[0] = 0;
238  block.offset[1] = 1;
239  block.offset[2] = 2;
240  block.width = width;
241  block.pitch = block.pixelSize * fileWidth;
242 
243 #if TK_MINOR_VERSION < 5
244  Tk_PhotoExpand(imageHandle, destX + width, destY + height);
245 #else
246  Tk_PhotoExpand(interp, imageHandle, destX + width, destY + height);
247 #endif
248 
249  if ((size_t)(srcY + height) < fileHeight) {
250  Tcl_Seek( chan, (long) ((fileHeight - srcY - height) * block.pitch),
251  SEEK_CUR );
252 
253  }
254 
255  nBytes = block.pitch;
256  pixelPtr = (unsigned char *) bu_malloc((unsigned) nBytes,
257  "PIX image buffer");
258  block.pixelPtr = pixelPtr + srcX * block.pixelSize;
259 
260  for (h = height; h > 0; h--) {
261  count = Tcl_Read( chan, (char *)pixelPtr, nBytes );
262  if (count != nBytes) {
263  Tcl_AppendResult(interp, "error reading PIX image file \"",
264  fileName, "\": ",
265  Tcl_Eof(chan) ? "not enough data" : Tcl_PosixError(interp),
266  (char *) NULL);
267  bu_free((char *) pixelPtr, "PIX image");
268  return TCL_ERROR;
269  }
270  block.height = 1;
271 #if TK_MINOR_VERSION < 5
272  Tk_PhotoPutBlock(imageHandle, &block, destX, destY+h-1, width, height, 1);
273 #else
274  Tk_PhotoPutBlock(interp, imageHandle, &block, destX, destY+h-1, width, height, 1);
275 #endif
276  }
277 
278  bu_free((char *) pixelPtr, "PIX image buffer");
279  return TCL_OK;
280 }
281 
282 /*
283  *----------------------------------------------------------------------
284  *
285  * FileWritePIX --
286  *
287  * This procedure is invoked to write image data to a file in PIX
288  * format.
289  *
290  * Results:
291  * A standard TCL completion code. If TCL_ERROR is returned
292  * then an error message is left in interp.
293  *
294  * Side effects:
295  * Data is written to the file given by "fileName".
296  *
297  *----------------------------------------------------------------------
298  */
299 
300 static int
301 FileWritePIX(Tcl_Interp *interp, const char *fileName, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr)
302 {
303  FILE *f;
304  int w, h;
305  int greenOffset, blueOffset;
306  unsigned char *pixelPtr, *pixLinePtr;
307 
308  if ((f = fopen(fileName, "wb")) == NULL) {
309  Tcl_AppendResult(interp, fileName, ": ", Tcl_PosixError(interp), (char *)NULL);
310  return TCL_ERROR;
311  }
312 
313  pixLinePtr = blockPtr->pixelPtr + blockPtr->offset[0] +
314  (blockPtr->height-1)*blockPtr->pitch;
315  greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
316  blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
317 
318  for (h = blockPtr->height; h > 0; h--) {
319  pixelPtr = pixLinePtr;
320  for (w = blockPtr->width; w > 0; w--) {
321  if ((putc(pixelPtr[0], f) == EOF)
322  || (putc(pixelPtr[greenOffset], f) == EOF)
323  || (putc(pixelPtr[blueOffset], f) == EOF))
324  {
325  goto writeerror;
326  }
327  pixelPtr += blockPtr->pixelSize;
328  }
329  pixLinePtr -= blockPtr->pitch;
330  }
331 
332  if (fclose(f) == 0) {
333  return TCL_OK;
334  }
335  f = NULL;
336 
337  writeerror:
338  Tcl_AppendResult(interp, "error writing \"", fileName, "\" as format [", format, "]: ", Tcl_PosixError(interp), (char *) NULL);
339  if (f != NULL) {
340  fclose(f);
341  }
342  return TCL_ERROR;
343 }
344 
345 #endif /* HAVE_TK */
346 
347 /*
348  * Local Variables:
349  * mode: C
350  * tab-width: 8
351  * indent-tabs-mode: t
352  * c-file-style: "stroustrup"
353  * End:
354  * ex: shiftwidth=4 tabstop=8
355  */
ustring interp
Header file for the BRL-CAD common definitions.
ustring width
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
int fb_common_name_size(size_t *widthp, size_t *heightp, const char *name)
Definition: asize.c:137
#define UNUSED(parameter)
Definition: common.h:239
int fb_common_file_size(size_t *widthp, size_t *heightp, const char *filename, int pixel_size)
Definition: asize.c:86
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328