1 #include "img.h"
2 #include "img_conv.h"
3 #include "Icon.h"
4 #include <stdlib.h>
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 static Bool initialized = false;
11
12 void
apc_img_init(void)13 apc_img_init( void)
14 {
15 if ( initialized) croak("Attempt to initialize image subsystem twice");
16 list_create( &imgCodecs, 8, 8);
17 initialized = true;
18 }
19
20 #define CHK if ( !initialized) croak("Image subsystem is not initialized");
21
22 void
apc_img_done(void)23 apc_img_done( void)
24 {
25 int i;
26
27 CHK;
28 for ( i = 0; i < imgCodecs. count; i++) {
29 PImgCodec c = ( PImgCodec)( imgCodecs. items[ i]);
30 if ( c-> instance)
31 c-> vmt-> done( c);
32 free( c);
33 }
34 list_destroy( &imgCodecs);
35 initialized = false;
36 }
37
38 Bool
apc_img_register(PImgCodecVMT codec,void * initParam)39 apc_img_register( PImgCodecVMT codec, void * initParam)
40 {
41 PImgCodec c;
42
43 CHK;
44 if ( !codec) return false;
45 c = ( PImgCodec) malloc( sizeof( struct ImgCodec) + codec-> size);
46 if ( !c) return false;
47
48 memset( c, 0, sizeof( struct ImgCodec));
49 c-> vmt = ( PImgCodecVMT) ((( Byte *) c) + sizeof( struct ImgCodec));
50 c-> initParam = initParam;
51 memcpy( c-> vmt, codec, codec-> size);
52 list_add( &imgCodecs, ( Handle) c);
53 return true;
54 }
55
56 static void *
init(PImgCodecInfo * info,void * param)57 init( PImgCodecInfo * info, void * param)
58 {
59 return NULL;
60 }
61
62 static void
done(PImgCodec instance)63 done( PImgCodec instance)
64 {
65 }
66
67 static HV *
defaults(PImgCodec instance)68 defaults( PImgCodec instance)
69 {
70 return newHV();
71 }
72
73 static void
check_in(PImgCodec instance,HV * system,HV * user)74 check_in( PImgCodec instance, HV * system, HV * user)
75 {
76 }
77
78 static void *
open_load(PImgCodec instance,PImgLoadFileInstance fi)79 open_load( PImgCodec instance, PImgLoadFileInstance fi)
80 {
81 return NULL;
82 }
83
84 static Bool
load(PImgCodec instance,PImgLoadFileInstance fi)85 load( PImgCodec instance, PImgLoadFileInstance fi)
86 {
87 return false;
88 }
89
90 static void
close_load(PImgCodec instance,PImgLoadFileInstance fi)91 close_load( PImgCodec instance, PImgLoadFileInstance fi)
92 {
93 free( fi-> instance);
94 }
95
96 static void *
open_save(PImgCodec instance,PImgSaveFileInstance fi)97 open_save( PImgCodec instance, PImgSaveFileInstance fi)
98 {
99 return NULL;
100 }
101
102 static Bool
save(PImgCodec instance,PImgSaveFileInstance fi)103 save( PImgCodec instance, PImgSaveFileInstance fi)
104 {
105 return false;
106 }
107
108 static void
close_save(PImgCodec instance,PImgSaveFileInstance fi)109 close_save( PImgCodec instance, PImgSaveFileInstance fi)
110 {
111 free( fi-> instance);
112 }
113
114
115 List imgCodecs;
116 struct ImgCodecVMT CNullImgCodecVMT = {
117 sizeof( struct ImgCodecVMT),
118 init,
119 done,
120 defaults,
121 check_in,
122 open_load,
123 load,
124 close_load,
125 defaults,
126 check_in,
127 open_save,
128 save,
129 close_save
130 };
131
132 void
apc_img_profile_add(HV * to,HV * from,HV * keys)133 apc_img_profile_add( HV * to, HV * from, HV * keys)
134 {
135 HE *he;
136 hv_iterinit(( HV*) keys);
137 for (;;)
138 {
139 char *key;
140 int keyLen;
141 SV ** holder;
142 if (( he = hv_iternext( keys)) == NULL)
143 return;
144 key = (char*) HeKEY( he);
145 keyLen = HeKLEN( he);
146 if ( !hv_exists( from, key, keyLen))
147 continue;
148 holder = hv_fetch( from, key, keyLen, 0);
149 if ( holder)
150 (void) hv_store( to, key, keyLen, newSVsv( *holder), 0);
151 }
152 }
153
154 static ssize_t
stdio_read(void * f,size_t bufsize,void * buffer)155 stdio_read( void * f, size_t bufsize, void * buffer)
156 {
157 return fread( buffer, 1, bufsize, ( FILE*) f);
158 }
159
160 static ssize_t
stdio_write(void * f,size_t bufsize,void * buffer)161 stdio_write( void * f, size_t bufsize, void * buffer)
162 {
163 return fwrite( buffer, 1, bufsize, ( FILE*) f);
164 }
165
166 static int
stdio_seek(void * f,long offset,int whence)167 stdio_seek( void * f, long offset, int whence)
168 {
169 return fseek( ( FILE*) f, offset, whence);
170 }
171
172 static long
stdio_tell(void * f)173 stdio_tell( void * f)
174 {
175 return ftell( ( FILE*) f);
176 }
177
178
179 static ImgIORequest std_ioreq = {
180 stdio_read,
181 stdio_write,
182 stdio_seek,
183 stdio_tell,
184 (void*) fflush,
185 (void*) ferror
186 };
187
188 PList
apc_img_load(Handle self,char * fileName,Bool is_utf8,PImgIORequest ioreq,HV * profile,char * error)189 apc_img_load( Handle self, char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * profile, char * error)
190 {
191 dPROFILE;
192 int i, profiles_len = 0, lastFrame = -2, codecID = -1;
193 PList ret;
194 PImgCodec c = NULL;
195 ImgLoadFileInstance fi;
196 AV * profiles = NULL;
197 HV * def = NULL, * firstObjectExtras = NULL, * commonHV = NULL;
198 Bool err = false;
199 Bool loadExtras = false, noImageData = false;
200 Bool incrementalLoad = false;
201 Bool iconUnmask = false;
202 Bool blending = true;
203 Bool noIncomplete = false;
204 char * baseClassName = "Prima::Image";
205 ImgIORequest sioreq;
206 int load_mask;
207 char dummy_error_buf[256];
208
209
210 #define out(x){ err = true;\
211 strncpy( fi.errbuf, x, 256);\
212 goto EXIT_NOW;}
213
214 #define outd(x,d){ err = true;\
215 snprintf( fi.errbuf, 256, x, d);\
216 goto EXIT_NOW;}
217
218 CHK;
219 memset( &fi, 0, sizeof( fi));
220 ret = plist_create( 8, 8);
221 if ( !ret) out("Not enough memory")
222
223 fi. errbuf = error ? error : dummy_error_buf;
224 fi. errbuf[0] = 0;
225
226 /* open file */
227 if ( ioreq == NULL) {
228 memcpy( &sioreq, &std_ioreq, sizeof( sioreq));
229 if (( sioreq. handle = prima_open_file( fileName, is_utf8, "rb")) == NULL)
230 out( strerror( errno));
231 fi. req = &sioreq;
232 fi. req_is_stdio = true;
233 load_mask = IMG_LOAD_FROM_FILE;
234 } else {
235 fi. req = ioreq;
236 fi. req_is_stdio = false;
237 load_mask = IMG_LOAD_FROM_STREAM;
238 }
239 fi. fileName = fileName;
240 fi. is_utf8 = is_utf8;
241 fi. stop = false;
242
243 /* assigning user file profile */
244 if ( pexist( index)) {
245 fi. frameMapSize = 1;
246 if ( !( fi. frameMap = (int*) malloc( sizeof( int))))
247 out("Not enough memory");
248 if ((*fi. frameMap = pget_i( index)) < 0)
249 out("Invalid index");
250 } else if ( pexist( map)) {
251 SV * sv = pget_sv( map);
252 if ( SvOK( sv)) {
253 if ( SvROK( sv) && SvTYPE( SvRV( sv)) == SVt_PVAV) {
254 AV * av = ( AV*) SvRV( sv);
255 int len = av_len( av) + 1;
256 if ( !( fi. frameMap = ( int *) malloc( sizeof( int) * len)))
257 out("Not enough memory");
258 for ( i = 0; i < len; i++) {
259 SV ** holder = av_fetch( av, i, 0);
260 if ( !holder) out("Array panic on 'map' property");
261 if (( fi. frameMap[ i] = SvIV( *holder)) < 0)
262 out("Invalid index on 'map' property");
263 }
264 fi. frameMapSize = len;
265 } else
266 out("Not an array passed to 'map' property");
267 }
268 } else if ( pexist( loadAll) && pget_B( loadAll)) {
269 fi. loadAll = true;
270 } else {
271 fi. frameMapSize = 1;
272 if ( ! (fi. frameMap = ( int*) malloc( sizeof( int))))
273 out("Not enough memory");
274 *fi. frameMap = 0;
275 }
276
277 if ( pexist( loadExtras) && pget_B( loadExtras))
278 fi. loadExtras = loadExtras = true;
279
280 if ( pexist( noImageData) && pget_B( noImageData))
281 fi. noImageData = noImageData = true;
282
283 if ( pexist( iconUnmask) && pget_B( iconUnmask))
284 fi. iconUnmask = iconUnmask = true;
285
286 if ( pexist( blending) && !pget_B( blending))
287 fi. blending = blending = false;
288
289 if ( pexist( noIncomplete) && pget_B( noIncomplete))
290 fi. noIncomplete = noIncomplete = true;
291
292 if ( pexist( eventMask))
293 fi. eventMask = pget_i( eventMask);
294
295 if ( pexist( eventDelay))
296 fi. eventDelay = 1000.0 * pget_f( eventDelay);
297 if ( fi. eventDelay <= 0)
298 fi. eventDelay = 100; /* 100 ms. reasonable? */
299 EVENT_SCANLINES_RESET(&fi);
300
301 if ( pexist( profiles)) {
302 SV * sv = pget_sv( profiles);
303 if ( SvOK( sv) && SvROK( sv) && SvTYPE( SvRV( sv)) == SVt_PVAV) {
304 profiles = ( AV *) SvRV( sv);
305 profiles_len = av_len( profiles);
306 } else
307 out("Not an array passed to 'profiles' property");
308 }
309
310 if ( pexist( className)) {
311 PVMT vmt;
312 baseClassName = pget_c( className);
313 vmt = gimme_the_vmt( baseClassName);
314 while ( vmt && vmt != (PVMT)CImage)
315 vmt = vmt-> base;
316 if ( !vmt)
317 outd("class '%s' is not a Prima::Image descendant", baseClassName);
318 }
319
320 /* all other properties to be parsed by codec */
321 fi. extras = profile;
322
323 fi. fileProperties = newHV();
324 fi. frameCount = -1;
325
326 /* finding codec */
327 {
328 Bool * loadmap = ( Bool *) malloc( sizeof( Bool) * imgCodecs. count);
329
330 if ( !loadmap)
331 out("Not enough memory");
332 memset( loadmap, 0, sizeof( Bool) * imgCodecs. count);
333 for ( i = 0; i < imgCodecs. count; i++) {
334 c = ( PImgCodec ) ( imgCodecs. items[ i]);
335 if ( !c-> instance)
336 c-> instance = c-> vmt-> init( &c->info, c-> initParam);
337 if ( !c-> instance) { /* failed to initialize, retry next time */
338 loadmap[ i] = true;
339 continue;
340 }
341 }
342 c = NULL;
343
344 /* finding by extension first */
345 if ( fileName) {
346 int fileNameLen = strlen( fileName);
347 for ( i = 0; i < imgCodecs. count; i++) {
348 int j = 0, found = false;
349 if ( loadmap[ i]) continue;
350 c = ( PImgCodec ) ( imgCodecs. items[ i]);
351 while ( c-> info-> fileExtensions[ j]) {
352 char * ext = c-> info-> fileExtensions[ j];
353 int extLen = strlen( ext);
354 if ( extLen < fileNameLen && stricmp( fileName + fileNameLen - extLen, ext) == 0) {
355 found = true;
356 break;
357 }
358 j++;
359 }
360 if ( found) {
361 loadmap[ i] = true;
362
363 if ( !( c-> info-> IOFlags & load_mask)) {
364 c = NULL;
365 continue;
366 }
367 if (( fi. instance = c-> vmt-> open_load( c, &fi)) != NULL) {
368 codecID = i;
369 break;
370 }
371
372 if ( fi. stop) {
373 err = true;
374 free( loadmap);
375 goto EXIT_NOW;
376 }
377 }
378 c = NULL;
379 }
380 }
381
382 /* use first suitable codec */
383 if ( c == NULL) {
384 for ( i = 0; i < imgCodecs. count; i++) {
385 if ( loadmap[ i]) continue;
386 c = ( PImgCodec ) ( imgCodecs. items[ i]);
387 if ( !( c-> info-> IOFlags & load_mask)) {
388 c = NULL;
389 continue;
390 }
391 if (( fi. instance = c-> vmt-> open_load( c, &fi)) != NULL) {
392 codecID = i;
393 break;
394 }
395 if ( fi. stop) {
396 err = true;
397 free( loadmap);
398 goto EXIT_NOW;
399 }
400 c = NULL;
401 }
402 }
403 free( loadmap);
404 if ( !c) out("No appropriate codec found");
405 }
406
407 if ( fi. loadAll) {
408 if ( fi. frameCount >= 0) {
409 fi. frameMapSize = fi. frameCount;
410 if ( !( fi. frameMap = (int*) malloc( fi. frameCount * sizeof(int))))
411 out("Not enough memory");
412 for ( i = 0; i < fi. frameCount; i++)
413 fi. frameMap[i] = i;
414 } else {
415 fi. frameMapSize = INT_MAX;
416 incrementalLoad = true;
417 }
418 }
419
420
421 /* use common profile */
422 def = c-> vmt-> load_defaults( c);
423 commonHV = newHV();
424 if ( profile) {
425 c-> vmt-> load_check_in( c, commonHV, profile);
426 apc_img_profile_add( commonHV, profile, def);
427 }
428
429 if ( fi. loadExtras && c-> info-> fileType)
430 (void) hv_store( fi. fileProperties, "codecID", 7, newSViv( codecID), 0);
431
432 /* loading */
433 for ( i = 0; i < fi. frameMapSize; i++) {
434 HV * profile = commonHV;
435 char * className = baseClassName;
436
437 fi. frame = incrementalLoad ? i : fi. frameMap[ i];
438 if (
439 ( fi. frameCount >= 0 && fi. frame >= fi. frameCount) ||
440 ( !(c-> info-> IOFlags & IMG_LOAD_MULTIFRAME) && fi. frame > 0)
441 ) {
442 if ( !(c-> info-> IOFlags & IMG_LOAD_MULTIFRAME) && fi. frameCount < 0)
443 fi. frameCount = i;
444 c-> vmt-> close_load( c, &fi);
445 if ( incrementalLoad)
446 /* that means, codec bothered to set frameCount at last - report no error then */
447 goto EXIT_NOW;
448 out("Frame index out of range");
449 }
450
451 fi. loadExtras = loadExtras;
452 fi. noImageData = noImageData;
453 fi. iconUnmask = iconUnmask;
454 fi. blending = blending;
455 fi. noIncomplete = noIncomplete;
456 fi. wasTruncated = false;
457
458 /* query profile */
459 if ( profiles && ( i <= profiles_len)) {
460 HV * hv;
461 SV ** holder = av_fetch( profiles, i, 0);
462 if ( !holder) outd("Array panic on 'profiles[%d]' property", i);
463 if ( SvOK( *holder)) {
464 if ( SvROK( *holder) && SvTYPE( SvRV( *holder)) == SVt_PVHV)
465 hv = ( HV*) SvRV( *holder);
466 else
467 outd("Not a hash passed to 'profiles[%d]' property", i);
468 profile = newHV();
469 apc_img_profile_add( profile, commonHV, commonHV);
470 c-> vmt-> load_check_in( c, profile, hv);
471 apc_img_profile_add( profile, hv, def);
472 {
473 HV * profile = hv;
474 if ( pexist( loadExtras))
475 fi. loadExtras = pget_B( loadExtras);
476 if ( pexist( noImageData))
477 fi. noImageData = pget_B( noImageData);
478 if ( pexist( iconUnmask))
479 fi. iconUnmask = pget_B( iconUnmask);
480 if ( pexist( blending))
481 fi. blending = pget_B( blending);
482 }
483 }
484 }
485
486 fi. jointFrame = ( fi. frame == lastFrame + 1);
487 fi. profile = profile;
488 lastFrame = fi. frame;
489
490 /* query className */
491 if ( pexist( className)) {
492 PVMT vmt;
493 className = pget_c( className);
494 vmt = gimme_the_vmt( className);
495 while ( vmt && vmt != (PVMT)CImage)
496 vmt = vmt-> base;
497 if ( !vmt) {
498 if ( fi. profile != commonHV) sv_free(( SV *) fi. profile);
499 outd("class '%s' is not a Prima::Image descendant", className);
500 }
501 }
502
503 /* create storage */
504 if (( i > 0) || ( self == NULL_HANDLE)) {
505 HV * profile = newHV();
506 fi. object = Object_create( className, profile);
507 sv_free(( SV *) profile);
508 if ( !fi. object) {
509 if ( fi. profile != commonHV) sv_free(( SV *) fi. profile);
510 outd("Failed to create object '%s'", className);
511 }
512 } else
513 fi. object = self;
514
515 if ( fi. iconUnmask && kind_of( fi. object, CIcon))
516 PIcon( fi. object)-> autoMasking = amNone;
517
518 fi. frameProperties = newHV();
519 if ( fi. loadExtras && c-> info-> fileType)
520 (void) hv_store( fi. frameProperties, "codecID", 7, newSViv( codecID), 0);
521
522 /* loading image */
523 if ( !c-> vmt-> load( c, &fi)) {
524 c-> vmt-> close_load( c, &fi);
525 sv_free(( SV *) fi. frameProperties);
526 if ( fi. object != self)
527 Object_destroy( fi. object);
528 if ( fi. profile != commonHV) sv_free(( SV *) fi. profile);
529 if ( incrementalLoad) {
530 if ( fi. frameCount < 0)
531 fi. frameCount = fi. frame;
532 else if ( fi.frame < fi.frameCount )
533 err = true;
534 /* or it is EOF, report no error then */
535 goto EXIT_NOW;
536 }
537 err = true;
538 goto EXIT_NOW;
539 }
540
541 if ( fi. loadExtras && fi. wasTruncated)
542 (void) hv_store( fi. frameProperties, "truncated", 9, newSVpv( fi.errbuf, 0 ), 0);
543
544 /* checking for grayscale */
545 {
546 PImage i = ( PImage) fi. object;
547 if ( !( i-> type & imGrayScale))
548 switch ( i-> type & imBPP) {
549 case imbpp1:
550 if ( i-> palSize == 2 && memcmp( i-> palette, stdmono_palette, sizeof( stdmono_palette)) == 0)
551 i-> type |= imGrayScale;
552 break;
553 case imbpp4:
554 if ( i-> palSize == 16 && memcmp( i-> palette, std16gray_palette, sizeof( std16gray_palette)) == 0)
555 i-> type |= imGrayScale;
556 break;
557 case imbpp8:
558 if ( i-> palSize == 256 && memcmp( i-> palette, std256gray_palette, sizeof( std256gray_palette)) == 0)
559 i-> type |= imGrayScale;
560 break;
561 }
562 }
563
564 /* updating image */
565 if ( !fi. noImageData) {
566 CImage( fi. object)-> update_change( fi. object);
567 /* loaders are ok to be lazy and use autoMasking for post-creation of the mask */
568 if ( fi. iconUnmask && kind_of( fi. object, CIcon))
569 PIcon( fi. object)-> autoMasking = amNone;
570 }
571
572 /* applying extras */
573 if ( fi. loadExtras) {
574 HV * extras = newHV();
575 SV * sv = newRV_noinc(( SV *) extras);
576
577 apc_img_profile_add( extras, fi. fileProperties, fi. fileProperties);
578 apc_img_profile_add( extras, fi. frameProperties, fi. frameProperties);
579 if ( i == 0) firstObjectExtras = extras;
580 (void) hv_store(( HV* )SvRV((( PAnyObject) fi. object)-> mate), "extras", 6, newSVsv( sv), 0);
581 sv_free( sv);
582 } else if ( fi. noImageData) { /* no extras, report dimensions only */
583 HV * extras = newHV();
584 SV * sv = newRV_noinc(( SV *) extras), **item;
585 if (( item = hv_fetch( fi. frameProperties, "width", 5, 0)) && SvOK( *item))
586 (void) hv_store( extras, "width", 5, newSVsv( *item), 0);
587 else
588 (void) hv_store( extras, "width", 5, newSViv(PImage(fi.object)-> w), 0);
589 if (( item = hv_fetch( fi. frameProperties, "height", 6, 0)) && SvOK( *item))
590 (void) hv_store( extras, "height", 6, newSVsv( *item), 0);
591 else
592 (void) hv_store( extras, "height", 6, newSViv(PImage(fi.object)-> h), 0);
593 (void) hv_store(( HV* )SvRV((( PAnyObject) fi. object)-> mate), "extras", 6, newSVsv( sv), 0);
594 sv_free( sv);
595 }
596
597 sv_free(( SV *) fi. frameProperties);
598 if ( fi. profile != commonHV) sv_free(( SV *) fi. profile);
599
600 list_add( ret, fi. object);
601 }
602
603 c-> vmt-> close_load( c, &fi);
604
605 /* returning info for null load request */
606 if ( self && loadExtras && fi. frameMapSize == 0) {
607 HV * extras = newHV();
608 SV * sv = newRV_noinc(( SV *) extras);
609 apc_img_profile_add( extras, fi. fileProperties, fi. fileProperties);
610 firstObjectExtras = extras;
611 (void) hv_store(( HV* )SvRV((( PAnyObject) self)-> mate), "extras", 6, newSVsv( sv), 0);
612 sv_free( sv);
613 }
614
615 EXIT_NOW:;
616 if ( err && fi.errbuf[0] == 0)
617 strcpy(fi.errbuf, fi.wasTruncated ? "Truncated file" : "Internal error");
618 if ( fi. frameCount < 0 && pexist( wantFrames) && pget_i( wantFrames)) {
619 if ( ioreq != NULL)
620 req_seek( ioreq, 0, SEEK_SET);
621 fi. frameCount = apc_img_frame_count( fileName, is_utf8, ioreq);
622 }
623 if ( firstObjectExtras)
624 (void) hv_store( firstObjectExtras, "frames", 6, newSViv( fi. frameCount), 0);
625 if ( err && ret)
626 list_add( ret, NULL_HANDLE); /* indicate the error */
627 if ( def)
628 sv_free(( SV *) def);
629 if ( commonHV)
630 sv_free(( SV *) commonHV);
631 if ( fi. fileProperties)
632 sv_free((SV *) fi. fileProperties);
633 if ( ioreq == NULL && fi.req != NULL && fi. req-> handle != NULL)
634 fclose(( FILE*) fi. req-> handle);
635 free( fi. frameMap);
636 return ret;
637 #undef out
638 #undef outd
639 }
640
641 int
apc_img_frame_count(char * fileName,Bool is_utf8,PImgIORequest ioreq)642 apc_img_frame_count( char * fileName, Bool is_utf8, PImgIORequest ioreq )
643 {
644 PImgCodec c = NULL;
645 ImgLoadFileInstance fi;
646 int i, frameMap, ret = 0;
647 char error[256];
648 ImgIORequest sioreq;
649 int load_mask;
650
651 CHK;
652 memset( &fi, 0, sizeof( fi));
653 /* open file */
654 if ( ioreq == NULL) {
655 memcpy( &sioreq, &std_ioreq, sizeof( sioreq));
656 if (( sioreq. handle = prima_open_file( fileName, is_utf8, "rb")) == NULL)
657 goto EXIT_NOW;
658 fi. req = &sioreq;
659 fi. req_is_stdio = true;
660 load_mask = IMG_LOAD_FROM_FILE;
661 } else {
662 fi. req = ioreq;
663 fi. req_is_stdio = false;
664 load_mask = IMG_LOAD_FROM_STREAM;
665 }
666
667 /* assigning request */
668 fi. fileName = fileName;
669 fi. is_utf8 = is_utf8;
670 fi. frameMapSize = frameMap = 0;
671 fi. frameMap = &frameMap;
672 fi. loadExtras = true;
673 fi. noImageData = true;
674 fi. iconUnmask = false;
675 fi. blending = false;
676 fi. noIncomplete = false;
677 fi. extras = newHV();
678 fi. fileProperties = newHV();
679 fi. frameCount = -1;
680 fi. errbuf = error;
681 fi. stop = false;
682
683 /* finding codec */
684 {
685 Bool * loadmap = ( Bool*) malloc( sizeof( Bool) * imgCodecs. count);
686
687 if ( !loadmap)
688 return 0;
689 memset( loadmap, 0, sizeof( Bool) * imgCodecs. count);
690 for ( i = 0; i < imgCodecs. count; i++) {
691 c = ( PImgCodec ) ( imgCodecs. items[ i]);
692 if ( !c-> instance)
693 c-> instance = c-> vmt-> init( &c->info, c-> initParam);
694 if ( !c-> instance) { /* failed to initialize, retry next time */
695 loadmap[ i] = true;
696 continue;
697 }
698 }
699
700 c = NULL;
701
702 /* finding by extension first */
703 if ( fileName) {
704 int fileNameLen = strlen( fileName);
705 for ( i = 0; i < imgCodecs. count; i++) {
706 int j = 0, found = false;
707 if ( loadmap[ i]) continue;
708 c = ( PImgCodec ) ( imgCodecs. items[ i]);
709 while ( c-> info-> fileExtensions[ j]) {
710 char * ext = c-> info-> fileExtensions[ j];
711 int extLen = strlen( ext);
712 if ( extLen < fileNameLen && stricmp( fileName + fileNameLen - extLen, ext) == 0) {
713 found = true;
714 break;
715 }
716 j++;
717 }
718 if ( found) {
719 loadmap[ i] = true;
720
721 if ( !( c-> info-> IOFlags & load_mask)) {
722 c = NULL;
723 continue;
724 }
725 if (( fi. instance = c-> vmt-> open_load( c, &fi)) != NULL)
726 break;
727
728 if ( fi. stop) {
729 free( loadmap);
730 goto EXIT_NOW;
731 }
732 }
733 c = NULL;
734 }
735 }
736
737 if ( c == NULL) {
738 for ( i = 0; i < imgCodecs. count; i++) {
739 if ( loadmap[ i]) continue;
740 c = ( PImgCodec ) ( imgCodecs. items[ i]);
741 if ( !( c-> info-> IOFlags & load_mask)) {
742 c = NULL;
743 continue;
744 }
745 if (( fi. instance = c-> vmt-> open_load( c, &fi)) != NULL)
746 break;
747 if ( fi. stop) {
748 free( loadmap);
749 goto EXIT_NOW;
750 }
751 c = NULL;
752 }
753 }
754 free( loadmap);
755 if ( !c) goto EXIT_NOW;
756 }
757
758 /* can tell now? */
759
760 if ( fi. frameCount >= 0) {
761 c-> vmt-> close_load( c, &fi);
762 ret = fi. frameCount;
763 goto EXIT_NOW;
764 }
765
766 if ( !( c-> info-> IOFlags & IMG_LOAD_MULTIFRAME)) {
767 c-> vmt-> close_load( c, &fi);
768 ret = 1; /* single-framed file. what else? */
769 goto EXIT_NOW;
770 }
771
772 /* if can't, trying to load huge index, hoping that if */
773 /* codec have a sequential access, it eventually meet the */
774 /* EOF and report the frame count */
775 {
776 HV * profile = newHV();
777 fi. object = Object_create( "Prima::Image", profile);
778 sv_free(( SV *) profile);
779 frameMap = fi. frame = INT_MAX;
780 fi. frameProperties = newHV();
781 }
782
783 /* loading image */
784 if ( c-> vmt-> load( c, &fi) || fi. frameCount >= 0) {
785 /* well, INT_MAX frame is ok, and maybe more, but can't report more anyway */
786 c-> vmt-> close_load( c, &fi);
787 ret = ( fi. frameCount < 0) ? INT_MAX : fi. frameCount;
788 goto EXIT_NOW;
789 }
790
791 /* can't report again - so loading as may as we can */
792 fi. loadAll = true;
793 for ( i = 0; i < INT_MAX; i++) {
794 fi. jointFrame = i > 0;
795 frameMap = fi. frame = i;
796 if ( !( c-> info-> IOFlags & IMG_LOAD_MULTIFRAME)) {
797 c-> vmt-> close_load( c, &fi);
798 if ( !( fi. instance = c-> vmt-> open_load( c, &fi))) {
799 ret = i;
800 goto EXIT_NOW;
801 }
802 }
803 if ( !c-> vmt-> load( c, &fi) || fi. frameCount >= 0) {
804 c-> vmt-> close_load( c, &fi);
805 ret = ( fi. frameCount < 0) ? i : fi. frameCount;
806 goto EXIT_NOW;
807 }
808 }
809
810 c-> vmt-> close_load( c, &fi);
811
812 EXIT_NOW:;
813 if ( fi. object)
814 Object_destroy( fi. object);
815 if ( fi. extras)
816 sv_free(( SV *) fi. extras);
817 if ( fi. frameProperties)
818 sv_free(( SV *) fi. frameProperties);
819 if ( fi. fileProperties)
820 sv_free(( SV *) fi. fileProperties);
821 if ( ioreq == NULL && fi.req != NULL && fi. req-> handle != NULL)
822 fclose(( FILE*) fi. req-> handle);
823 return ret;
824 }
825
826 int
apc_img_save(Handle self,char * fileName,Bool is_utf8,PImgIORequest ioreq,HV * profile,char * error)827 apc_img_save( Handle self, char * fileName, Bool is_utf8, PImgIORequest ioreq, HV * profile, char * error)
828 {
829 dPROFILE;
830 int i;
831 PImgCodec c = NULL;
832 ImgSaveFileInstance fi;
833 AV * images = NULL;
834 HV * def = NULL, * commonHV = NULL;
835 Bool err = false;
836 int codecID = -1;
837 int xself = self ? 1 : 0;
838 int ret = 0;
839 Bool autoConvert = true;
840 ImgIORequest sioreq;
841 int save_mask;
842 char dummy_error_buf[256];
843
844 #define out(x){ err = true;\
845 strncpy( fi.errbuf, x, 256);\
846 goto EXIT_NOW;}
847
848 #define outd(x,d){ err = true;\
849 snprintf( fi.errbuf, 256, x, d);\
850 goto EXIT_NOW;}
851
852 CHK;
853 memset( &fi, 0, sizeof( fi));
854
855 if ( pexist( append) && pget_B( append))
856 fi. append = true;
857
858 if ( pexist( autoConvert))
859 autoConvert = pget_B( autoConvert);
860
861 /* open file */
862 if ( fi. append && ioreq == NULL) {
863 FILE * f = ( FILE *) prima_open_file( fileName, is_utf8, "rb");
864 if ( !f)
865 fi. append = false;
866 else
867 fclose( f);
868 }
869
870 fi. errbuf = error ? error : dummy_error_buf;
871 if ( ioreq == NULL) {
872 memcpy( &sioreq, &std_ioreq, sizeof( sioreq));
873 if (( sioreq. handle = prima_open_file( fileName, is_utf8, fi. append ? "rb+" : "wb+" )) == NULL)
874 out( strerror( errno));
875 fi. req = &sioreq;
876 fi. req_is_stdio = true;
877 save_mask = IMG_SAVE_TO_FILE;
878 } else {
879 fi. req = ioreq;
880 fi. req_is_stdio = false;
881 save_mask = IMG_SAVE_TO_STREAM;
882 }
883
884 fi. fileName = fileName;
885 fi. is_utf8 = is_utf8;
886
887 fi. frameMapSize = xself;
888 if ( pexist( images)) {
889 SV * sv = pget_sv( images);
890 if ( SvOK( sv) && SvROK( sv) && SvTYPE( SvRV( sv)) == SVt_PVAV) {
891 images = ( AV *) SvRV( sv);
892 fi. frameMapSize += av_len( images) + 1;
893 } else
894 out("Not an array passed to 'images' property");
895 }
896 if ( fi. frameMapSize == 0)
897 out("Nothing to save");
898
899 /* fill array of objects */
900 if ( !( fi. frameMap = ( Handle *) malloc( sizeof( Handle) * fi. frameMapSize)))
901 out("Not enough memory");
902 memset( fi. frameMap, 0, sizeof( Handle) * fi. frameMapSize);
903
904 for ( i = 0; i < fi. frameMapSize; i++) {
905 Handle obj = NULL_HANDLE;
906
907 /* query profile */
908 if ( self && (i == 0)) {
909 obj = self;
910 if ( !kind_of( obj, CImage))
911 out("Not a Prima::Image descendant passed");
912 if ( PImage(obj)-> w == 0 || PImage(obj)-> h == 0)
913 out("Cannot save a null image");
914 } else if ( images) {
915 SV ** holder = av_fetch( images, i - xself, 0);
916 if ( !holder) outd("Array panic on 'images[%d]' property", i - xself);
917 obj = gimme_the_mate( *holder);
918 if ( !obj)
919 outd("Invalid object reference passed in 'images[%d]'", i - xself);
920 if ( !kind_of( obj, CImage))
921 outd("Not a Prima::Image descendant passed in 'images[%d]'", i - xself);
922 if ( PImage(obj)-> w == 0 || PImage(obj)-> h == 0)
923 out("Cannot save a null image");
924 } else
925 out("Logic error");
926 fi. frameMap[ i] = obj;
927 }
928
929 /* all other properties to be parsed by codec */
930 fi. extras = profile;
931
932 /* finding codec */
933 strcpy( fi.errbuf, "No appropriate codec found");
934 {
935 Bool * savemap = ( Bool*) malloc( sizeof( Bool) * imgCodecs. count);
936
937 if ( !savemap)
938 out("Not enough memory");
939 memset( savemap, 0, sizeof( Bool) * imgCodecs. count);
940
941 for ( i = 0; i < imgCodecs. count; i++) {
942 c = ( PImgCodec ) ( imgCodecs. items[ i]);
943 if ( !c-> instance)
944 c-> instance = c-> vmt-> init( &c->info, c-> initParam);
945 if ( !c-> instance) { /* failed to initialize, retry next time */
946 savemap[ i] = true;
947 continue;
948 }
949 }
950
951 /* checking 'codecID', if available */
952 {
953 SV * c = NULL;
954 if ( pexist( codecID))
955 c = pget_sv( codecID);
956 else if ( self &&
957 hv_exists(( HV*)SvRV((( PAnyObject) self)-> mate), "extras", 6)
958 ) {
959 SV ** sv = hv_fetch(( HV*)SvRV((( PAnyObject) self)-> mate), "extras", 6, 0);
960 if ( sv && SvOK( *sv) && SvROK( *sv) && SvTYPE( SvRV( *sv)) == SVt_PVHV) {
961 HV * profile = ( HV *) SvRV( *sv);
962 if ( pexist( codecID))
963 c = pget_sv( codecID);
964 }
965 }
966 if ( c && SvOK( c)) { /* accept undef */
967 codecID = SvIV( c);
968 if ( codecID < 0) codecID = imgCodecs. count - codecID;
969 }
970 }
971
972 /* find codec */
973 c = NULL;
974 if ( codecID >= 0) {
975 if ( codecID >= imgCodecs. count)
976 out("Codec index out of range");
977
978 c = ( PImgCodec ) ( imgCodecs. items[ codecID]);
979 if ( !( c-> info-> IOFlags & save_mask))
980 out( ioreq ?
981 "Codec cannot save images to streams" :
982 "Codec cannot save images");
983
984 if ( fi. frameMapSize > 1 &&
985 !( c-> info-> IOFlags & IMG_SAVE_MULTIFRAME))
986 out("Codec cannot save mutiframe images");
987 if ( fi. append &&
988 !( c-> info-> IOFlags & IMG_SAVE_APPEND))
989 out("Codec cannot append frames");
990
991 if (( fi. instance = c-> vmt-> open_save( c, &fi)) == NULL)
992 out("Codec cannot handle this file");
993
994 if ( !autoConvert) {
995 int j, *k = c-> info-> saveTypes, ok = 0;
996 for ( j = 0; j < fi. frameMapSize; j++) {
997 int type = PImage( fi. frameMap[j])-> type;
998 while ( *k) {
999 if ( type == *k) {
1000 ok = 1;
1001 break;
1002 }
1003 k++;
1004 }
1005 }
1006 if ( !ok)
1007 out("Image type(s) not supported by the codec specified");
1008 }
1009 }
1010
1011 if ( !c && fileName) {
1012 int fileNameLen = strlen( fileName);
1013 /* finding codec by extension */
1014 for ( i = 0; i < imgCodecs. count; i++) {
1015 int j = 0, found = false;
1016 if ( savemap[ i]) continue;
1017 c = ( PImgCodec ) ( imgCodecs. items[ i]);
1018 while ( c-> info-> fileExtensions[ j]) {
1019 char * ext = c-> info-> fileExtensions[ j];
1020 int extLen = strlen( ext);
1021 if ( extLen < fileNameLen && stricmp( fileName + fileNameLen - extLen, ext) == 0) {
1022 found = true;
1023 break;
1024 }
1025 j++;
1026 }
1027
1028 if ( found) {
1029 savemap[ i] = true;
1030 if ( !( c-> info-> IOFlags & save_mask)) {
1031 c = NULL;
1032 continue;
1033 }
1034
1035 if ( fi. frameMapSize > 1
1036 && !( c-> info-> IOFlags & IMG_SAVE_MULTIFRAME)) {
1037 c = NULL;
1038 continue;
1039 }
1040 if ( fi. append
1041 && !( c-> info-> IOFlags & IMG_SAVE_APPEND)) {
1042 c = NULL;
1043 continue;
1044 }
1045
1046 if ( !autoConvert) {
1047 int j, *k = c-> info-> saveTypes, ok = 0;
1048 for ( j = 0; j < fi. frameMapSize; j++) {
1049 int type = PImage( fi. frameMap[j])-> type;
1050 while ( *k) {
1051 if ( type == *k) {
1052 ok = 1;
1053 break;
1054 }
1055 k++;
1056 }
1057 }
1058 if ( !ok) {
1059 c = NULL;
1060 continue;
1061 }
1062 }
1063
1064 if (( fi. instance = c-> vmt-> open_save( c, &fi)) != NULL)
1065 break;
1066 }
1067 c = NULL;
1068 }
1069 }
1070
1071 free( savemap);
1072 if ( !c) { /* use pre-formatted error string */
1073 err = true;
1074 goto EXIT_NOW;
1075 }
1076 }
1077
1078 snprintf( fi.errbuf, 256, "Error saving %s", fileName ? fileName : "to stream");
1079
1080 /* use common profile */
1081 def = c-> vmt-> save_defaults( c);
1082 commonHV = newHV();
1083 if ( profile) {
1084 c-> vmt-> save_check_in( c, commonHV, profile);
1085 apc_img_profile_add( commonHV, profile, def);
1086 }
1087
1088 /* saving */
1089 for ( i = 0; i < fi. frameMapSize; i++) {
1090 HV * profile = commonHV;
1091 PImage im;
1092
1093 im = ( PImage) fi. frameMap[ i];
1094 if ( hv_exists(( HV*)SvRV( im-> mate), "extras", 6)) {
1095 SV ** sv = hv_fetch(( HV*)SvRV( im-> mate), "extras", 6, 0);
1096 if ( sv && SvOK( *sv) && SvROK( *sv) && SvTYPE( SvRV( *sv)) == SVt_PVHV) {
1097 HV * hv = ( HV *) SvRV( *sv);
1098 profile = newHV();
1099 apc_img_profile_add( profile, commonHV, commonHV);
1100 c-> vmt-> save_check_in( c, profile, hv);
1101 apc_img_profile_add( profile, hv, def);
1102 }
1103 }
1104
1105 fi. frame = i;
1106 fi. object = fi. frameMap[ i];
1107 fi. objectExtras = profile;
1108
1109 /* converting image to format with maximum bit depth and category flags match */
1110 if ( autoConvert) {
1111 int *k = c-> info-> saveTypes;
1112 int max = *k & imBPP, best = *k, supported = false;
1113 int flags = im-> type & imCategory, bestflags = *k & imCategory, bestmatch;
1114 #define dBITS(a) int i = 0x80, match = ( flags & (a)) >> 8
1115 #define CALCBITS(x) { \
1116 x = 0;\
1117 while ( i >>= 1 ) if ( match & i ) x++; \
1118 }
1119 {
1120 dBITS( bestflags );
1121 CALCBITS( bestmatch )
1122 }
1123 while ( *k) {
1124 if ( im-> type == *k) {
1125 supported = true;
1126 break;
1127 }
1128 if ( max < ( *k & imBPP)) {
1129 dBITS( bestflags = ( *k & imCategory));
1130 max = *k & imBPP;
1131 best = *k;
1132 CALCBITS( bestmatch );
1133 } else if ( max == ( *k & imBPP)) {
1134 dBITS( *k );
1135 int testmatch;
1136 CALCBITS( testmatch );
1137 if ( testmatch > bestmatch ) {
1138 best = *k;
1139 bestflags = *k & imCategory;
1140 bestmatch = testmatch;
1141 }
1142 }
1143 k++;
1144 }
1145 if ( !supported) {
1146 im-> self-> set_type(( Handle) im, best);
1147 if ( best != im-> type) outd("Failed converting image to type '%04x'", best);
1148 }
1149 }
1150
1151 /* saving image */
1152 if ( !c-> vmt-> save( c, &fi)) {
1153 c-> vmt-> close_save( c, &fi);
1154 if ( fi. objectExtras != commonHV) sv_free(( SV *) fi. objectExtras);
1155 err = true;
1156 goto EXIT_NOW;
1157 }
1158
1159 if ( fi. objectExtras != commonHV) sv_free(( SV *) fi. objectExtras);
1160 ret++;
1161 }
1162
1163 c-> vmt-> close_save( c, &fi);
1164
1165 EXIT_NOW:;
1166 free( fi. frameMap);
1167 if ( ioreq == NULL && fi. req != NULL && fi. req-> handle != NULL)
1168 fclose(( FILE*) fi. req-> handle);
1169 if ( err && fileName)
1170 apc_fs_unlink( fileName, is_utf8 );
1171 if ( def)
1172 sv_free(( SV *) def);
1173 if ( commonHV)
1174 sv_free(( SV *) commonHV);
1175 return err ? -ret : ret;
1176 #undef out
1177 #undef outd
1178 }
1179 void
apc_img_codecs(PList ret)1180 apc_img_codecs( PList ret)
1181 {
1182 int i;
1183 PImgCodec c;
1184
1185 CHK;
1186 for ( i = 0; i < imgCodecs. count; i++) {
1187 c = ( PImgCodec ) ( imgCodecs. items[ i]);
1188 if ( !c-> instance)
1189 c-> instance = c-> vmt-> init( &c->info, c-> initParam);
1190 if ( !c-> instance) /* failed to initialize, retry next time */
1191 continue;
1192 list_add( ret, ( Handle) c);
1193 }
1194 }
1195
1196 int
apc_img_read_palette(PRGBColor palBuf,SV * palette,Bool triplets)1197 apc_img_read_palette( PRGBColor palBuf, SV * palette, Bool triplets)
1198 {
1199 AV * av;
1200 int i, count;
1201 Byte buf[768];
1202
1203 if ( !SvROK( palette) || ( SvTYPE( SvRV( palette)) != SVt_PVAV))
1204 return 0;
1205 av = (AV *) SvRV( palette);
1206 count = av_len( av) + 1;
1207
1208 if ( triplets) {
1209 if ( count > 768) count = 768;
1210 count -= count % 3;
1211
1212 for ( i = 0; i < count; i++)
1213 {
1214 SV **itemHolder = av_fetch( av, i, 0);
1215 if ( itemHolder == NULL) return 0;
1216 buf[ i] = SvIV( *itemHolder);
1217 }
1218 memcpy( palBuf, buf, count);
1219 return count/3;
1220 } else {
1221 int j;
1222 if ( count > 256) count = 256;
1223
1224 for ( i = 0, j = 0; i < count; i++)
1225 {
1226 Color c;
1227 SV **itemHolder = av_fetch( av, i, 0);
1228 if ( itemHolder == NULL) return 0;
1229 c = (Color)(SvIV( *itemHolder));
1230 buf[j++] = c & 0xFF;
1231 buf[j++] = (c >> 8) & 0xFF;
1232 buf[j++] = (c >> 16) & 0xFF;
1233 }
1234 memcpy( palBuf, buf, j);
1235 return count;
1236 }
1237 }
1238
1239
fill_plist(char * key,char ** list,HV * profile)1240 static AV * fill_plist( char * key, char ** list, HV * profile)
1241 {
1242 AV * av = newAV();
1243 if ( !list) list = imgPVEmptySet;
1244 while ( *list) {
1245 av_push( av, newSVpv( *list, 0));
1246 list++;
1247 }
1248 (void) hv_store( profile, key, strlen( key), newRV_noinc(( SV *) av), 0);
1249 return av;
1250 }
1251
fill_ilist(char * key,int * list,HV * profile)1252 static void fill_ilist( char * key, int * list, HV * profile)
1253 {
1254 AV * av = newAV();
1255 if ( !list) list = imgIVEmptySet;
1256 while ( *list) {
1257 av_push( av, newSViv( *list));
1258 list++;
1259 }
1260 (void) hv_store( profile, key, strlen( key), newRV_noinc(( SV *) av), 0);
1261 }
1262
1263
1264 HV *
apc_img_info2hash(PImgCodec codec)1265 apc_img_info2hash( PImgCodec codec)
1266 {
1267 HV * profile, * hv;
1268 AV * av;
1269 PImgCodecInfo c;
1270
1271 CHK;
1272 profile = newHV();
1273 if ( !codec) return profile;
1274
1275 if ( !codec-> instance)
1276 codec-> instance = codec-> vmt-> init( &codec->info, codec-> initParam);
1277 if ( !codec-> instance)
1278 return profile;
1279 c = codec-> info;
1280
1281 pset_c( name, c-> name);
1282 pset_c( vendor, c-> vendor);
1283 pset_i( versionMajor, c-> versionMaj);
1284 pset_i( versionMinor, c-> versionMin);
1285 fill_plist( "fileExtensions", c-> fileExtensions, profile);
1286 pset_c( fileType, c-> fileType);
1287 pset_c( fileShortType, c-> fileShortType);
1288 fill_plist( "featuresSupported", c-> featuresSupported, profile);
1289 pset_c( module, c-> primaModule);
1290 pset_c( package, c-> primaPackage);
1291 pset_i( canLoad, c-> IOFlags & IMG_LOAD_FROM_FILE);
1292 pset_i( canLoadStream , c-> IOFlags & IMG_LOAD_FROM_STREAM);
1293 pset_i( canLoadMultiple, c-> IOFlags & IMG_LOAD_MULTIFRAME);
1294 pset_i( canSave , c-> IOFlags & IMG_SAVE_TO_FILE);
1295 pset_i( canSaveStream , c-> IOFlags & IMG_SAVE_TO_STREAM);
1296 pset_i( canSaveMultiple, c-> IOFlags & IMG_SAVE_MULTIFRAME);
1297 pset_i( canAppend, c-> IOFlags & IMG_SAVE_APPEND);
1298
1299 fill_ilist( "types", c-> saveTypes, profile);
1300
1301 if ( c-> IOFlags & ( IMG_LOAD_FROM_FILE|IMG_LOAD_FROM_STREAM)) {
1302 hv = codec-> vmt-> load_defaults( codec);
1303 if ( c-> IOFlags & IMG_LOAD_MULTIFRAME) {
1304 (void) hv_store( hv, "index", 5, newSViv(0), 0);
1305 (void) hv_store( hv, "map", 3, newSVsv(NULL_SV), 0);
1306 (void) hv_store( hv, "loadAll", 7, newSViv(0), 0);
1307 (void) hv_store( hv, "wantFrames", 10, newSViv(0), 0);
1308 }
1309 (void) hv_store( hv, "loadExtras", 10, newSViv(0), 0);
1310 (void) hv_store( hv, "noImageData", 11, newSViv(0), 0);
1311 (void) hv_store( hv, "iconUnmask", 10, newSViv(0), 0);
1312 (void) hv_store( hv, "blending", 8, newSViv(0), 0);
1313 (void) hv_store( hv, "noIncomplete", 12, newSViv(0), 0);
1314 (void) hv_store( hv, "className", 9, newSVpv("Prima::Image", 0), 0);
1315 } else
1316 hv = newHV();
1317 pset_sv_noinc( loadInput, newRV_noinc(( SV *) hv));
1318
1319 av = fill_plist( "loadOutput", c-> loadOutput, profile);
1320 if ( c-> IOFlags & ( IMG_LOAD_FROM_FILE|IMG_LOAD_FROM_STREAM)) {
1321 if ( c-> IOFlags & IMG_LOAD_MULTIFRAME)
1322 av_push( av, newSVpv( "frames", 0));
1323 av_push( av, newSVpv( "height", 0));
1324 av_push( av, newSVpv( "width", 0));
1325 av_push( av, newSVpv( "codecID", 0));
1326 av_push( av, newSVpv( "truncated", 0));
1327 }
1328
1329 if ( c-> IOFlags & ( IMG_SAVE_TO_FILE|IMG_SAVE_TO_STREAM)) {
1330 hv = codec-> vmt-> save_defaults( codec);
1331 if ( c-> IOFlags & IMG_SAVE_MULTIFRAME)
1332 (void) hv_store( hv, "append", 6, newSViv(0), 0);
1333 (void) hv_store( hv, "autoConvert", 11, newSViv(1), 0);
1334 (void) hv_store( hv, "codecID", 7, newSVsv( NULL_SV), 0);
1335 } else
1336 hv = newHV();
1337 pset_sv_noinc( saveInput, newRV_noinc(( SV *) hv));
1338
1339 fill_plist( "mime", c-> mime, profile);
1340
1341 return profile;
1342 }
1343
1344 char * imgPVEmptySet[] = { NULL };
1345 int imgIVEmptySet[] = { 0 };
1346
1347 void
apc_img_notify_header_ready(PImgLoadFileInstance fi)1348 apc_img_notify_header_ready( PImgLoadFileInstance fi)
1349 {
1350 Event e = { cmImageHeaderReady };
1351 e. gen. p = fi-> frameProperties;
1352 CImage( fi-> object)-> message( fi-> object, &e);
1353 }
1354
1355 void
apc_img_notify_scanlines_ready(PImgLoadFileInstance fi,int scanlines,int direction)1356 apc_img_notify_scanlines_ready( PImgLoadFileInstance fi, int scanlines, int direction)
1357 {
1358 Event e;
1359 int height, width;
1360 unsigned int dt;
1361 struct timeval t;
1362
1363 fi-> lastCachedScanline += scanlines;
1364 gettimeofday( &t, NULL);
1365 dt =
1366 t.tv_sec * 1000 + t.tv_usec / 1000 -
1367 fi-> lastEventTime.tv_sec * 1000 - fi-> lastEventTime.tv_usec / 1000;
1368
1369 if ( dt < fi-> eventDelay) return;
1370 if ( fi-> lastEventScanline == fi-> lastCachedScanline) return;
1371
1372 e. cmd = cmImageDataReady;
1373 height = PImage( fi-> object)-> h;
1374 width = PImage( fi-> object)-> w;
1375
1376 switch ( direction ) {
1377 case SCANLINES_DIR_TOP_TO_BOTTOM:
1378 e. gen. R. left = 0;
1379 e. gen. R. right = width - 1;
1380 e. gen. R. bottom = height - fi-> lastCachedScanline;
1381 e. gen. R. top = height - fi-> lastEventScanline - 1;
1382 break;
1383 case SCANLINES_DIR_BOTTOM_TO_TOP:
1384 e. gen. R. left = 0;
1385 e. gen. R. right = width - 1;
1386 e. gen. R. bottom = fi-> lastEventScanline;
1387 e. gen. R. top = fi-> lastCachedScanline - 1;
1388 break;
1389 case SCANLINES_DIR_LEFT_TO_RIGHT:
1390 e. gen. R. left = fi-> lastEventScanline;
1391 e. gen. R. right = fi-> lastCachedScanline - 1;
1392 e. gen. R. bottom = 0;
1393 e. gen. R. top = height - 1;
1394 break;
1395 case SCANLINES_DIR_RIGHT_TO_LEFT:
1396 e. gen. R. left = width - fi-> lastCachedScanline;
1397 e. gen. R. right = width - fi-> lastEventScanline - 1;
1398 e. gen. R. bottom = 0;
1399 e. gen. R. top = height - 1;
1400 break;
1401 }
1402 CImage( fi-> object)-> message( fi-> object, &e);
1403
1404 gettimeofday( &fi-> lastEventTime, NULL);
1405 fi-> lastEventScanline = fi-> lastCachedScanline;
1406 }
1407 #ifdef __cplusplus
1408 }
1409 #endif
1410