~ubuntu-branches/ubuntu/gutsy/amsn/gutsy

« back to all changes in this revision

Viewing changes to utils/TkCximage/src/PhotoFormat.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Theodore Karkoulis
  • Date: 2006-01-04 15:26:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104152602-ipe1yg00rl3nlklv
Tags: 0.95-1
New Upstream Release (closes: #345052, #278575).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  File : TkCximage.cpp
 
3
 
 
4
  Description : Contains all functions for the Tk extension for the CxImage utility
 
5
 
 
6
  Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net)
 
7
*/
 
8
 
 
9
#include "TkCximage.h"
 
10
 
 
11
static ChainedList animated_gifs;
 
12
Tk_ImageDisplayProc *PhotoDisplayOriginal=NULL;
 
13
 
 
14
/////////////////////////////////////
 
15
// Functions to manage lists       //
 
16
/////////////////////////////////////
 
17
 
 
18
ChainedIterator TkCxImage_lstGetListItem(list_element_type list_element_id) { //Get the iterator with the specified id
 
19
 
 
20
  ChainedIterator item;
 
21
 
 
22
  for( item = g_list.begin(); item != g_list.end() && (*item)->list_element_id != list_element_id; item++);
 
23
 
 
24
  return item;
 
25
 
 
26
}
 
27
 
 
28
 
 
29
struct data_item* TkCxImage_lstAddItem(struct data_item* item) { //Add the specified item if its id not already exists
 
30
 
 
31
  if ( !item ) return NULL;
 
32
  if ( TkCxImage_lstGetListItem(item->list_element_id) != g_list.end() ) return NULL;
 
33
 
 
34
  g_list.push_back( item );
 
35
 
 
36
  return item;
 
37
 
 
38
}
 
39
 
 
40
struct data_item* TkCxImage_lstGetItem(list_element_type list_element_id) { //Get the item with the specified id
 
41
 
 
42
        ChainedIterator listitem = TkCxImage_lstGetListItem( list_element_id );
 
43
        if( listitem != g_list.end() )
 
44
                return (*listitem);
 
45
        else
 
46
                return NULL;
 
47
}
 
48
 
 
49
struct data_item* TkCxImage_lstDeleteItem(list_element_type list_element_id) { //Delete the item with the specified id if exists
 
50
 
 
51
        ChainedIterator item = TkCxImage_lstGetListItem( list_element_id );
 
52
        struct data_item* element;
 
53
 
 
54
        if( item != g_list.end() ) {
 
55
                element = (*item);
 
56
                g_list.erase( item );
 
57
                return element;
 
58
        }
 
59
        else {
 
60
                return NULL;
 
61
        }
 
62
 
 
63
}
 
64
 
 
65
////////////////////////////
 
66
// TkCxImage code         //
 
67
////////////////////////////
 
68
 
 
69
int ChanMatch (Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format,int *widthPtr,
 
70
                      int *heightPtr, Tcl_Interp *interp)
 
71
{
 
72
  CxImage image;
 
73
 
 
74
  LOG("Chanel matching"); //
 
75
  LOG("Filename is"); //
 
76
  APPENDLOG(fileName); //
 
77
 
 
78
  // Set escape to -1 to prevent decoding the image, but just return it's width and height
 
79
  //image.SetEscape(-1);
 
80
 
 
81
  if (image.Load(fileName, CXIMAGE_FORMAT_UNKNOWN)) {
 
82
    *widthPtr = image.GetWidth();
 
83
    *heightPtr = image.GetHeight();
 
84
 
 
85
    LOG("Supported Format"); //
 
86
    LOG("Width :"); //
 
87
    APPENDLOG(*widthPtr); //
 
88
    LOG("Heigth :"); //
 
89
    APPENDLOG(*heightPtr); //
 
90
 
 
91
    return true;
 
92
  }
 
93
 
 
94
  return false;
 
95
}
 
96
 
 
97
 
 
98
int ObjMatch (Tcl_Obj *data, Tcl_Obj *format, int *widthPtr, int *heightPtr, Tcl_Interp *interp) {
 
99
 
 
100
  BYTE * buffer = NULL;
 
101
  int length = 0;
 
102
 
 
103
  CxImage image;
 
104
 
 
105
  LOG("Data matching"); //
 
106
 
 
107
  buffer = Tcl_GetByteArrayFromObj(data, &length);
 
108
 
 
109
  LOG(""); //
 
110
 
 
111
  if (image.Decode(buffer, length, CXIMAGE_FORMAT_GIF) ||
 
112
      image.Decode(buffer, length, CXIMAGE_FORMAT_PNG) ||
 
113
      image.Decode(buffer, length, CXIMAGE_FORMAT_JPG) ||
 
114
      image.Decode(buffer, length, CXIMAGE_FORMAT_TGA) ||
 
115
      image.Decode(buffer, length, CXIMAGE_FORMAT_BMP)) {
 
116
    *widthPtr = image.GetWidth();
 
117
    *heightPtr = image.GetHeight();
 
118
 
 
119
    LOG("Supported Format"); //
 
120
    LOG("Width :"); //
 
121
    APPENDLOG(*widthPtr); //
 
122
    LOG("Heigth :"); //
 
123
    APPENDLOG(*heightPtr); //
 
124
 
 
125
    return true;
 
126
  }
 
127
 
 
128
  LOG("Unknown format");
 
129
 
 
130
  return false;
 
131
}
 
132
 
 
133
int ChanRead (Tcl_Interp *interp, Tcl_Channel chan, CONST char *fileName, Tcl_Obj *format, Tk_PhotoHandle imageHandle,
 
134
                     int destX, int destY, int width, int height, int srcX, int srcY)
 
135
{
 
136
        Tcl_Obj *data = Tcl_NewObj();
 
137
 
 
138
        Tcl_SetChannelOption(interp, chan, "-encoding", "binary");
 
139
        Tcl_SetChannelOption(interp, chan, "-translation", "binary");
 
140
 
 
141
        Tcl_ReadChars(chan, data, -1, 0);
 
142
 
 
143
        LOG("Reading from file :"); //
 
144
        APPENDLOG(fileName); //
 
145
 
 
146
  return ObjRead(interp, data, format, imageHandle, destX, destY, width, height, srcX, srcY);
 
147
 
 
148
}
 
149
 
 
150
int ObjRead (Tcl_Interp *interp, Tcl_Obj *data, Tcl_Obj *format, Tk_PhotoHandle imageHandle,
 
151
                    int destX, int destY, int width, int height, int srcX, int srcY)
 
152
{
 
153
 
 
154
        BYTE * buffer = NULL;
 
155
        long size = 0;
 
156
 
 
157
        BYTE * FileData = NULL;
 
158
        int length = 0;
 
159
 
 
160
  CxImage image;
 
161
 
 
162
  LOG("Reading data :"); //
 
163
 
 
164
  FileData = Tcl_GetByteArrayFromObj(data, &length);
 
165
 
 
166
 
 
167
  if (! image.Decode(FileData, length, CXIMAGE_FORMAT_GIF) &&
 
168
      ! image.Decode(FileData, length, CXIMAGE_FORMAT_PNG) &&
 
169
      ! image.Decode(FileData, length, CXIMAGE_FORMAT_JPG) &&
 
170
      ! image.Decode(FileData, length, CXIMAGE_FORMAT_TGA) &&
 
171
      ! image.Decode(FileData, length, CXIMAGE_FORMAT_BMP))
 
172
    return TCL_ERROR;
 
173
 
 
174
#if ANIMATE_GIFS
 
175
  int numframes = image.GetNumFrames();
 
176
#endif
 
177
 
 
178
 
 
179
  LOG("Cropping"); //
 
180
 
 
181
  if(!image.Crop(srcX, srcY, srcX + width, srcY + height)) {
 
182
    Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
183
    return TCL_ERROR;
 
184
  }
 
185
 
 
186
  LOG("Flipping image"); //
 
187
 
 
188
  if(!image.Flip()) {
 
189
    Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
190
    return TCL_ERROR;
 
191
  }
 
192
 
 
193
  LOG("Encoding to RGBA"); //
 
194
 
 
195
  if(!image.Encode2RGBA(buffer, size)) {
 
196
    Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
197
    return TCL_ERROR;
 
198
  }
 
199
 
 
200
  LOG("Setting PhotoImageBlock"); //
 
201
 
 
202
  Tk_PhotoImageBlock block = {
 
203
    buffer,             // pixel ptr
 
204
    width,
 
205
    height,
 
206
    width*4,            // pitch : number of bytes separating 2 adjacent pixels vertically
 
207
    4,                  // pixel size : size in bytes of one pixel .. 4 = RGBA
 
208
  };
 
209
 
 
210
  block.offset[0] = 0;
 
211
  block.offset[1] = 1;
 
212
  block.offset[2] = 2;
 
213
 
 
214
  if ( image.AlphaIsValid() || image.IsTransparent() ) {
 
215
    LOG("Alpha is valid, setting offset[3]"); //
 
216
    block.offset[3] = 3;
 
217
  }
 
218
 
 
219
  LOG("Putting Block into image"); //
 
220
#if TK_MINOR_VERSION == 3
 
221
  Tk_PhotoBlank(imageHandle);
 
222
  Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height);
 
223
#else
 
224
#if TK_MINOR_VERSION == 4
 
225
  Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height, TK_PHOTO_COMPOSITE_SET);
 
226
#else
 
227
#if TK_MINOR_VERSION == 5
 
228
  Tk_PhotoPutBlock((Tcl_Interp *) NULL, imageHandle, &block, destX, destY, width, height, TK_PHOTO_COMPOSITE_SET);
 
229
#endif
 
230
#endif
 
231
#endif
 
232
 
 
233
#if  ANIMATE_GIFS
 
234
        LOG("Getting item");
 
235
        APPENDLOG(imageHandle);
 
236
        GifInfo* item=TkCxImage_lstGetItem(imageHandle);
 
237
        if(item!=NULL) {
 
238
                LOG("Got item in Animated list");
 
239
                Tcl_DeleteTimerHandler(item->timerToken);
 
240
                item->image->DestroyGifFrames();
 
241
                delete item->image;
 
242
                for(GifBuffersIterator it=item->buffers.begin(); it!=item->buffers.end(); it++){
 
243
                        (*it)->Close();
 
244
                        delete (*it);
 
245
                }
 
246
                LOG("Deleting AnimatedGifInfo");
 
247
                APPENDLOG(item->Handle);
 
248
                TkCxImage_lstDeleteItem(item->Handle);
 
249
                delete item;
 
250
        }
 
251
  // If it's an animated gif, take care of it right here
 
252
        if(g_EnableAnimated && numframes > 1) {
 
253
 
 
254
                GifInfo * AnimatedGifInfo = new GifInfo;
 
255
                CxImage *image = NULL;
 
256
 
 
257
                AnimatedGifInfo->CurrentFrame = 0;
 
258
                AnimatedGifInfo->CopiedFrame = -1;
 
259
                AnimatedGifInfo->NumFrames = numframes;
 
260
                AnimatedGifInfo->Handle = imageHandle;
 
261
                AnimatedGifInfo->ImageMaster = (Tk_ImageMaster) *((void **)imageHandle);
 
262
                AnimatedGifInfo->interp = interp;
 
263
                AnimatedGifInfo->image = new CxImage;
 
264
                AnimatedGifInfo->image->RetreiveAllFrame();
 
265
                AnimatedGifInfo->image->SetFrame(numframes - 1);
 
266
                AnimatedGifInfo->image->Decode(FileData, length, CXIMAGE_FORMAT_GIF);
 
267
 
 
268
                for(int i = 0; i < numframes; i++){
 
269
                        if(AnimatedGifInfo->image->GetFrameNo(i) != AnimatedGifInfo->image) {
 
270
                                AnimatedGifInfo->image->GetFrameNo(i)->Flip();
 
271
                        }
 
272
                }
 
273
                LOG("Adding AnimatedGifInfo");
 
274
                APPENDLOG(imageHandle);
 
275
                TkCxImage_lstAddItem(AnimatedGifInfo);
 
276
 
 
277
                /*
 
278
                // Store each frame
 
279
                for(int i = 0; i < numframes; i++){
 
280
                        currentFrame = new CxImage();
 
281
                        currentFrame->SetFrame(i);
 
282
                        if(currentFrame->Decode(FileData, length, CXIMAGE_FORMAT_GIF) && currentFrame->Flip()) {
 
283
                                AnimatedGifInfo->Frames[i] = currentFrame;
 
284
                        } else {
 
285
                                delete currentFrame;
 
286
                                for(int i = 0; i < numframes; i++){
 
287
                                        delete AnimatedGifInfo->Frames[i];
 
288
                                        AnimatedGifInfo->Frames[i] = NULL;
 
289
                                }
 
290
                                delete AnimatedGifInfo->Frames;
 
291
                                AnimatedGifInfo->Frames = NULL;
 
292
                                delete AnimatedGifInfo;
 
293
                                AnimatedGifInfo = NULL;
 
294
                        }
 
295
                }
 
296
        */
 
297
                if (AnimatedGifInfo)
 
298
                        AnimatedGifInfo->timerToken=Tcl_CreateTimerHandler(AnimatedGifInfo->image->GetFrameNo(0)->GetFrameDelay(), AnimateGif, (ClientData) AnimatedGifInfo);
 
299
        }
 
300
 
 
301
#endif // ANIMATE_GIFS
 
302
 
 
303
  LOG("Freeing memory used by buffer"); //
 
304
  image.FreeMemory(buffer);
 
305
 
 
306
  return TCL_OK;
 
307
}
 
308
 
 
309
int ChanWrite (Tcl_Interp *interp, CONST char *fileName, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr) {
 
310
 
 
311
  CxImage image;
 
312
  int Type = CXIMAGE_FORMAT_UNKNOWN;
 
313
  char * cxFormat = NULL;
 
314
  int alpha = 0;
 
315
  BYTE * pixelPtr = NULL;
 
316
 
 
317
  if (format) {
 
318
    cxFormat = Tcl_GetStringFromObj(format, NULL);
 
319
    Type = GetFileTypeFromFormat(cxFormat);
 
320
  }
 
321
 
 
322
  if (Type == CXIMAGE_FORMAT_UNKNOWN) {
 
323
    Type = GetFileTypeFromFileName((char *) fileName);
 
324
  }
 
325
 
 
326
  if (Type == CXIMAGE_FORMAT_UNKNOWN) {
 
327
    Type = CXIMAGE_FORMAT_GIF;
 
328
  }
 
329
 
 
330
  pixelPtr = (BYTE *) malloc(blockPtr->width * blockPtr->height * blockPtr->pixelSize);
 
331
 
 
332
  if (RGB2BGR(blockPtr, pixelPtr)) {
 
333
    alpha = 1;
 
334
  }
 
335
 
 
336
  if(!image.CreateFromArray(pixelPtr, blockPtr->width, blockPtr->height,
 
337
                            8 * blockPtr->pixelSize, blockPtr->pitch, true))
 
338
    {
 
339
      free(pixelPtr);
 
340
      Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
341
      return TCL_ERROR;
 
342
    }
 
343
 
 
344
  free(pixelPtr);
 
345
  if (alpha == 0)
 
346
    image.AlphaDelete();
 
347
 
 
348
  if (Type == CXIMAGE_FORMAT_GIF)
 
349
    image.DecreaseBpp(8, true);
 
350
 
 
351
  if (!image.Save(fileName, Type)) {
 
352
    Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
353
    return TCL_ERROR;
 
354
  }
 
355
 
 
356
  return TCL_OK;
 
357
}
 
358
 
 
359
int StringWrite (Tcl_Interp *interp, Tcl_Obj *format, Tk_PhotoImageBlock *blockPtr) {
 
360
 
 
361
  BYTE * buffer = NULL;
 
362
  long size = 0;
 
363
  int Type = CXIMAGE_FORMAT_UNKNOWN;
 
364
  char * cxFormat = NULL;
 
365
  BYTE * pixelPtr = NULL;
 
366
  int alpha = 0;
 
367
  CxImage image;
 
368
 
 
369
  if (format) {
 
370
    cxFormat = Tcl_GetStringFromObj(format, NULL);
 
371
    Type = GetFileTypeFromFormat(cxFormat);
 
372
  }
 
373
 
 
374
  if (Type == CXIMAGE_FORMAT_UNKNOWN) {
 
375
    Type = CXIMAGE_FORMAT_GIF;
 
376
  }
 
377
 
 
378
  pixelPtr = (BYTE *) malloc(blockPtr->width * blockPtr->height * blockPtr->pixelSize);
 
379
 
 
380
  if (RGB2BGR(blockPtr, pixelPtr)) {
 
381
    alpha = 1;
 
382
  }
 
383
 
 
384
  if(!image.CreateFromArray(pixelPtr, blockPtr->width, blockPtr->height,
 
385
                            8 * blockPtr->pixelSize, blockPtr->pitch, true))
 
386
    {
 
387
      free(pixelPtr);
 
388
      Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
389
      return TCL_ERROR;
 
390
    }
 
391
 
 
392
  free(pixelPtr);
 
393
  if (alpha == 0)
 
394
    image.AlphaDelete();
 
395
 
 
396
  if (Type == CXIMAGE_FORMAT_GIF)
 
397
    image.DecreaseBpp(8, true);
 
398
 
 
399
 
 
400
  if (!image.Encode(buffer, size, Type) ) {
 
401
    Tcl_AppendResult(interp, image.GetLastError(), NULL);
 
402
    return TCL_ERROR;
 
403
  }
 
404
 
 
405
  Tcl_ResetResult(interp);
 
406
  Tcl_AppendResult(interp, buffer);
 
407
 
 
408
  image.FreeMemory(buffer);
 
409
 
 
410
  return TCL_OK;
 
411
}
 
412
 
 
413
 
 
414
#if ANIMATE_GIFS
 
415
void AnimateGif(ClientData data) {
 
416
        GifInfo *Info = (GifInfo *)data;
 
417
        if (Info) { //Info is valid
 
418
                Tk_ImageMaster master = (Tk_ImageMaster) *((void **) Info->Handle);
 
419
                if(master == Info->ImageMaster) {
 
420
                //Image is always the same
 
421
                        if(g_EnableAnimated) {
 
422
                                Info->CurrentFrame++;
 
423
                                if(Info->CurrentFrame == Info->NumFrames)
 
424
                                        Info->CurrentFrame = 0;
 
425
                                CxImage *image = Info->image->GetFrameNo(Info->CurrentFrame);
 
426
                                Tk_ImageChanged(Info->ImageMaster, 0, 0, image->GetWidth(), image->GetHeight(), image->GetWidth(), image->GetHeight());
 
427
                
 
428
                                Info->timerToken=Tcl_CreateTimerHandler(image->GetFrameDelay()?10*image->GetFrameDelay():40, AnimateGif, data);
 
429
                        } else {
 
430
                                int currentFrame = Info->CurrentFrame;
 
431
                                CxImage *image = Info->image->GetFrameNo(currentFrame);
 
432
                                Info->timerToken=Tcl_CreateTimerHandler(image->GetFrameDelay()?10*image->GetFrameDelay():40, AnimateGif, data);
 
433
                        }
 
434
                } else {
 
435
                        LOG("Image destroyed, deleting... Image Master was : ");
 
436
                        APPENDLOG( master );
 
437
                        APPENDLOG(" - ");
 
438
                        APPENDLOG( Info->ImageMaster);
 
439
 
 
440
                        Info->image->DestroyGifFrames();
 
441
                        delete Info->image;
 
442
                        LOG("Deleting AnimatedGifInfo");
 
443
                        APPENDLOG(Info->Handle);
 
444
                        TkCxImage_lstDeleteItem(Info->Handle);
 
445
                        for(GifBuffersIterator it=Info->buffers.begin(); it!=Info->buffers.end(); it++){
 
446
                                (*it)->Close();
 
447
                                delete (*it);
 
448
                        }
 
449
                        delete Info;
 
450
                        Info = NULL;
 
451
                }
 
452
        }
 
453
 
 
454
}
 
455
 
 
456
void PhotoDisplayProcHook(
 
457
        ClientData instanceData,
 
458
        Display *display,
 
459
        Drawable drawable,
 
460
        int imageX,
 
461
        int imageY,
 
462
        int width,
 
463
        int height,
 
464
        int drawableX,
 
465
        int drawableY){
 
466
 
 
467
#ifndef MAC_TCL
 
468
#ifndef WIN32
 
469
 
 
470
  /* 
 
471
   * The whole next block is used to prevent a bug with XGetImage
 
472
   * that happens with Tcl/Tk before 8.4.9 that caused a BadMatch.
 
473
   */
 
474
  Window root_geo;
 
475
  int x_geo, y_geo;
 
476
  unsigned int drawableWidth_geo;
 
477
  unsigned int drawableHeight_geo;
 
478
  unsigned int bd_geo;
 
479
  unsigned int depth_geo;
 
480
  
 
481
  // Make sure there's something to draw
 
482
  if (width < 1 || height < 1) {
 
483
    return;
 
484
  }
 
485
  
 
486
  // Get the drawable's width and height and x and y
 
487
  switch (XGetGeometry(display, drawable, &root_geo, &x_geo, &y_geo, 
 
488
                       &drawableWidth_geo, &drawableHeight_geo, &bd_geo, &depth_geo)) {
 
489
    
 
490
  case BadDrawable:
 
491
  case BadWindow:
 
492
    Tcl_Panic("ClipSizeForDrawable: invalid drawable passed"); 
 
493
    break;
 
494
  }
 
495
  
 
496
  // Make sure we're not requesting a width or heigth more than allowed
 
497
  if (width > drawableWidth_geo) {
 
498
    width = drawableWidth_geo;
 
499
  }
 
500
  
 
501
  if (height > drawableHeight_geo) {
 
502
    height = drawableHeight_geo;
 
503
  }
 
504
  
 
505
  // Make sure the coordinates are valid
 
506
  if (drawableX < 0) {
 
507
    drawableX = 0;
 
508
  }
 
509
  if (drawableY < 0) {
 
510
    drawableY = 0;
 
511
  }
 
512
  
 
513
  /*
 
514
   * End of the fix
 
515
   */
 
516
 
 
517
#endif
 
518
#endif
 
519
 
 
520
 
 
521
        Tk_PhotoHandle handle = (Tk_PhotoHandle) *((void **) instanceData);
 
522
        GifInfo* item=TkCxImage_lstGetItem(handle);
 
523
        if (item != NULL){
 
524
                if (item->CurrentFrame != item->CopiedFrame) { //Frame isn't the good one in the photo buffer
 
525
                        CxImage *image = item->image->GetFrameNo(item->CurrentFrame);
 
526
                        item->CopiedFrame = item->CurrentFrame; //We set the copied frame before to avoid infinite loops
 
527
                        AnimatedGifFrameToTk(NULL, item, image, true);
 
528
                        //fprintf(stderr, "Copied frame n°%u\n",item->CopiedFrame);
 
529
                }
 
530
        }
 
531
 
 
532
        
 
533
 
 
534
        
 
535
        PhotoDisplayOriginal(instanceData,display,drawable,imageX,imageY,width,height,drawableX,drawableY);
 
536
}
 
537
 
 
538
#endif // ANIMATE_GIFS