3 // SCImage primitive set for SuperCollider3
6 // charles picasso 2008
10 //#if SCIMAGE_MAC_OS_10_4
16 #import <objc/objc-class.h>
21 #import "PyrPrimitive.h"
27 #import "SCVirtualMachine.h"
34 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4)
35 #define class_getSuperclass(a) ((a)->super_class)
36 #define class_getName(a) ((a)->name)
37 typedef float ColorData
;
39 typedef CGFloat ColorData
;
42 extern int slotGetPoint(PyrSlot
* a
, NSPoint
*p
);
43 extern int slotGetNSRect(PyrSlot
* a
, NSRect
*r
);
44 extern int allocSlotStrVal(PyrSlot
*slot
, char **str
);
45 extern int slotColorVal(PyrSlot
*slot
, SCColor
*sccolor
);
46 extern int slotStrLen(PyrSlot
* slot
);
48 extern pthread_mutex_t gLangMutex
; // in case
50 PyrSymbol
*s_scfilter
;
51 PyrSymbol
*s_scimagekernel
;
52 static BOOL gCIFilterPlugInsLoaded
= NO
; //
54 CGRect
OutsetRect(CGRect r
, const float dx
, const float dy
);
57 * SCImage Finalizer callback function
59 int FinalizeSCImageObject(struct VMGlobals
* g
, struct PyrObject
* object
)
61 if( !IsNil(object
->slots
+0) ) {
62 SCImage
* scimage
= (SCImage
*)slotRawPtr(object
->slots
);
64 post("finalize scimage (%p), dataptr (%p)\n", object
, scimage
);
67 SetNil(object
->slots
+0);
73 * SCImageKernel Finalizer callback function
75 int FinalizeSCImageKernelObject(struct VMGlobals
* g
, struct PyrObject
* object
)
77 if( !IsNil(object
->slots
+4) ) {
78 CIKernel
* kernel
= (CIKernel
*)slotRawPtr(&object
->slots
[4]);
80 post("finalize scimagekernel (%p), dataptr (%p)\n", object
, kernel
);
83 SetNil(object
->slots
+4);
88 /* This function should be the one to use to create a new PyrObject of class s_scimage
89 * it will setup directly the Finalizer object
90 * so the PyrObject will free directly the SCImage instance
91 * Not calling this function in any other situation may result in a memory leak.
93 PyrObject
* newPyrSCImage(VMGlobals
* g
)
95 PyrObject
* object
= instantiateObject(g
->gc
, s_scimage
->u.classobj
, 0, false, true);
97 InstallFinalizer(g
, object
, 9, FinalizeSCImageObject
);
101 inline NSString
* nsStringFromSlot(PyrSlot
*slot
)
106 len
= slotStrLen(slot
); // check if Symbol or String
107 if(len
== -1) // returns -1 if failure
110 nsString
= [[NSString alloc
]initWithBytes
:IsSym(slot
) ?
(void*)slotRawSymbol(slot
)->name
: (void*)slotRawString(slot
)->s length
:len encoding
:NSASCIIStringEncoding
];
112 return [nsString autorelease
];
115 //==================================================================================================
116 // SCImage uses now two models: NSBitmapImageRep + CIImage underneath
118 // Concerning NSBitmapImageRep
119 // ---------------------------
120 // (+) advantages : Quartz compliant - pixel access + manipulation via simple setters
121 // although NSBitmapImageRep does handle only pre-multiplied alpha pixels
122 // NSAlphaNonpremultipliedBitmapFormat does not work in 10.5 so not portable for now...
124 // Concerning CIImage
125 // ------------------
126 // (-) drawbacks : no direct pixel manipulation like the nsbitmapimagerep (wich is anyway a not very good model for that too...
127 // a CGImage should be better
128 // we may need also to download _from_ gpu memory to get the nsbitmapimagerep if CoreImage uses acceleration
129 // (+) advantages : can be in gpu memory
130 // possibility to use the CoreImage possibilities : Filters...ect...
131 //==================================================================================================
133 // Getting Pixel Macro -
134 // handle different conversions but there is roundoff errors... so
135 // integer division -> better seems to be the MultiplyAlpha
136 // change COLOR_SCALE macro to point to another function for a _forward_ alpha premultiplication
137 // change COLOR_UNSCALE macro to point to another function for a _reverse_ alpha premultiplication
138 // better to use getPixel:AtX:y because it handles the unscale really better
140 #pragma mark -- Pixel Macros
143 static const float oneOn255
= (1.f
/255.f
);
146 // Get Rid of signed integer interpretation in sc - kill the 2-complement info
147 #define PIXEL_RED(pixel) ((pixel >> 24) & 0x000000FF)
148 #define PIXEL_GREEN(pixel) ((pixel >> 16) & 0x000000FF)
149 #define PIXEL_BLUE(pixel) ((pixel >> 8) & 0x000000FF)
150 #define PIXEL_ALPHA(pixel) (pixel & 0x000000FF)
152 // Setting Pixel Macro
153 #define SET_PIXEL_RED(pixel, value) pixel = (pixel & 0x00FFFFFF) | ((value) << 24)
154 #define SET_PIXEL_GREEN(pixel, value) pixel = (pixel & 0xFF00FFFF) | ((value) << 16)
155 #define SET_PIXEL_BLUE(pixel, value) pixel = (pixel & 0xFFFF00FF) | ((value) << 8)
156 #define SET_PIXEL_ALPHA(pixel, value) pixel = (pixel & 0xFFFFFF00) | (value)
158 // Macro for working with premultiplied alpha data
159 // May introduce several roundoff errors if several convert - unconvert passes so... careful with that...
160 #define COLOR_SCALE COLOR_SCALE2
161 #define COLOR_SCALE1(channel, alpha) (((channel) * (alpha)) + 127) / 255 // simple
162 #define COLOR_SCALE2(channel, alpha) MultiplyAlpha(alpha, channel)
164 // none of those are ok :(
165 #define COLOR_UNSCALE COLOR_UNSCALE3
166 #define COLOR_UNSCALE1(channel, alpha) ((channel) * 255) / alpha // simple Formula - rounding errors if scale - unscale !!! so...
167 #define COLOR_UNSCALE2(channel, alpha) ((channel) * 256 - 1) / (alpha) // ...modified one... beware
168 #define COLOR_UNSCALE3(channel, alpha) ((((channel) * 255) + ((alpha) >> 1)) / (alpha)) // should be better - from libnr - sodipodi
170 // more Macros see libnr - sodipodi here:
171 // http://sodipodi.cvs.sourceforge.net/sodipodi/libnr/nr-pixops.h
172 // but currently none handles de-premultiplication better than the getPixel method
175 static inline int MultiplyAlpha(const int a
, const int r
)
178 temp
= (r
* a
) + 0x80;
179 return ((temp
+ (temp
>> 8)) >> 8);
182 #pragma mark -- Graphics Context Utilities
183 // returns a new rgba bitmap context. you owns the returned context. should be released after
184 NSBitmapImageRep
* CreateBitmapContextRGBA(const int width
, const int height
)
187 [[NSBitmapImageRep alloc
]
188 initWithBitmapDataPlanes
:NULL
195 colorSpaceName
:NSCalibratedRGBColorSpace
//may be NSDeviceRGBColorSpace is faster since it matches hardware properties
196 // bitmapFormat: NSAlphaNonpremultipliedBitmapFormat // better for pixel manipulation - does not work on 10.5
197 // bitmapFormat: NSAlphaFirstBitmapFormat
198 bytesPerRow
:/*(width * height * 4)*/ 0 // calc word alignment - faster
199 bitsPerPixel
:0 // guess it for me ;-)
203 // creates and return an autoreleased NSBitmapImageRep built from an CIImage or an NSImage
204 // if image is nil then it will return a zero filled pixel NSBitmapImageRep
205 NSBitmapImageRep
* BitmapContextRGBAWithImage(const int width
, const int height
, id image
)
207 NSGraphicsContext
*nsPrevCtx
= NULL
;
208 NSBitmapImageRep
*bitmap
= CreateBitmapContextRGBA(width
, height
);
210 NSLog(@
"Error: CreateBitmapContextRGBAWithImage Failed creating valid RGBA Bitmap context");
216 [NSGraphicsContext saveGraphicsState
];
218 NSGraphicsContext
*nsCtx
=
219 [NSGraphicsContext graphicsContextWithBitmapImageRep
:bitmap
];
222 NSLog(@
"Error: CreateBitmapContextRGBAWithImage Failed creating valid NSGraphicsContext with RGBA Bitmap Attributes");
227 [NSGraphicsContext setCurrentContext
:nsCtx
]; // set the RGBA ctx
229 if([image isKindOfClass
:[NSImage
class]]) {
230 if([image isValid
]) {
231 [image drawAtPoint
:NSZeroPoint fromRect
:NSZeroRect operation
:NSCompositeCopy fraction
:1.0]; // draw inside of it
234 NSLog(@
"Error: invalid image supplied as input to the bitmap context");
238 else if([image isKindOfClass
:[CIImage
class]]) {
239 CGRect extent
= [image extent
];
240 extent.origin
= (CGPoint
){0.f
, 0.f
};
241 [ [nsCtx CIContext
] drawImage
:image inRect
:CGRectMake(0.f
, 0.f
, (float)width
, (float)height
) fromRect
:extent
];
244 NSLog(@
"Error: Invalid class supplied as input to bitmap context !");
248 [NSGraphicsContext restoreGraphicsState
];
252 memset([bitmap bitmapData
], 0, [bitmap bytesPerRow
]*[bitmap pixelsHigh
]); // better to clear everything
255 return [bitmap autorelease
];
259 if(nsPrevCtx
) [NSGraphicsContext setCurrentContext
:nsPrevCtx
]; // restore previous ctx
263 #pragma mark -- SCImage Class
265 @implementation SCImage
267 -(id)initWithCIImage
:(CIImage
*)image extent
:(CGRect
)extent format
:(CIFormat
)imageFormat
272 _ciFormat
= imageFormat
;
274 #if SCIMAGE_MAC_OS_10_5
275 _ciimageStore
= [[CIImageAccumulator allocWithZone
:[self zone
]]initWithExtent
:extent format
:_ciFormat
];
277 NSLog(@
"SCImage initWithContentsOfURL failed creating valid CIImageAccumulator !");
280 [_ciimageStore setImage
:image
];
282 // extent and format cannot be choosen
283 _ciimage
= [image retain
];
286 [self setShouldSyncBitmap
:YES
];
290 #if SCIMAGE_MAC_OS_10_5
297 -(id)initWithNSImage
:(NSImage
*)image
{
300 // TODO: clean up the initFromURL method...ect... to use this method instead
305 NSImage seems to have an incorrect size depending on the dpi of the image
306 find the largest representation in the nsimage and the set the size according to it
308 int pixelsHigh
=0, pixelsWide
=0; // should be NSInteger in 10.5 - but stick with an <int> for now
310 NSEnumerator
*e
= [[image representations
]objectEnumerator
];
311 while( (irep
= [e nextObject
]) ) {
313 do not check ratio - they should be always preserved - just take the max
314 they should always be part of the same rep
316 pixelsHigh
= sc_max([irep pixelsHigh
], pixelsHigh
);
317 pixelsWide
= sc_max([irep pixelsWide
], pixelsWide
);
320 if( size.width
< (float)pixelsWide || size.height
< (float)pixelsHigh
) {
321 //post("converting : %f %f -> %i %i\n", size.width, size.height, pixelsWide, pixelsHigh);
322 [image setSize
:NSMakeSize((float)pixelsWide
, (float)pixelsHigh
)];
326 _bitmap
= BitmapContextRGBAWithImage([image size
].width
, [image size
].height
, image
);
330 [self rebuildNSImageFromBitmapRep
];
334 [self setShouldSyncCIImage
:YES
];
344 -(id)initWithSize
:(NSSize
)size isAccelerated
:(BOOL)yorn format
:(CIFormat
)imageFormat
348 _bitmap
= BitmapContextRGBAWithImage((int)size.width
, (int)size.height
, nil);
352 [self rebuildNSImageFromBitmapRep
];
355 [self rebuildCIImageFromBitmapRep
];
362 [self setShouldSyncCIImage
:YES
];
373 return [[SCImage alloc
]initWithNSImage
:[self nsimage
]]; // perform a full pixel copy
376 -(id)initWithContentsOfURL
:(NSURL
*)url isAccelerated
:(BOOL)yorn format
:(CIFormat
)imageFormat
380 _ciFormat
= imageFormat
;
384 CIImage
*ciimage
= [[CIImage alloc
] initWithContentsOfURL
:url options
:[NSDictionary dictionaryWithObjectsAndKeys
: [NSNumber numberWithInt
:_ciFormat
], @
"CIFormat"]];
385 #if SCIMAGE_MAC_OS_10_5
386 _ciimageStore
= [[CIImageAccumulator allocWithZone
:[self zone
]]initWithExtent
:[ciimage extent
] format
:_ciFormat
];
388 NSLog(@
"SCImage initWithContentsOfURL failed creating valid CIImageAccumulator !");
392 [_ciimageStore setImage
:ciimage
];
394 _ciimage
= [ciimage retain
];
399 NSImage
*nsimage
= [[NSImage alloc
] initWithContentsOfURL
:url
];
404 size
= [nsimage size
];
407 NSImage seems to have an incorrect size depending on the dpi of the image
408 find the largest representation in the nsimage and the set the size according to it
410 int pixelsHigh
=0, pixelsWide
=0; // should be NSInteger in 10.5 - but stick with an <int> for 10.4
412 NSEnumerator
*e
= [[nsimage representations
]objectEnumerator
];
413 while( (irep
= [e nextObject
]) ) {
415 do not check ratio - they should be always preserved - just take the max
416 they should always be part of the same rep
418 pixelsHigh
= sc_max([irep pixelsHigh
], pixelsHigh
);
419 pixelsWide
= sc_max([irep pixelsWide
], pixelsWide
);
422 if( size.width
< (float)pixelsWide || size.height
< (float)pixelsHigh
) {
423 //post("converting : %f %f -> %i %i\n", size.width, size.height, pixelsWide, pixelsHigh);
424 [nsimage setSize
:NSMakeSize((float)pixelsWide
, (float)pixelsHigh
)];
425 size
= [nsimage size
];
428 _bitmap
= BitmapContextRGBAWithImage( (int)size.width
, (int)size.height
, nsimage
);
440 [self setShouldSyncBitmap
:YES
];
442 [self setShouldSyncCIImage
:YES
];
452 // Common initializer for both models
456 _bitmapSynced
= _ciimageSynced
= YES
;
457 _interpolation
= NSImageInterpolationDefault
;
459 #if SCIMAGE_MAC_OS_10_5
460 _ciimageStore
= nil;// CAREFUL: may lead to error / crash if commonInit is called after previous _ciimageStore initialization
462 _ciimage
= nil;// CAREFUL: may lead to error / crash if commonInit is called after previous _ciimage initialization
464 _wLock
= [[NSLock alloc
]init
];
467 _hints
= (SCImageHint
)1; // do not optimize drawing when using non-accelerated model - hence using filter will do nothing
468 _inited
= YES
; // initialization flag
472 - (void)setDrawingHint
:(SCImageHint
)hint
476 -(void)setScalesWhenResized
:(BOOL)yorn
479 [[self nsimage
]setScalesWhenResized
:yorn
]; // test for now
481 -(BOOL)scalesWhenResized
485 -(void)setSize
:(NSSize
)s
487 if([self size
].width
!= s.width ||
[self size
].height
!= s.height
)
489 [self lock
]; // in case
492 NSLog(@
"Resizing Image %f %f", s.width
, s.height
);
495 BOOL scales
= [self scalesWhenResized
];
497 NSBitmapImageRep
*new_bitmap
= CreateBitmapContextRGBA(s.width
, s.height
);
498 // NSGraphicsContext* prevctx = [NSGraphicsContext currentContext];
500 [NSGraphicsContext saveGraphicsState
];
502 NSGraphicsContext
*nctx
=
504 NSGraphicsContext graphicsContextWithAttributes
:
505 [NSDictionary dictionaryWithObject
:new_bitmap forKey
:NSGraphicsContextDestinationAttributeName
]
506 ]; // create new RGBA ctx with bitmap as destination
508 [NSGraphicsContext setCurrentContext
:nctx
];
509 if([self isAccelerated
])
512 [[nctx CIContext
]drawImage
:[self ciimage
] inRect
:CGRectMake(0.f
, 0.f
, s.width
, s.height
) fromRect
:[self extent
]];
514 [[nctx CIContext
]drawImage
:[self ciimage
] atPoint
:CGPointMake(0.f
, 0.f
) fromRect
:[self extent
]];
519 [_bitmap drawInRect
:NSMakeRect(0.f
, 0.f
, s.width
, s.height
)];
521 [_bitmap drawAtPoint
:NSMakePoint(0.f
, 0.f
)];
523 // [NSGraphicsContext setCurrentContext:prevctx];
524 [NSGraphicsContext restoreGraphicsState
];
527 _bitmap
= [new_bitmap retain
];
529 [self rebuildNSImageFromBitmapRep
];
531 if([self isAccelerated
])
532 [self rebuildCIImageFromBitmapRep
];
534 _ciimageSynced
= _bitmapSynced
= YES
; // everybody's synced
539 -(void)setAccelerated
:(BOOL)yorn
541 if(yorn
!= _accelerated
) {
542 [self syncRepresentations
]; // sync representations
552 return (_bitmapSynced
&& _ciimageSynced
);
557 [self rebuildNSImageFromBitmapRep
]; // in case
563 #if SCIMAGE_MAC_OS_10_5
564 if(!_ciimageStore
&& _bitmap
)
565 [self rebuildCIImageFromBitmapRep
];
566 return [_ciimageStore image
];
568 if(!_ciimage
&& _bitmap
)
569 [self rebuildCIImageFromBitmapRep
];
574 -(NSBitmapImageRep
*)bitmapRepresentation
576 #if SCIMAGE_MAC_OS_10_5
577 if(!_bitmap
&& _ciimageStore
)
579 if(!_bitmap
&& _ciimage
)
581 [self rebuildBitmapRepFromCIImage
];// in case
585 -(void)rebuildNSImageFromBitmapRep
588 NSLog(@
"Error: SCImage rebuildCIImageFromBitmapRep: No valuable Bitmap Context to rebuild the CIImage");
596 _nsimage
= [[NSImage alloc
]initWithSize
:NSMakeSize([_bitmap pixelsWide
], [_bitmap pixelsHigh
])]; // simple store
597 [_nsimage addRepresentation
:_bitmap
];
600 NSLog(@
"SCImage (%p) Recaching NSImage (%p) from BitmapRep (%p)", self, _nsimage
, _bitmap
);
603 -(void)rebuildCIImageFromBitmapRep
606 NSLog(@
"Error: SCImage rebuildCIImageFromBitmapRep: No valuable Bitmap Context to rebuild the CIImage");
610 #if SCIMAGE_MAC_OS_10_5
612 [_ciimageStore release
];
614 CIImage
* _ciimage
= [[CIImage alloc
]initWithBitmapImageRep
:[self bitmapRepresentation
]];
615 _ciimageStore
= [[CIImageAccumulator allocWithZone
:[self zone
]]initWithExtent
:[_ciimage extent
] format
:_ciFormat
];
618 [_ciimageStore setImage
:[_ciimage autorelease
]];
621 NSLog(@
"Error: SCImage (%p) Failed Creating valid CIImageAccumulator");
624 _ciimage
= [[CIImage alloc
]initWithBitmapImageRep
:[self bitmapRepresentation
]];
628 NSLog(@
"SCImage (%p) Recaching CIImage (%p) from BitmapRep (%p)", self, _ciimage
, _bitmap
);
631 -(void)rebuildBitmapRepFromCIImage
633 // rebuild a BitmapContext from the CIImage
634 // expensive since it may reload it from the GPU.
635 // only if - user wants to manipulate pixels after using filter
636 // - user wants to save data in file
641 CIImage
*ciimage
= [self ciimage
];
642 CGRect extent
= [ciimage extent
];
643 _bitmap
= BitmapContextRGBAWithImage((int)extent.size.width
, (int)extent.size.height
, ciimage
); // create a context from CIImage
644 [_bitmap retain
]; // retain it since it is an autoreleased one
646 NSLog(@
"SCImage (%p) Recaching NSBitmapImageRep (%p) from CIImage (%p)", self, _bitmap
, ciimage
);
652 // currently does nothing
655 - (NSImageInterpolation
)imageInterpolation
657 return _interpolation
;
660 - (void)setImageInterpolation
:(NSImageInterpolation
)interp
663 NSLog(@
"SCImage (%p) setImageInterpolation: %i", self, interp
);
665 _interpolation
= interp
;
668 // update all representations from the current used rep
669 -(void)syncRepresentations
674 if([self isAccelerated
]) {
684 NSLog(@
"SCImage (%p) syncBitmap", self);
686 [self rebuildBitmapRepFromCIImage
];
687 [self rebuildNSImageFromBitmapRep
];
693 if(!_ciimageSynced
) {
695 NSLog(@
"SCImage (%p) syncCIImage", self);
697 [self rebuildCIImageFromBitmapRep
];
698 _ciimageSynced
= YES
;
703 return (![self isSynced
] ||
(_cache
== NULL
));
706 -(void)setShouldSyncCIImage
:(BOOL)yorn
{
707 _ciimageSynced
= !yorn
;
710 -(void)setShouldSyncBitmap
:(BOOL)yorn
{
711 _bitmapSynced
= !yorn
;
716 return (int)[self size
].width
;
721 return (int)[self size
].height
;
725 return [self isAccelerated
] ?
[[self ciimage
]extent
] : CGRectMake(0.f
, 0.f
, (float)[_bitmap pixelsWide
], (float)[_bitmap pixelsHigh
]);
729 if([self isAccelerated
]) {
730 CGSize s
= [[self ciimage
]extent
].size
;
731 return NSMakeSize(s.width
, s.height
);
733 return NSMakeSize([_bitmap pixelsWide
], [_bitmap pixelsHigh
]);
737 -(unsigned char*)bitmapData
739 if([self isAccelerated
])
741 return [[self bitmapRepresentation
] bitmapData
];
744 -(void)setPixel
:(PixelData
*)pixel atX
:(int)x y
:(int)y
746 if([self isAccelerated
])
748 [[self bitmapRepresentation
] setPixel
:pixel atX
:(long)x y
:(long)y
];
749 [self setShouldSyncCIImage
:YES
];
752 -(void)setColor
:(NSColor
*)color atX
:(unsigned int)x y
:(unsigned int)y
754 if([self isAccelerated
])
756 [[self bitmapRepresentation
] setColor
:color atX
:x y
:y
];
757 [self setShouldSyncCIImage
:YES
];
760 -(void)getPixel
:(PixelData
*)pixel atX
:(int)x y
:(int)y
762 if([self isAccelerated
])
764 [[self bitmapRepresentation
] getPixel
:pixel atX
:x y
:y
];
767 -(NSColor
*)colorAtX
:(unsigned int)x y
:(unsigned int)y
769 if([self isAccelerated
])
771 return [[self bitmapRepresentation
]colorAtX
:x y
:y
];
785 if([self isAccelerated
])
788 //_prevCtx = [NSGraphicsContext currentContext];
790 _savedCtxState
= YES
;
791 [NSGraphicsContext saveGraphicsState
];
793 NSGraphicsContext
*nsCtx
=
794 [NSGraphicsContext graphicsContextWithAttributes
:
795 [NSDictionary dictionaryWithObject
:[self bitmapRepresentation
] forKey
:NSGraphicsContextDestinationAttributeName
]
796 ]; // create new RGBA ctx with bitmap as destination
799 NSLog(@
"Error: SCImage lockFocus: Failed setting valid NSGraphicsContext");
801 [NSGraphicsContext restoreGraphicsState
];
803 if(_interpolation
!= NSImageInterpolationDefault
) {
804 [nsCtx setImageInterpolation
:_interpolation
];
806 [NSGraphicsContext setCurrentContext
:nsCtx
]; // set the RGBA ctx
813 // [NSGraphicsContext setCurrentContext:_prevCtx];
815 if ( _savedCtxState
)
816 [NSGraphicsContext restoreGraphicsState
];
822 [self setShouldSyncCIImage
:YES
];
826 - (void)drawAtPoint
:(NSPoint
)point fromRect
:(NSRect
)srcRect operation
:(NSCompositingOperation
)op fraction
:(float)delta
828 NSImageInterpolation interp
= NSImageInterpolationDefault
;
829 NSGraphicsContext
*ctx
= NULL
;
831 ctx
= [NSGraphicsContext currentContext
];
832 NSAssert(ctx
!= nil, @
"SCImage DrawAtPoint Failed retrieving valid GraphicsContext");
834 if(_interpolation
!= NSImageInterpolationDefault
) {
835 interp
= [ctx imageInterpolation
];
836 [ctx setImageInterpolation
:_interpolation
];
840 double past
= GetTimeOfDay();
843 if(_accelerated || _hints
== SCImageUseGraphicsAccelerationWhenPossible
) // Keep CIImage up-to-date
845 [self syncCIImage
]; // update if needed
847 if(delta
< 1.0f || op
!= NSCompositeCopy
)
848 [[self ciimage
]drawAtPoint
:point fromRect
:srcRect operation
:op fraction
:delta
];
849 else // true CIContext draw
850 [[ctx CIContext
]drawImage
:[self ciimage
] atPoint
:*(CGPoint
*)&point fromRect
:*(CGRect
*)&srcRect
];
853 NSLog(@
"SCImage (%p) CIImage drawAtPoint Called Time To Render: %f", self, GetTimeOfDay() - past
);
858 [self syncBitmap
]; // update if needed
860 [[self nsimage
]drawAtPoint
:point fromRect
:srcRect operation
:op fraction
:delta
];
862 NSLog(@
"SCImage (%p) NSImage drawAtPoint Called Time To Render: %f", self, GetTimeOfDay() - past
);
866 [ctx setImageInterpolation
:interp
];
869 - (void)drawInRect
:(NSRect
)dstRect fromRect
:(NSRect
)srcRect operation
:(NSCompositingOperation
)op fraction
:(float)delta
871 NSGraphicsContext
*ctx
= [NSGraphicsContext currentContext
];
872 NSAssert(ctx
!= nil, @
"SCImage DrawAtPoint Failed retrieving valid GraphicsContext");
875 double past
= GetTimeOfDay();
880 [self syncCIImage
]; // update if needed
882 if(delta
< 1.0f || op
!= NSCompositeSourceOver
)
883 [[self ciimage
]drawInRect
:dstRect fromRect
:srcRect operation
:op fraction
:delta
];
885 [[ctx CIContext
]drawImage
:[self ciimage
] inRect
:*(CGRect
*)&dstRect fromRect
:*(CGRect
*)&srcRect
];
888 NSLog(@
"SCImage (%p) CIImage drawInRect Called Time To Render: %f", self, GetTimeOfDay() - past
);
895 NSImageInterpolation interp
= NSImageInterpolationDefault
;
896 if(_interpolation
!= NSImageInterpolationDefault
) {
897 interp
= [ctx imageInterpolation
];
898 [ctx setImageInterpolation
:_interpolation
];
900 [[self nsimage
]drawInRect
:dstRect fromRect
:srcRect operation
:op fraction
:delta
];
903 NSLog(@
"SCImage (%p) NSImage drawInRect Called Time To Render: %f", self, GetTimeOfDay() - past
);
906 [ctx setImageInterpolation
:interp
];
911 - (void)drawInSCRect
:(NSRect
)dstRect fromRect
:(NSRect
)srcRect operation
:(NSCompositingOperation
)op fraction
:(float)delta
913 NSGraphicsContext
*ctx
= [NSGraphicsContext currentContext
];
914 NSAssert(ctx
!= nil, @
"SCImage DrawAtPoint Failed retrieving valid GraphicsContext");
917 double past
= GetTimeOfDay();
920 srcRect.origin.y
= [self size
].height
- srcRect.origin.y
- srcRect.size.height
;
924 [self syncCIImage
]; // update if needed
927 NSAffineTransform
*transform
= [NSAffineTransform transform
];
928 [transform translateXBy
:0 yBy
:[self extent
].size.height
];
929 [transform scaleXBy
:1.0 yBy
:-1.0];
931 CIFilter
* fmat
= [CIFilter filterWithName
:@
"CIAffineTransform"];
933 NSLog(@
"SCImageBackground Failed getting valid CIfilter !");
938 [fmat setValue
: [self ciimage
] forKey
: @
"inputImage"];
939 [fmat setValue
: transform forKey
: @
"inputTransform"];
940 timage
= [fmat valueForKey
:@
"outputImage"];
941 if(op
!= NSCompositeSourceOver
&& op
!= NSCompositeCopy
)
943 [timage drawInRect
:dstRect fromRect
:srcRect operation
:op fraction
:delta
];
948 CIFilter
* fcol
= [CIFilter filterWithName
:@
"CIColorMatrix"];
950 [fcol setValue
: timage forKey
:@
"inputImage"];
951 [fcol setValue
: [CIVector vectorWithX
:0.0 Y
:0.0 Z
:0.0 W
:delta
] forKey
:@
"inputAVector"];
952 timage
= [fcol valueForKey
:@
"outputImage"];
955 [[ctx CIContext
]drawImage
:timage inRect
:*(CGRect
*)&dstRect fromRect
:*(CGRect
*)&srcRect
];
959 NSLog(@
"SCImage (%p) CIImage drawInRect Called Time To Render: %f", self, GetTimeOfDay() - past
);
964 CGContextRef cgctx
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
965 CGContextSaveGState(cgctx
);
967 NSImageInterpolation interp
= NSImageInterpolationDefault
;
968 if(_interpolation
!= NSImageInterpolationDefault
) {
969 interp
= [ctx imageInterpolation
];
970 [ctx setImageInterpolation
:_interpolation
];
975 CGContextTranslateCTM(cgctx
, dstRect.origin.x
, dstRect.origin.y
+ dstRect.size.height
);
976 CGContextScaleCTM(cgctx
, 1, -1.0f
);
977 dstRect.origin.y
= dstRect.origin.x
= 0.f
;
978 [[self nsimage
]drawInRect
:dstRect fromRect
:srcRect operation
:op fraction
:delta
];
981 NSLog(@
"SCImage (%p) NSImage drawInRect Called Time To Render: %f", self, GetTimeOfDay() - past
);
984 [ctx setImageInterpolation
:interp
]; // needed before ?? to test
985 CGContextRestoreGState(cgctx
);
989 - (void)tileInSCRect
:(NSRect
)dstRect fromRect
:(NSRect
)srcRect operation
:(NSCompositingOperation
)op fraction
:(float)delta
992 CGContextRef cgc
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
996 CGContextSaveGState(cgc
);
997 CGContextClipToRect(cgc
, *(CGRect
*)&dstRect
);
999 int numCols
= (int)ceilf(sc_max(1, (dstRect.size.width
/ srcRect.size.width
) + 0.5));
1000 int numRows
= (int)ceilf(sc_max(1, (dstRect.size.height
/ srcRect.size.height
) + 0.5));
1003 srcRect.origin.y
= [self size
].height
- srcRect.origin.y
- srcRect.size.height
;
1004 CGPoint where
= CGPointMake(dstRect.origin.x
, dstRect.origin.y
);
1009 cgLayer
= CGLayerCreateWithContext(cgc
, *(CGSize
*)&srcRect.size
, NULL
);
1010 CGContextRef lcg
= CGLayerGetContext(cgLayer
);
1011 CGContextTranslateCTM(lcg
, 0.f
, srcRect.size.height
);
1012 CGContextScaleCTM(lcg
, 1, -1.0f
);
1013 CIContext
*cictx
= [[CIContext contextWithCGContext
:lcg options
:nil]retain
];
1014 [cictx drawImage
:[self ciimage
] inRect
:CGRectMake(0.f
, 0.f
, srcRect.size.width
, srcRect.size.height
) fromRect
:*(CGRect
*)&srcRect
];
1020 cgLayer
= CGLayerCreateWithContext(cgc
, *(CGSize
*)&srcRect.size
, NULL
);
1021 CGContextRef lcg
= CGLayerGetContext(cgLayer
);
1022 [NSGraphicsContext saveGraphicsState
];
1023 [NSGraphicsContext setCurrentContext
:[NSGraphicsContext graphicsContextWithGraphicsPort
:lcg flipped
:NO
]];
1024 CGContextTranslateCTM(lcg
, 0.f
, srcRect.size.height
);
1025 CGContextScaleCTM(lcg
, 1, -1.0f
);
1026 [[self nsimage
]drawInRect
:NSMakeRect(0.f
, 0.f
, srcRect.size.width
, srcRect.size.height
) fromRect
:*(NSRect
*)&srcRect operation
:NSCompositeCopy fraction
:delta
];
1027 [NSGraphicsContext restoreGraphicsState
];
1029 _cache
= (void*)cgLayer
;
1032 double past
= GetTimeOfDay();
1038 CGContextSetAlpha(cgc
, delta
);
1040 for(y
=0; y
< numRows
; ++y
)
1042 where.x
= dstRect.origin.x
;
1043 for(x
=0; x
< numCols
; ++x
)
1045 CGContextDrawLayerAtPoint(cgc
, where
, cgLayer
);
1046 where.x
+= srcRect.size.width
;
1048 where.y
+= srcRect.size.height
;
1053 NSLog(@
"SCImage (%p) drawInRect Called Time To Render: %f", self, GetTimeOfDay() - past
);
1055 CGLayerRelease(cgLayer
);
1056 CGContextRestoreGState(cgc
);
1059 - (void)applyFilter
:(CIFilter
*)filter
1061 if(![self isAccelerated
])
1062 [self syncCIImage
]; // update ciimage rep
1064 if([[filter inputKeys
] containsObject
:@
"inputImage"]) {
1065 [filter setValue
:[self ciimage
] forKey
:@
"inputImage"];
1068 CIImage
*result
= [filter valueForKey
:@
"outputImage"];
1070 NSLog(@
"Failed Appying filter to image !");
1074 #if SCIMAGE_MAC_OS_10_5
1075 [_ciimageStore setImage
:result
];
1082 [self setShouldSyncBitmap
:YES
]; // invalidates bitmap
1085 -(SCImage
*)imageFilteredWith
:(CIFilter
*)filter
1087 if(![self isAccelerated
])
1090 [filter setValue
:[self ciimage
] forKey
:@
"inputImage"];
1091 CIImage
*result
= [filter valueForKey
:@
"outputImage"];
1094 NSLog(@
"Failed Appying filter to image !");
1098 #if SCIMAGE_MAC_OS_10_5
1099 SCImage
*newSCImage
= [[SCImage alloc
]initWithCIImage
:result extent
:[_ciimageStore extent
] format
:_ciFormat
];
1101 SCImage
*newSCImage
= [[SCImage alloc
]initWithCIImage
:result extent
:[_ciimage extent
] format
:_ciFormat
];
1104 return [newSCImage autorelease
];
1112 #if SCIMAGE_MAC_OS_10_5
1113 -(CIImageAccumulator
*)accumulator
{
1114 return _ciimageStore
;
1121 NSLog(@
"SCImage (%p) Dealloc", self);
1125 #if SCIMAGE_MAC_OS_10_5
1126 if(_ciimageStore
) [_ciimageStore release
];
1128 if(_ciimage
) [_ciimage release
];
1130 if(_bitmap
) [_bitmap release
];
1131 if(_nsimage
) [_nsimage release
];
1136 #pragma mark -- SCImage Primitive Set
1137 //----------------------------------------------------------------------------------------------------
1138 // SCImage primitive set
1140 int prSCImage_New(struct VMGlobals
*g
, int numArgsPushed
);
1141 int prSCImage_New(struct VMGlobals
*g
, int numArgsPushed
)
1143 if (!g
->canCallOS
) return errCantCallOS
;
1145 PyrSlot
*receiver
= g
->sp
- 3; // instance of SCImage
1146 PyrSlot
*a
= g
->sp
- 2; // width
1147 PyrSlot
*b
= g
->sp
- 1; // height
1148 PyrSlot
*c
= g
->sp
; // graphics acceleration
1150 float width
, height
;
1151 int err
= slotFloatVal(a
, &width
);
1152 if (err
) return err
;
1153 err
= slotFloatVal(b
, &height
);
1154 if (err
) return err
;
1157 SCImage
* image
= [[SCImage alloc
]initWithSize
: NSMakeSize(width
, height
) isAccelerated
:IsTrue(c
) format
:kCIFormatARGB8
];
1159 NSLog(@
"prSCImage_New Failed Creating valid SCImage !");
1163 SetPtr(slotRawObject(receiver
)->slots
+ 0, image
);
1164 SetFloat(slotRawObject(receiver
)->slots
+ 1, width
);
1165 SetFloat(slotRawObject(receiver
)->slots
+ 2, height
);
1166 InstallFinalizer(g
, slotRawObject(receiver
), 9, FinalizeSCImageObject
);
1171 int prSCImage_NewFromURL(struct VMGlobals
*g
, int numArgsPushed
);
1172 int prSCImage_NewFromURL(struct VMGlobals
*g
, int numArgsPushed
)
1174 if (!g
->canCallOS
) return errCantCallOS
;
1176 PyrSlot
*receiver
= g
->sp
- 1; // instance of SCImage
1177 PyrSlot
*a
= g
->sp
; // URL
1181 err
= allocSlotStrVal(a
, &urlpath
);
1182 if (err
) return err
;
1184 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
1185 NSString
*ns_urlpath
= [[[NSString alloc
] initWithCString
:urlpath length
:strlen(urlpath
)]autorelease
]; // Deprecated >= 10.4
1187 NSString
*ns_urlpath
= [NSString stringWithCString
:urlpath encoding
:NSASCIIStringEncoding
];
1190 NSLog(@
"Failed Creating valid NSURL from string: %s", urlpath
);
1195 SCImage
* image
= [[SCImage alloc
]initWithContentsOfURL
:[NSURL URLWithString
:ns_urlpath
] isAccelerated
:NO format
:kCIFormatARGB8
]; // by default for now set to NO
1197 NSLog(@
"prSCImage_NewFromURL Failed Creating valid SCImage !");
1201 SetPtr(slotRawObject(receiver
)->slots
+ 0, image
);
1202 SetFloat(slotRawObject(receiver
)->slots
+ 1, (float)[image width
]); // using size.width / size.height can return non integral number (ex: 499.996 instead of 499)
1203 SetFloat(slotRawObject(receiver
)->slots
+ 2, (float)[image height
]); // better to stick with bitmap properties to have true pixel size
1204 InstallFinalizer(g
, slotRawObject(receiver
), 9, FinalizeSCImageObject
);
1209 int prSCImage_WriteToFile(struct VMGlobals
*g
, int numArgsPushed
);
1210 int prSCImage_WriteToFile(struct VMGlobals
*g
, int numArgsPushed
)
1212 if (!g
->canCallOS
) return errCantCallOS
;
1214 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1215 PyrSlot
*a
= g
->sp
- 1; // path
1216 PyrSlot
*b
= g
->sp
; // image_type
1220 err
= allocSlotStrVal(a
, &path
);
1221 if (err
) return err
;
1224 err
= slotIntVal(b
, &image_type
);
1225 if (err
) return err
;
1227 NSString
*StringPath
= [[NSString alloc
] initWithCString
:path length
:strlen(path
)];
1230 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1232 if([image isAccelerated
]) {
1233 [image syncBitmap
]; // force sync of the bitmap
1235 NSData
*data
= [[image bitmapRepresentation
] representationUsingType
:(NSBitmapImageFileType
)image_type properties
:nil];
1236 BOOL result
= [data writeToFile
:StringPath atomically
:YES
];
1238 [StringPath release
];
1240 SetBool(receiver
, result ?
true : false); // inform the user if save is ok
1245 int prSCImage_interpolation(struct VMGlobals
*g
, int numArgsPushed
);
1246 int prSCImage_interpolation(struct VMGlobals
*g
, int numArgsPushed
)
1248 if (!g
->canCallOS
) return errCantCallOS
;
1250 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1251 SCImage
*image
= (SCImage
*)slotRawPtr(&slotRawObject(receiver
)->slots
[0]);
1255 SetInt(receiver
, [image imageInterpolation
]); //
1259 int prSCImage_setInterpolation(struct VMGlobals
*g
, int numArgsPushed
);
1260 int prSCImage_setInterpolation(struct VMGlobals
*g
, int numArgsPushed
)
1262 if (!g
->canCallOS
) return errCantCallOS
;
1264 PyrSlot
*receiver
= g
->sp
- 1; // SCImage
1265 PyrSlot
*a
= g
->sp
; // interpolation
1267 int interp
= NSImageInterpolationDefault
;
1269 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1273 if(slotIntVal(a
, &interp
) != errNone
)
1276 [image setImageInterpolation
:(NSImageInterpolation
)interp
];
1281 int prSCImage_Free(struct VMGlobals
*g
, int numArgsPushed
);
1282 int prSCImage_Free(struct VMGlobals
*g
, int numArgsPushed
)
1284 if (!g
->canCallOS
) return errCantCallOS
;
1286 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1287 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1292 NSLog(@
"Releasing SCImage (%p)", image
);
1296 SetNil(slotRawObject(receiver
)->slots
+ 0); // ensure slot is NIL
1297 SetNil(slotRawObject(receiver
)->slots
+ 1); // not only the pointer
1298 SetNil(slotRawObject(receiver
)->slots
+ 2);
1303 int prSCImage_sync(struct VMGlobals
*g
, int numArgsPushed
);
1304 int prSCImage_sync(struct VMGlobals
*g
, int numArgsPushed
)
1306 if (!g
->canCallOS
) return errCantCallOS
;
1308 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1309 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1310 [image syncRepresentations
]; // force sync
1313 NSLog(@
"SCImage (%p) Force Sync", image
);
1318 int prSCImage_setSize(struct VMGlobals
*g
, int numArgsPushed
);
1319 int prSCImage_setSize(struct VMGlobals
*g
, int numArgsPushed
)
1321 if (!g
->canCallOS
) return errCantCallOS
;
1323 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1324 PyrSlot
*a
= g
->sp
- 1; // width
1325 PyrSlot
*b
= g
->sp
; // height
1329 err
= slotFloatVal(a
, &width
);
1330 if (err
) return err
;
1333 err
= slotFloatVal(b
, &height
);
1334 if (err
) return err
;
1336 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1337 [image setSize
: NSMakeSize(width
, height
)];
1339 SetFloat(slotRawObject(receiver
)->slots
+ 1, width
);
1340 SetFloat(slotRawObject(receiver
)->slots
+ 2, height
);
1345 int prSCImage_setScalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
);
1346 int prSCImage_setScalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
)
1348 if (!g
->canCallOS
) return errCantCallOS
;
1350 PyrSlot
*receiver
= g
->sp
- 1; // instance of SCImage
1351 PyrSlot
*a
= g
->sp
; // bool flag
1353 BOOL flag
= IsTrue(a
);
1354 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1355 [image setScalesWhenResized
: flag
];
1360 int prSCImage_scalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
);
1361 int prSCImage_scalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
)
1363 if (!g
->canCallOS
) return errCantCallOS
;
1365 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1367 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1368 SetBool(receiver
, [image scalesWhenResized
]);
1372 int prSCImage_DrawAtPoint(struct VMGlobals
*g
, int numArgsPushed
);
1373 int prSCImage_DrawAtPoint(struct VMGlobals
*g
, int numArgsPushed
)
1375 if (!g
->canCallOS
) return errCantCallOS
;
1377 PyrSlot
*d
= g
->sp
; // fraction
1378 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1379 PyrSlot
*b
= g
->sp
- 2; // fromRect
1380 PyrSlot
*a
= g
->sp
- 3; // point
1381 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1386 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1388 return errNone
; // just do nothing
1390 if(![image ciimage
])
1392 NSLog(@
"SCImage CIImage is nil !");
1396 err
= slotGetPoint(a
, &nsPoint
);
1397 if (err
) return err
;
1401 rect
= NSMakeRect(0.0,0.0,[image size
].width
,[image size
].height
);
1403 err
= slotGetNSRect(b
, &rect
);
1404 if (err
) return err
;
1408 err
= slotIntVal(c
, &co
);
1409 if (err
) return err
;
1412 err
= slotFloatVal(d
, &fraction
);
1413 if (err
) return err
;
1415 // [image drawInSCRect:NSMakeRect(nsPoint.x, nsPoint.y, [image size].width, [image size].height) fromRect:rect operation:(NSCompositingOperation)co fraction:fraction];
1416 [image drawInSCRect
:NSMakeRect(nsPoint.x
, nsPoint.y
, rect.size.width
, rect.size.height
) fromRect
:rect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1421 int prSCImage_DrawInRect(struct VMGlobals
*g
, int numArgsPushed
);
1422 int prSCImage_DrawInRect(struct VMGlobals
*g
, int numArgsPushed
)
1424 if (!g
->canCallOS
) return errCantCallOS
;
1426 PyrSlot
*d
= g
->sp
; // fraction
1427 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1428 PyrSlot
*b
= g
->sp
- 2; // fromRect
1429 PyrSlot
*a
= g
->sp
- 3; // rect
1430 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1433 NSRect rect
, fromRect
;
1435 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1440 err
= slotGetNSRect(a
, &rect
);
1441 if (err
) return err
;
1444 fromRect
= NSMakeRect(0.0,0.0,[image size
].width
,[image size
].height
); // CIImage does not support NSZeroRect as argument
1446 err
= slotGetNSRect(b
, &fromRect
);
1447 if (err
) return err
;
1451 err
= slotIntVal(c
, &co
);
1452 if (err
) return err
;
1455 err
= slotFloatVal(d
, &fraction
);
1456 if (err
) return err
;
1458 [image drawInSCRect
:rect fromRect
:fromRect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1463 int prSCImage_TileInRect(struct VMGlobals
*g
, int numArgsPushed
);
1464 int prSCImage_TileInRect(struct VMGlobals
*g
, int numArgsPushed
)
1466 if (!g
->canCallOS
) return errCantCallOS
;
1468 PyrSlot
*d
= g
->sp
; // fraction
1469 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1470 PyrSlot
*b
= g
->sp
- 2; // fromRect
1471 PyrSlot
*a
= g
->sp
- 3; // rect
1472 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1474 NSRect nsFromRect
, nsRect
;
1479 if(IsNil(slotRawObject(receiver
)->slots
+0))
1482 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1487 err
= slotGetNSRect(a
, &nsRect
);
1488 if (err
) return err
;
1490 err
= slotGetNSRect(b
, &nsFromRect
);
1491 if (err
) return err
;
1493 err
= slotFloatVal(d
, &fraction
);
1494 if (err
) return err
;
1496 err
= slotIntVal(c
, &co
);
1497 if (err
) return err
;
1499 [image tileInSCRect
:nsRect fromRect
:nsFromRect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1503 int prSCImage_lockFocus(struct VMGlobals
*g
, int numArgsPushed
);
1504 int prSCImage_lockFocus(struct VMGlobals
*g
, int numArgsPushed
)
1506 if (!g
->canCallOS
) return errCantCallOS
;
1508 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1509 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1510 // here we do not use the set flipped because it will create problem
1511 // if we draw on top of an already image loaded with URL and write it after
1512 // better to S(T(ctx)) directly so everything is fine now
1513 // and we can write it with no problem
1515 CGContextRef ctx
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
1516 CGContextSaveGState(ctx
);
1517 CGContextTranslateCTM(ctx
, 0, [image size
].height
);
1518 CGContextScaleCTM(ctx
, 1, -1.0f
);
1523 int prSCImage_unlockFocus(struct VMGlobals
*g
, int numArgsPushed
);
1524 int prSCImage_unlockFocus(struct VMGlobals
*g
, int numArgsPushed
)
1526 if (!g
->canCallOS
) return errCantCallOS
;
1528 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1529 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1530 // revert the coordinate system
1531 CGContextRef ctx
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
1532 CGContextRestoreGState(ctx
);
1534 [image unlockFocus
];
1539 int prSCImage_recache(struct VMGlobals
*g
, int numArgsPushed
);
1540 int prSCImage_recache(struct VMGlobals
*g
, int numArgsPushed
)
1542 if (!g
->canCallOS
) return errCantCallOS
;
1544 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1546 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1551 // returns a premultipled alpha pixel as an uint32
1552 int prSCImage_pixelAt(struct VMGlobals
*g
, int numArgsPushed
);
1553 int prSCImage_pixelAt(struct VMGlobals
*g
, int numArgsPushed
)
1555 if (!g
->canCallOS
) return errCantCallOS
;
1557 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1558 PyrSlot
*xSlot
= g
->sp
- 1;
1559 PyrSlot
*ySlot
= g
->sp
;
1563 PixelData pixelAsArray
[4] = {0, 0, 0, 0};
1567 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1568 if(!image
) return errNone
;
1570 err
= slotIntVal(xSlot
, &x
);
1573 err
= slotIntVal(ySlot
, &y
);
1576 [image setAccelerated
:NO
];
1577 [image getPixel
:pixelAsArray atX
:x y
:y
];
1578 //SetInt(receiver, ((pixelAsArray[0] << 24) | (pixelAsArray[1] << 16) | (pixelAsArray[2] << 8) | pixelAsArray[3]));
1579 if( pixelAsArray
[3] == 0 ) { // avoid EXC_ARITHMETIC
1581 (pixelAsArray
[0] << 24) |
1582 (pixelAsArray
[1] << 16) |
1583 (pixelAsArray
[2] << 8)
1587 (COLOR_UNSCALE( pixelAsArray
[0], pixelAsArray
[3] ) << 24) |
1588 (COLOR_UNSCALE( pixelAsArray
[1], pixelAsArray
[3] ) << 16) |
1589 (COLOR_UNSCALE( pixelAsArray
[2], pixelAsArray
[3] ) << 8) |
1596 int prSCImage_setPixelAt(struct VMGlobals
*g
, int numArgsPushed
);
1597 int prSCImage_setPixelAt(struct VMGlobals
*g
, int numArgsPushed
)
1599 if (!g
->canCallOS
) return errCantCallOS
;
1601 PyrSlot
*receiver
= g
->sp
- 3; // instance of SCImage
1602 PyrSlot
*pixelSlot
= g
->sp
- 2;
1603 PyrSlot
*xSlot
= g
->sp
- 1;
1604 PyrSlot
*ySlot
= g
->sp
;
1606 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1612 PixelData pixelData
[4]={0, 0, 0, 0};
1614 err
= slotIntVal(pixelSlot
, (int*)&pixel
);
1617 err
= slotIntVal(xSlot
, &x
);
1620 err
= slotIntVal(ySlot
, &y
);
1623 [image setAccelerated
:NO
];
1625 pixelData
[0] = COLOR_SCALE(PIXEL_RED(pixel
), PIXEL_ALPHA(pixel
));
1626 pixelData
[1] = COLOR_SCALE(PIXEL_GREEN(pixel
), PIXEL_ALPHA(pixel
));
1627 pixelData
[2] = COLOR_SCALE(PIXEL_BLUE(pixel
), PIXEL_ALPHA(pixel
));
1628 pixelData
[3] = PIXEL_ALPHA(pixel
);
1630 [image setPixel
:pixelData atX
:x y
:y
];
1635 int prSCImage_setColorAt(struct VMGlobals
*g
, int numArgsPushed
);
1636 int prSCImage_setColorAt(struct VMGlobals
*g
, int numArgsPushed
)
1638 if (!g
->canCallOS
) return errCantCallOS
;
1640 PyrSlot
*receiver
= g
->sp
- 3; // instance of SCImage
1641 PyrSlot
*colorSlot
= g
->sp
- 2;
1642 PyrSlot
*xSlot
= g
->sp
- 1;
1643 PyrSlot
*ySlot
= g
->sp
;
1645 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1649 [image setAccelerated
:NO
];
1653 NSSize size
= [image size
];
1655 err
= slotColorVal(colorSlot
, &color
);
1658 err
= slotIntVal(xSlot
, &x
);
1661 err
= slotIntVal(ySlot
, &y
);
1665 setColor
:[NSColor colorWithCalibratedRed
:color.red green
:color.green blue
:color.blue alpha
:color.alpha
]
1673 int prSCImage_getColorAt(struct VMGlobals
*g
, int numArgsPushed
);
1674 int prSCImage_getColorAt(struct VMGlobals
*g
, int numArgsPushed
)
1676 if (!g
->canCallOS
) return errCantCallOS
;
1678 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1679 PyrSlot
*xSlot
= g
->sp
- 1;
1680 PyrSlot
*ySlot
= g
->sp
;
1683 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1689 err
= slotIntVal(xSlot
, &x
);
1692 err
= slotIntVal(ySlot
, &y
);
1695 [image setAccelerated
:NO
];
1705 nsColor
= [nsColor colorUsingColorSpaceName
:NSCalibratedRGBColorSpace
];
1706 PyrObject
*color
= instantiateObject(g
->gc
, s_color
->u.classobj
, 0, false, true);
1707 PyrSlot
*slots
= color
->slots
;
1708 SetFloat(slots
+0, [nsColor redComponent
]);
1709 SetFloat(slots
+1, [nsColor greenComponent
]);
1710 SetFloat(slots
+2, [nsColor blueComponent
]);
1711 SetFloat(slots
+3, [nsColor alphaComponent
]);
1712 SetObject(receiver
, color
);
1718 int prSCImage_loadPixels(struct VMGlobals
*g
, int numArgsPushed
);
1719 int prSCImage_loadPixels(struct VMGlobals
*g
, int numArgsPushed
)
1721 if (!g
->canCallOS
) return errCantCallOS
;
1723 PyrSlot
*receiver
= g
->sp
- 3;
1724 PyrSlot
*pixelSlot
= g
->sp
- 2;
1725 PyrSlot
*regionSlot
= g
->sp
- 1;
1729 NSBitmapImageRep
*bitmap
;
1731 int height
, width
, y
=0, x
=0, startIndex
=0;
1735 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1740 size
= [image size
];
1742 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1743 if(pyrclass
!= class_int32array
) {
1744 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1748 slotIntVal(g
->sp
, &startIndex
);
1750 return errIndexOutOfRange
;
1752 PyrInt32Array
* allocatedPixelArray
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1754 bitmap
= [image bitmapRepresentation
];
1756 if(IsNil(regionSlot
)) {
1757 region
= NSIntegralRect(NSMakeRect(0.f
, 0.f
, [bitmap pixelsWide
], [bitmap pixelsHigh
]));
1759 if(slotGetNSRect(regionSlot
, ®ion
) != errNone
)
1760 return errWrongType
;
1761 region
= NSIntegralRect(region
);
1762 if( region.origin.x
< 0 || region.origin.y
< 0 ||
((region.origin.x
+ region.size.width
) > [bitmap pixelsWide
]) ||
((region.origin.y
+ region.size.height
) > [bitmap pixelsHigh
]) )
1763 return errIndexOutOfRange
;
1766 height
= region.size.height
;
1767 width
= region.size.width
;
1768 pixelsData
= (uint32
*)allocatedPixelArray
->i
+ startIndex
;
1769 PixelData pixel
[4]={0, 0, 0, 0};
1771 if((allocatedPixelArray
->size
- startIndex
) < ( height
* width
/** 4*/ ) ) {
1772 post("Error: pixel array is not of good size ! should be %i bytes long\n", height
* width
/** 4*/);
1773 return errIndexOutOfRange
;
1777 unsigned char alpha
;
1778 height
= height
+ region.origin.y
; //padding h and w to meet origin
1779 width
= width
+ region.origin.x
;
1780 for(y
=(int)region.origin.y
; y
< height
; y
++) {
1781 for(x
=(int)region.origin.x
; x
< width
; x
++) {
1783 // most of the unscale routines may be not as precise as we need
1784 // especially when dealing with CIImage <-> NSImage conversion...
1785 // it should be better to use vImage framework directly !
1787 [bitmap getPixel
:pixel atX
:x y
:y
];
1789 SET_PIXEL_RED ( *pixelsData
, COLOR_UNSCALE(pixel
[0], pixel
[3]) );
1790 SET_PIXEL_GREEN( *pixelsData
, COLOR_UNSCALE(pixel
[1], pixel
[3]) );
1791 SET_PIXEL_BLUE ( *pixelsData
, COLOR_UNSCALE(pixel
[2], pixel
[3]) );
1792 SET_PIXEL_ALPHA( *pixelsData
, pixel
[3]);
1794 SET_PIXEL_RED ( *pixelsData
, pixel
[0] );
1795 SET_PIXEL_GREEN( *pixelsData
, pixel
[1] );
1796 SET_PIXEL_BLUE ( *pixelsData
, pixel
[2] );
1797 SET_PIXEL_ALPHA( *pixelsData
, pixel
[3] );
1801 //bitmapData += bytesLeft;
1808 int prSCImage_updatePixels(struct VMGlobals
*g
, int numArgsPushed
);
1809 int prSCImage_updatePixels(struct VMGlobals
*g
, int numArgsPushed
)
1811 if (!g
->canCallOS
) return errCantCallOS
;
1813 PyrSlot
*receiver
= g
->sp
- 2;
1814 PyrSlot
*pixelSlot
= g
->sp
- 1;
1817 NSBitmapImageRep
*bitmap
;
1818 int width
, height
, bytesPerRow
, bytesLeft
, startIndex
=0, y
=0, x
=0;
1819 unsigned char *bitmapData
;
1821 PyrInt32Array
*pixels
;
1824 if(IsNil(pixelSlot
))
1827 slotIntVal(g
->sp
, &startIndex
);
1829 return errIndexOutOfRange
;
1831 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1837 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1838 if(pyrclass
!= class_int32array
) {
1839 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1843 pixels
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1845 bitmap
= [image bitmapRepresentation
];
1847 NSLog(@
"prSCImage_updatePixels failed retrieving valid NSBitmapImageRep...");
1851 width
= [bitmap pixelsWide
]; // RGBA
1852 height
= [bitmap pixelsHigh
];
1853 bytesPerRow
= [bitmap bytesPerRow
];
1854 bitmapData
= [bitmap bitmapData
];
1855 pixelsData
= (uint32
*)pixels
->i
+ startIndex
;
1856 bytesLeft
= bytesPerRow
- (width
*4);
1858 if( (pixels
->size
- startIndex
) < (int)(width
*height
/* *4 */)) {
1859 post("Error: pixel array is not of good size ! should be %i bytes long from index: %i\n", (int)(width
*height
/**4*/), startIndex
);
1860 return errIndexOutOfRange
;
1864 unsigned char alpha
;
1865 for(y
=0; y
< height
; ++y
) {
1866 for(x
=0; x
< width
; ++x
) {
1867 alpha
= PIXEL_ALPHA(*pixelsData
);
1868 *bitmapData
++ = COLOR_SCALE(PIXEL_RED(*pixelsData
), alpha
);
1869 *bitmapData
++ = COLOR_SCALE(PIXEL_GREEN(*pixelsData
), alpha
);
1870 *bitmapData
++ = COLOR_SCALE(PIXEL_BLUE(*pixelsData
), alpha
);
1871 *bitmapData
++ = alpha
;
1874 bitmapData
+= bytesLeft
;
1878 [image setShouldSyncCIImage
:YES
];
1884 int prSCImage_updatePixelsInRect(struct VMGlobals
*g
, int numArgsPushed
);
1885 int prSCImage_updatePixelsInRect(struct VMGlobals
*g
, int numArgsPushed
)
1887 if (!g
->canCallOS
) return errCantCallOS
;
1889 PyrSlot
*receiver
= g
->sp
- 3;
1890 PyrSlot
*pixelSlot
= g
->sp
- 2;
1891 PyrSlot
*rectSlot
= g
->sp
- 1;
1894 NSBitmapImageRep
*bitmap
;
1895 int width
, height
, bytesPerRow
, bytesLeft
, y
=0, x
=0, startIndex
=0, err
;
1896 unsigned char *bitmapData
;
1898 PyrInt32Array
*pixels
;
1902 if(IsNil(pixelSlot
))
1905 slotIntVal(g
->sp
, &startIndex
); // get the Array start index
1907 return errIndexOutOfRange
;
1909 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1915 err
= slotGetNSRect(rectSlot
, &rect
);
1916 if (err
) return err
;
1917 rect
= NSIntegralRect(rect
);
1919 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1920 if(pyrclass
!= class_int32array
) {
1921 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1925 pixels
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1926 bitmap
= [image bitmapRepresentation
];
1928 NSLog(@
"prSCImage_updatePixels failed retrieving valid NSBitmapImageRep...");
1929 return errIndexOutOfRange
;
1932 width
= [bitmap pixelsWide
]; // RGBA
1933 height
= [bitmap pixelsHigh
];
1934 bytesPerRow
= [bitmap bytesPerRow
];
1935 bitmapData
= [bitmap bitmapData
];
1936 pixelsData
= (uint32
*)pixels
->i
+ startIndex
;
1939 rect.origin.x
= sc_max(rect.origin.x
, 0); // negative idx not allowed
1940 rect.origin.y
= sc_max(rect.origin.y
, 0); // negative idx not allowed
1941 rect.size.width
= sc_min(rect.size.width
, width
); // clip to image width max
1942 rect.size.height
= sc_min(rect.size.height
, height
); // clip to image height max
1944 // what is the best :
1945 // 1 - clipping + wrapping thus giving strange results ?
1946 // 2 - throw an error ?
1947 // just throw an error for now -> so no strange results and no scratching head... :)
1948 // zero tolerance >:^(
1950 ((rect.origin.x
+ rect.size.width
) > width
) ||
1951 ((rect.origin.y
+ rect.size.height
) > height
)
1953 return errIndexOutOfRange
;
1955 bytesLeft
= (bytesPerRow
- (rect.size.width
* 4));
1956 if( (pixels
->size
- startIndex
) < (int)(rect.size.width
* rect.size.height
)) {
1957 post("Error: pixel array is not of good size ! should be %i bytes long from index: %i\n", (int)(rect.size.width
* rect.size.height
), startIndex
);
1962 unsigned char alpha
;
1963 bitmapData
+= ((int)rect.origin.y
* bytesPerRow
) + ((int)rect.origin.x
* 4);
1964 for(y
=0; y
< rect.size.height
; ++y
) {
1965 for(x
=0; x
< rect.size.width
; ++x
) {
1966 alpha
= PIXEL_ALPHA(*pixelsData
);
1967 *bitmapData
++ = COLOR_SCALE(PIXEL_RED(*pixelsData
), alpha
);
1968 *bitmapData
++ = COLOR_SCALE(PIXEL_GREEN(*pixelsData
), alpha
);
1969 *bitmapData
++ = COLOR_SCALE(PIXEL_BLUE(*pixelsData
), alpha
);
1970 *bitmapData
++ = alpha
;
1973 bitmapData
+= bytesLeft
;
1977 [image setShouldSyncCIImage
:YES
];
1982 int prSCImage_isAccelerated(struct VMGlobals
*g
, int numArgsPushed
);
1983 int prSCImage_isAccelerated(struct VMGlobals
*g
, int numArgsPushed
)
1985 if (!g
->canCallOS
) return errCantCallOS
;
1987 PyrSlot
*receiver
= g
->sp
;
1989 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1995 SetBool(receiver
, [image isAccelerated
]);
2000 int prSCImage_setAccelerated(struct VMGlobals
*g
, int numArgsPushed
);
2001 int prSCImage_setAccelerated(struct VMGlobals
*g
, int numArgsPushed
)
2003 if (!g
->canCallOS
) return errCantCallOS
;
2005 PyrSlot
*receiver
= g
->sp
- 1;
2006 PyrSlot
*yornSlot
= g
->sp
;
2008 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2014 [image setAccelerated
:IsTrue(yornSlot
)];
2021 // Currently it grabs a portion from the scgraphview
2022 // user should here pass the ABSOLUTE view bounds or a specific rect
2023 int prSCImage_imageFromSCWindowRect(struct VMGlobals
*g
, int numArgsPushed
);
2024 int prSCImage_imageFromSCWindowRect(struct VMGlobals
*g
, int numArgsPushed
)
2026 if (!g
->canCallOS
) return errCantCallOS
;
2028 PyrSlot
*receiver
= g
->sp
- 2; // SCImage class
2029 PyrSlot
*a
= g
->sp
- 1; // SCWindow instance
2030 PyrSlot
*b
= g
->sp
; // SCRect instance - portion in the SCGraphView
2033 NSBitmapImageRep
*nsbitmap
= nil;
2034 NSImage
*nsimage
= nil;
2035 SCGraphView
*nsview
= nil;
2036 SCImage
*scimage
= nil;
2039 if(!IsPtr(&slotRawObject(a
)->slots
[0])) {
2043 nsview
= (SCGraphView
*)slotRawPtr(&slotRawObject(a
)->slots
[0]); // get SCGraphView instance
2044 err
= slotGetNSRect(b
, &rect
);
2049 nsbitmap
= [[NSBitmapImageRep alloc
]initWithFocusedViewRect
:rect
];
2050 [nsview unlockFocus
];
2054 post("Error: Failed getting valid image from SCView !\n");
2058 PyrObject
* object
= NULL
;
2061 [[NSImage alloc
]initWithSize
:NSMakeSize((float)[nsbitmap pixelsWide
], (float)[nsbitmap pixelsHigh
])];
2064 post("Error: Failed creating valid NSImage !\n");
2069 [nsimage addRepresentation
:nsbitmap
];
2071 scimage
= [[SCImage alloc
]initWithNSImage
:nsimage
];
2073 post("Error: Failed creating valid SCImage !\n");
2078 // Instantiate and set the SCObject
2079 object
= newPyrSCImage(g
);
2081 post("Error: Failed creating valid SCImage class !");
2087 SetPtr(object
->slots
+ 0, scimage
);
2088 SetFloat(object
->slots
+ 1, (float)[nsbitmap pixelsWide
]);
2089 SetFloat(object
->slots
+ 2, (float)[nsbitmap pixelsHigh
]);
2090 SetObject(receiver
, object
);
2094 if(nsimage
) [nsimage release
];
2095 if(nsbitmap
) [nsbitmap release
];
2100 #pragma mark --- SCImageFilter Primitive Set
2102 PyrClass
* slotArrayGetCommonClass(PyrObject
* array
)
2104 int size
= array
->size
;
2108 PyrClass
*commonClass
= slotRawObject(&array
->slots
[0])->classptr
;
2110 for(int i
=1; i
< size
; ++i
) {
2111 if(slotRawObject(&array
->slots
[0])->classptr
!= commonClass
)
2118 BOOL nsClassIsKindOfClass(Class currentClass
, Class match
);
2119 BOOL nsClassIsKindOfClass(Class currentClass
, Class match
)
2121 if(currentClass
== match
)
2125 while( (superClass
= class_getSuperclass(currentClass
)) ) {
2126 if(superClass
== match
)
2133 id ciVectorFromSlot(PyrObject
* slot
);
2134 id ciVectorFromSlot(PyrObject
* slot
)
2136 ColorData values
[4] = {0.f
, 0.f
, 0.f
, 0.f
};
2137 int size
= slot
->size
, err
;
2139 for (int i
=0; i
< size
; ++i
) {
2141 err
= slotFloatVal(slot
->slots
+ i
, &val
);
2146 return [CIVector vectorWithValues
:values count
:(size_t)4];
2149 int safeSlotFloatVal(PyrSlot
* slot
, float* value
);
2150 int safeSlotFloatVal(PyrSlot
* slot
, float* value
)
2156 return slotFloatVal(slot
, value
);
2159 CGRect
OutsetRect(CGRect r
, const float dx
, const float dy
)
2161 CGRect ret
= CGRectMake(r.origin.x
- dx
, r.origin.y
- dy
, r.size.width
+ dx
+ dx
, r.size.height
+ dy
+ dy
);
2165 CIImage
* CropAndCenterCIImage(CIImage
*image
, CGRect originalExtent
, CGRect
* cropRegionRef
);
2166 CIImage
* CropAndCenterCIImage(CIImage
*image
, CGRect originalExtent
, CGRect
* cropRegionRef
)
2168 #if SCIMAGE_FILTER_DEBUG
2169 NSLog(@
"Cropping and centering CIImage %p", image
);
2171 CGRect extent
= [image extent
];
2172 CIFilter
* ciFilter
;
2177 CGRect cropRegion
= *cropRegionRef
;
2178 // Crop to specified rectangle.
2179 if(extent.size.width
> cropRegion.size.width || extent.size.height
> cropRegion.size.height
)
2181 if(extent.origin.x
> 0) {cropRegion.origin.x
= extent.origin.x
;}
2182 if(extent.origin.y
> 0) {cropRegion.origin.y
= extent.origin.y
;}
2185 // quite strange but happens sometime...
2186 if(extent.origin.x
< 0 && ((extent.origin.x
+ extent.size.width
) < cropRegion.size.width
)) {
2187 float diff
= extent.size.width
+ extent.origin.x
;
2188 cropRegion.origin.x
-= (cropRegion.size.width
- diff
);
2191 if(extent.origin.y
< 0 && ((extent.origin.y
+ extent.size.height
) < cropRegion.size.height
)) {
2192 float diff
= extent.size.height
+ extent.origin.y
;
2193 cropRegion.origin.y
-= (cropRegion.size.height
- diff
);
2196 #if SCIMAGE_FILTER_DEBUG
2197 NSLog(@
"SCImageFilter: Cropping To Size: (%4.2f, %4.2f, %4.2f, %4.2f) fromExtent: (%4.2f, %4.2f, %4.2f, %4.2f)",
2198 cropRegion.origin.x
,cropRegion.origin.y
,cropRegion.size.width
,cropRegion.size.height
,
2199 extent.origin.x
,extent.origin.y
,extent.size.width
,extent.size.height
2203 ciFilter
= [CIFilter filterWithName
:@
"CICrop"]; // crop the final result according
2204 [ciFilter setValue
:image forKey
:@
"inputImage"];
2205 [ciFilter setValue
:[CIVector vectorWithX
:cropRegion.origin.x Y
:cropRegion.origin.y Z
:cropRegion.size.width W
:cropRegion.size.height
] forKey
:@
"inputRectangle"];
2206 image
= [ciFilter valueForKey
:@
"outputImage"];
2207 extent
= [image extent
];
2208 #if SCIMAGE_FILTER_DEBUG
2209 NSLog(@
"SCImageFilter: After CROP Extent: (%4.2f, %4.2f, %4.2f, %4.2f)", extent.origin.x
,extent.origin.y
,extent.size.width
, extent.size.height
);
2214 // translating origin and center it if we need it
2215 // currently auto translation is now deactivated by default - let the user choose
2218 if(extent.origin.x != 0 || extent.origin.y != 0) {
2219 ciFilter = [CIFilter filterWithName:@"CIAffineTransform"];
2220 NSAffineTransform* trs = [NSAffineTransform transform];
2221 [trs translateXBy:-extent.origin.x yBy:-extent.origin.y]; // move to zero
2222 [ciFilter setValue:trs forKey:@"inputTransform"];
2223 [ciFilter setValue:image forKey:@"inputImage"];
2224 image = [ciFilter valueForKey:@"outputImage"];
2225 #if SCIMAGE_FILTER_DEBUG
2226 NSLog(@"SCImageFilter: After Translate: (%4.2f, %4.2f, %4.2f, %4.2f)", extent.origin.x,extent.origin.y,extent.size.width, extent.size.height);
2234 id nsciObjectFromSlot(PyrSlot
*slot
, Class attributeClass
, NSString
*attributeType
);
2235 id nsciObjectFromSlot(PyrSlot
*slot
, Class attributeClass
, NSString
*attributeType
)
2238 if(attributeClass
== [CIImage
class] || attributeType
== kCIAttributeTypeGradient
)
2240 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(slot
)->slots
);
2241 return [image ciimage
];
2243 else if(isKindOfSlot(slot
, s_scimage
->u.classobj
) && (attributeClass
== NULL
) && (attributeType
== NULL
)) // here returns the CISampler by default
2245 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(slot
)->slots
);
2246 return [CISampler samplerWithImage
:[image ciimage
]];
2248 // else if(isKindOfSlot(slot, s_vector->u.classobj)) {
2250 else if(isKindOfSlot(slot, s_array->u.classobj)) {
2251 #if SCIMAGE_FILTER_DEBUG
2252 NSLog(@"Creating CIVector From Vector Slot");
2255 return ciVectorFromSlot(slotRawObject(slot));
2258 else if(isKindOfSlot(slot
, s_color
->u.classobj
))
2260 PyrSlot
* color_slots
= slotRawObject(slot
)->slots
;
2262 err
= slotFloatVal(color_slots
+0, &cr
);
2264 err
= slotFloatVal(color_slots
+1, &cg
);
2266 err
= slotFloatVal(color_slots
+2, &cb
);
2268 err
= slotFloatVal(color_slots
+3, &ca
);
2271 #if SCIMAGE_FILTER_DEBUG
2272 NSLog(@
"Creating CIColor/NSColor From Color Slot");
2275 if(attributeClass
== [NSColor
class])
2277 return [NSColor colorWithCalibratedRed
:cr green
:cg blue
:cb alpha
:ca
];
2279 return [CIColor colorWithRed
:cr green
:cg blue
:cb alpha
:ca
];
2281 else if(isKindOfSlot(slot
, s_array
->u.classobj
))
2283 if(attributeClass
== [NSAffineTransform
class]) {
2284 #if SCIMAGE_FILTER_DEBUG
2285 NSLog(@
"Creating NSAffineTransform From Array Slot");
2287 // array containing [Tx, Ty, Sx, Sy, Rot in radians]
2288 PyrObject
* array
= slotRawObject(slot
);
2289 int size
= sc_min(array
->size
, 5), err
;
2290 float attributes
[5] = {0.f
, 0.f
, 1.f
, 1.f
, 0.f
};
2291 for(int i
=0; i
< size
; ++i
) {
2292 err
= slotFloatVal(array
->slots
+i
, attributes
+i
);
2294 attributes
[i
] = 0.f
;
2297 NSAffineTransform
*transform
= [NSAffineTransform transform
];
2298 [transform translateXBy
:attributes
[0] yBy
:attributes
[1]];
2299 [transform scaleXBy
:attributes
[2] yBy
:attributes
[3]];
2300 [transform rotateByRadians
:attributes
[4]];
2304 if(attributeClass
== [CIVector
class] || attributeClass
== NULL
) {
2305 #if SCIMAGE_FILTER_DEBUG
2306 NSLog(@
"Creating CIVector From Array Slot");
2308 return ciVectorFromSlot(slotRawObject(slot
));
2312 if(nsClassIsKindOfClass(attributeClass
, [NSData
class])) {
2313 // handle specific case here...
2314 // mostly for CIColorCube Filter
2315 #if SCIMAGE_FILTER_DEBUG
2316 NSLog(@
"Creating NSData From Array Slot");
2318 PyrClass
*support
= slotArrayGetCommonClass(slotRawObject(slot
));
2323 support != s_int8array->u.classobj &&
2324 support != s_int16array->u.classobj &&
2325 support != s_int32array->u.classobj &&
2326 support != s_doublearray->u.classobj &&
2327 support != class_floatarray->u.classobj
2336 else if(IsTrue(slot
) ||
IsFalse(slot
) )
2338 #if SCIMAGE_FILTER_DEBUG
2339 NSLog(@
"Creating NSNumber From Boolean Slot");
2341 return [NSNumber numberWithBool
:(IsTrue(slot
))];
2343 else if(IsFloat(slot
) ||
IsInt(slot
))
2345 #if SCIMAGE_FILTER_DEBUG
2346 NSLog(@
"Creating NSNumber From Float/Int Slot");
2350 err
= safeSlotFloatVal(slot
, &val
);
2353 if(attributeType
== kCIAttributeTypeBoolean
) {
2354 return [NSNumber numberWithBool
:val
> 0];
2356 return [NSNumber numberWithFloat
:val
];
2359 post("Non supported type of class: %s", slotRawObject(slot
)->classptr
->name
);
2360 return nil; // failure
2364 int prSCImageFilter_ApplyMultiple(struct VMGlobals
*g
, int numArgsPushed
);
2365 int prSCImageFilter_ApplyMultiple(struct VMGlobals
*g
, int numArgsPushed
)
2367 PyrSlot
*receiver
= g
->sp
- 4;
2368 PyrSlot
*filtersSlot
= g
->sp
- 3;
2369 PyrSlot
*inPlace
= g
->sp
- 2;
2370 PyrSlot
*updateRegionSlot
= g
->sp
- 1;
2371 PyrSlot
*cropRegionSlot
= g
->sp
;
2374 SCImage
*scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2380 int numberOfFilters
;
2381 PyrObject
* scFilter
;
2382 PyrObject
*arguments
;
2386 //NSArray *inputKeys;
2391 CGRect origExtent
= [scimage extent
];
2395 numberOfFilters
= slotRawObject(filtersSlot
)->size
;
2397 // Get the CIImage rep in the SCImage
2398 if(![scimage isAccelerated
])
2399 [scimage syncCIImage
]; // update ciimage rep
2400 ciimage
= [scimage ciimage
]; // now we can get it
2402 // Iterate through all the filters
2403 for(int i
=0; i
< numberOfFilters
; ++i
)
2407 scFilter
= slotRawObject(&(slotRawObject(filtersSlot
)->slots
[i
]));
2409 if(IsFalse(scFilter
->slots
+3)) // filter enabled ?
2412 ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(scFilter
->slots
+0)]; // filter name
2413 if(!ciFilter
) return errFailed
;
2414 #if SCIMAGE_FILTER_DEBUG
2415 NSLog(@
"SCImageFilter --- Setting Filter Named %@", nsStringFromSlot(scFilter
->slots
+0));
2417 [ciFilter setDefaults
];
2419 arguments
= slotRawObject(&scFilter
->slots
[2]); // filter values
2420 size
= (arguments
->size
>> 1);
2422 for(int i
=0; i
< size
; ++i
)
2424 key
= slotRawSymbol(arguments
->slots
+ (i
<<1));
2425 value
= arguments
->slots
+ ((i
<<1) + 1);
2426 nskey
= [NSString stringWithFormat
:@
"input%c%s", toupper(*key
->name
), key
->name
+1];
2427 valueClass
= NSClassFromString( [[[ciFilter attributes
] objectForKey
:nskey
] objectForKey
:@
"CIAttributeClass"]);
2428 nsvalue
= nsciObjectFromSlot(value
, valueClass
, [[ciFilter attributes
] objectForKey
:kCIAttributeType
]);
2432 #if SCIMAGE_FILTER_DEBUG
2433 NSLog(@
"Setting Key: %@ Value: %@ Class: %@", nskey
, nsvalue
, valueClass
);
2435 [ciFilter setValue
:nsvalue forKey
:nskey
];
2439 post("Error: bad (nil) slot value for Filter: %s key %s, NSObject conversion failed for class %s !", slotRawSymbol(&scFilter
->slots
[0])->name
, [nskey UTF8String
], class_getName(valueClass
));
2443 // concatenate filters
2444 if([[ciFilter inputKeys
]containsObject
:@
"inputImage"])
2446 [ciFilter setValue
:ciimage forKey
:@
"inputImage"];
2450 ciimage
= [ciFilter valueForKey
:@
"outputImage"];
2454 destExtent
= [ciimage extent
];
2456 #if SCIMAGE_MAC_OS_10_5
2458 //CGRectIsInfinite(destExtent) || // infinite rects are mosly results from generator filters
2459 !IsNil(updateRegionSlot
) // better to keep original extent if constrained update
2462 destExtent
= origExtent
;
2467 // if the rect is not infinite :
2468 // 1 - crop the image if a cropRegion is specified
2469 // 2 - translate the image to align origin of extent with coordindate origin of image (0,0)
2471 if(IsNil(cropRegionSlot
)) {
2472 #if SCIMAGE_FILTER_DEBUG
2473 NSLog(@
"SCImageFilter: Nil Crop Region - creating from %i, %i maximum crop size", SCCIIMAGE_MAX_WIDTH
, SCCIIMAGE_MAX_HEIGHT
);
2475 cropRegion
= OutsetRect(origExtent
, floorf((SCCIIMAGE_MAX_WIDTH
- origExtent.size.width
) * 0.5), floorf((SCCIIMAGE_MAX_HEIGHT
- origExtent.size.height
) * 0.5));
2477 err
= slotGetNSRect(cropRegionSlot
, (NSRect
*)&cropRegion
);
2480 ciimage
= CropAndCenterCIImage(ciimage
, origExtent
, &cropRegion
);
2481 destExtent
= [ciimage extent
];
2483 #if SCIMAGE_MAC_OS_10_5
2488 PyrObject
*receiverObj
;
2491 // Here the caller should be directly updated !
2492 // Size will be equal if :
2493 // 1 - the filter does not extend the image bounds (modified / infinite extent)
2494 // 2 - the update region slot if not nil to constrain updates
2495 if(CGSizeEqualToSize(destExtent.size
, origExtent.size
))
2497 #if SCIMAGE_MAC_OS_10_5
2498 if(!IsNil(updateRegionSlot
))
2500 CGRect updateRegion
;
2501 err
= slotGetNSRect(updateRegionSlot
, (NSRect
*)&updateRegion
);
2503 // Invert SC Coordinates
2504 updateRegion.origin.y
= [[scimage accumulator
]extent
].size.height
- (updateRegion.origin.y
+ updateRegion.size.height
);
2505 [[scimage accumulator
] setImage
:ciimage dirtyRect
:updateRegion
];
2509 [[scimage accumulator
] setImage
:ciimage
];
2513 [scimage
->_ciimage release
];
2514 scimage
->_ciimage
= ciimage
;
2516 [scimage setShouldSyncBitmap
:YES
]; // keep the sync info
2521 receiverObj
= slotRawObject(receiver
);
2523 #if SCIMAGE_FILTER_DEBUG
2524 NSLog(@
"SCImageFilter: New Extent (%4.2f, %4.2f, %4.2f, %4.2f)", destExtent.origin.x
, destExtent.origin.y
, destExtent.size.width
, destExtent.size.height
);
2529 receiverObj
= newPyrSCImage(g
);
2532 post("Failed creating valid SCImage class !");
2537 #if SCIMAGE_DEBUG || SCIMAGE_FILTER_DEBUG
2538 NSLog(@
"SCImageFilter: Creating New SCImage Class");
2539 NSLog(@
"SCImageFilter: OriginalImage Extent: (%4.2f, %4.2f, %4.2f, %4.2f) NewImage Extent: (%4.2f, %4.2f, %4.2f, %4.2f)",
2540 origExtent.origin.x
, origExtent.origin.y
, origExtent.size.width
, origExtent.size.height
,
2541 destExtent.origin.x
,destExtent.origin.y
,destExtent.size.width
, destExtent.size.height
2545 SCImage
*newSCImage
= [[SCImage alloc
]initWithCIImage
:ciimage extent
:destExtent format
:[scimage format
]];
2548 post("Error: Failed creating valid CIImage cache !!!");
2552 value
= receiverObj
->slots
;
2553 SetPtr(value
+ 0, newSCImage
);
2554 SetFloat(value
+ 1, destExtent.size.width
);
2555 SetFloat(value
+ 2, destExtent.size.height
);
2557 if(receiverObj
== slotRawObject(receiver
))
2560 SetObject(receiver
, receiverObj
);
2565 int prSCImageFilter_Apply(struct VMGlobals
*g
, int numArgsPushed
);
2566 int prSCImageFilter_Apply(struct VMGlobals
*g
, int numArgsPushed
)
2568 PyrSlot
*receiver
= g
->sp
- 3;
2569 PyrSlot
*filterNameSlot
= g
->sp
- 2;
2570 PyrSlot
*argumentsSlot
= g
->sp
- 1;
2571 PyrSlot
*inPlace
= g
->sp
;
2573 SCImage
*scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2579 CIFilter
* ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(filterNameSlot
)];
2583 [ciFilter setDefaults
];
2585 PyrObject
*arguments
= slotRawObject(argumentsSlot
); // array
2592 int size
= (arguments
->size
>> 1);
2594 for(int i
=0; i
< size
; ++i
) {
2595 key
= (PyrSymbol
*)slotRawSymbol(arguments
->slots
+ (i
<<1));
2596 value
= arguments
->slots
+ ((i
<<1) + 1);
2597 nskey
= [NSString stringWithFormat
:@
"input%c%s", toupper(*key
->name
), key
->name
+1];
2598 valueClass
= NSClassFromString( [[[ciFilter attributes
] objectForKey
:nskey
] objectForKey
:@
"CIAttributeClass"]);
2599 nsvalue
= nsciObjectFromSlot(value
, valueClass
, [[ciFilter attributes
] objectForKey
:kCIAttributeType
]);
2601 #if SCIMAGE_FILTER_DEBUG
2602 NSLog(@
"Setting Key: %@ Value: %@ Class: %@", nskey
, nsvalue
, valueClass
);
2604 [ciFilter setValue
:nsvalue forKey
:nskey
];
2606 post("Error: bad (nil) slot value for key %s, NSObject conversion failed for class %s !", [nskey UTF8String
], class_getName(valueClass
));
2610 if(IsTrue(inPlace
)) {
2611 [scimage applyFilter
:ciFilter
]; // in place filter
2615 NSLog(@
"Creating New SCImage Class");
2618 scimage
= [scimage imageFilteredWith
:ciFilter
]; // filtered copy
2619 PyrObject
* object
= newPyrSCImage(g
);
2620 PyrSlot
*slots
= object
->slots
;
2621 SetPtr(slots
+ 0, scimage
);
2622 SetFloat(slots
+ 1, (float)[scimage width
]);
2623 SetFloat(slots
+ 2, (float)[scimage height
]);
2624 SetObject(receiver
, object
);
2632 * Currently only cache the CIKernel object + install a finalizer on it
2634 int cachePyrKernel(VMGlobals
*g
, PyrObject
* kernelObject
)
2636 NSString
* kernelCmd
= nsStringFromSlot(kernelObject
->slots
+0);
2638 post("Error: Kernel string command does not seem valid !\n");
2642 id kernel
= [CIKernel kernelsWithString
:kernelCmd
];
2644 post("Error: Failed creating valid Kernel from shader string !!\n");
2648 // Create the Kernel
2649 kernel
= [(NSArray
*)kernel objectAtIndex
:0];
2651 post("Error: Failed retrieving valid CIKernel !");
2656 if( !IsNil(kernelObject
->slots
+4) ) {
2657 id current
= (id)slotRawPtr(&kernelObject
->slots
[4]);
2662 SetPtr(kernelObject
->slots
+4, kernel
);
2664 if( IsNil(kernelObject
->slots
+5) ) {
2666 post("install finalizer scimagekernel (%p)\n", kernelObject
);
2668 InstallFinalizer(g
, kernelObject
, 5, FinalizeSCImageKernelObject
);
2671 post("caching scimagekernel (%p)\n", kernelObject
);
2676 int prSCImageKernel_Compile(struct VMGlobals
*g
, int numArgsPushed
);
2677 int prSCImageKernel_Compile(struct VMGlobals
*g
, int numArgsPushed
)
2679 PyrSlot
* receiver
= g
->sp
;
2680 return cachePyrKernel(g
, slotRawObject(receiver
));
2684 * This function is intended to apply a specific CIKernel to the image
2685 * Still experimental
2687 int prSCImageFilter_ApplyKernel(struct VMGlobals
*g
, int numArgsPushed
);
2688 int prSCImageFilter_ApplyKernel(struct VMGlobals
*g
, int numArgsPushed
)
2690 PyrSlot
*receiver
= g
->sp
- 3;
2691 PyrSlot
*kernelSlot
= g
->sp
- 2;
2692 PyrSlot
*cropRegionSlot
= g
->sp
- 1;
2693 PyrSlot
*inPlace
= g
->sp
;
2695 PyrSlot
*argumentSlot
;
2696 SCImage
*newSCImage
=nil;
2698 PyrObject
*kernelObject
=nil;
2699 CIKernel
*kernel
=nil;
2708 scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2714 [scimage setAccelerated
:YES
];
2715 CIFilter
* ciFilter
= [[CIFilter
new]autorelease
];
2717 ///// Setting and caching the Kernel Object
2718 kernelObject
= slotRawObject(kernelSlot
);
2719 if(IsNil(kernelObject
->slots
+4)) {
2720 err
= cachePyrKernel(g
, kernelObject
);
2723 argumentSlot
= kernelObject
->slots
+1;
2724 kernel
= (CIKernel
*)(slotRawPtr(&kernelObject
->slots
[4]));
2728 // Get the extent of the image
2729 CGRect extent
= [[scimage ciimage
]extent
];
2731 #if SCIMAGE_FILTER_DEBUG
2732 NSLog(@
"SCImageFilter: CIKernel created Successfully !");
2734 // Setting the Argument Array + PyrObject->Cocoa conversion
2737 You can pass the following types to a kernel routine:
2739 Requires a CISampler object when applied. // directly added in SCApp
2741 A qualifier for a sampler type.
2742 float, vec2, vec3, vec4:
2743 Requires an NSNumber or CIVector.
2745 A color that will be matched to the CIContext working color space when passed into the program.
2746 It requires a CIColor object when applied. To the kernel program it appears to be a vec4 type in premultiplied RGBA format.
2749 NSMutableArray
* arguments
= [NSMutableArray arrayWithCapacity
:16];
2751 post("Error: memory error ? allocation failed for NSMutableArray. applying Kernel aborted !");
2755 #if SCIMAGE_FILTER_DEBUG
2756 NSLog(@
"SCImageFilter: CIKernel setting Arguments !");
2758 // set all the arguments
2759 if( !IsNil(argumentSlot
) ) { // iterate through all the arguments
2760 PyrObject
* pyrArray
= slotRawObject(argumentSlot
);
2761 int size
= pyrArray
->size
;
2762 for(int i
=0; i
< size
; ++i
) {
2763 id object
= nsciObjectFromSlot(pyrArray
->slots
+i
, NULL
, NULL
);
2765 [arguments addObject
:object
];
2768 return errFailed
; // Kernels require no bad arguments
2772 // Create the Option Dictionary that contains additional info about final rendering
2773 // kCIApplyOptionDefinition : DOD of image
2774 // kCIApplyOptionExtent : size of the resulting image
2775 NSMutableDictionary
* dictionary
= [[[NSDictionary dictionary
] mutableCopy
] autorelease
];
2778 setValue
:[[scimage ciimage
] definition
] // better to pass directly the filterShape
2779 forKey
:kCIApplyOptionDefinition
2782 // Set the Extent of the result image if one is specified
2784 if(!IsNil(maxBounds)) {
2786 err = slotGetNSRect(maxBounds, (NSRect*)&maxRect);
2788 [dictionary setValue:
2789 [NSArray arrayWithObjects:
2790 [NSNumber numberWithFloat:maxRect.origin.x], // x
2791 [NSNumber numberWithFloat:maxRect.origin.y], // y
2792 [NSNumber numberWithFloat:maxRect.size.width], // w
2793 [NSNumber numberWithFloat:maxRect.size.height] // h
2796 forKey:kCIApplyOptionExtent
2801 #if SCIMAGE_FILTER_DEBUG
2802 NSLog(@
"SCImageFilter: CIKernel created Options successfully !");
2807 ciimage
= [ciFilter apply
:kernel arguments
:arguments options
:dictionary
];
2809 // if the rect is not infinite :
2810 // 1 - crop the image if a cropRegion is specified
2811 // 2 - translate the image to align origin of extent with coordindate origin of image (0,0)
2813 if(IsNil(cropRegionSlot
)) {
2814 cropRegion
= OutsetRect(extent
, floorf((SCCIIMAGE_MAX_WIDTH
- extent.size.width
) * 0.5), floorf((SCCIIMAGE_MAX_HEIGHT
- extent.size.height
) * 0.5));
2816 err
= slotGetNSRect(cropRegionSlot
, (NSRect
*)&cropRegion
);
2820 ciimage
= CropAndCenterCIImage(ciimage
, extent
, &cropRegion
);
2822 destExtent
= [ciimage extent
];
2824 #if SCIMAGE_FILTER_DEBUG
2825 NSLog(@
"SCImageFilter: applied Kernel Successfully !");
2828 // Setting the PyrSlot
2829 PyrObject
* receiverObj
;
2832 if( CGSizeEqualToSize(extent.size
, destExtent.size
) ) {
2833 #if SCIMAGE_MAC_OS_10_5
2834 [[scimage accumulator
] setImage
:ciimage
];
2836 [scimage
->_ciimage release
];
2837 scimage
->_ciimage
= [ciimage retain
];
2839 [scimage setShouldSyncBitmap
:YES
]; // invalidates bitmap
2842 NSLog(@
"CIKernel different size returned");
2843 receiverObj
= slotRawObject(receiver
);
2848 receiverObj
= newPyrSCImage(g
);
2851 #if SCIMAGE_FILTER_DEBUG
2852 NSLog(@
"SCImageFilter: Creating New SCImage Class");
2855 newSCImage
= [[SCImage alloc
]initWithCIImage
:ciimage extent
:destExtent format
:[scimage format
]];
2857 PyrSlot
*slots
= receiverObj
->slots
;
2858 [(id)slotRawPtr(slots
) release
];
2860 SetPtr(slots
+ 0, newSCImage
);
2861 SetFloat(slots
+ 1, destExtent.size.width
);
2862 SetFloat(slots
+ 2, destExtent.size.height
);
2864 if(receiverObj
!= slotRawObject(receiver
)) {
2865 SetObject(receiver
, receiverObj
);
2868 @catch ( NSException
*e
)
2870 //if([[e name]isEqualToString: @"CIKernelMissingArgument"])
2871 post("Error: %s\n", [[NSString stringWithFormat
:@
"%@ %@", @
"SCImageKernel", e
]UTF8String
]);
2878 int prSCImageFilter_GetAttributeMinMax(struct VMGlobals
*g
, int numArgsPushed
)
2880 PyrSlot
*receiver
= g
->sp
- 2;
2881 PyrSlot
*filterAttributeSlot
= g
->sp
- 1;
2882 PyrSlot
*returnedArraySlot
= g
->sp
;
2885 ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(slotRawObject(receiver
)->slots
+0)]; // filter name
2886 if(!ciFilter
) return errFailed
;
2888 NSDictionary
* attrDict
= [ciFilter attributes
];
2889 NSString
*key
= nsStringFromSlot(filterAttributeSlot
);
2892 #if SCIMAGE_FILTER_DEBUG
2893 NSLog(@
"Checking for CIFilter MinMax of attribute: %@", key
);
2902 const char* cStr
= [key cStringUsingEncoding
:NSASCIIStringEncoding
];
2903 attribute
= [attrDict objectForKey
: [NSString stringWithFormat
:@
"input%c%s", toupper(*cStr
), cStr
+1]];
2905 post("SCImageFilter : no attributes named %s found !\n", [key UTF8String
]);
2911 PyrObject
* pyrArray
= slotRawObject(returnedArraySlot
); // should be an array of size 3
2912 NSString
* attrType
= [attribute objectForKey
:kCIAttributeType
];
2915 minmax
[0] = [attribute objectForKey
: kCIAttributeSliderMin
] ?
[attribute objectForKey
: kCIAttributeSliderMin
] : [attribute objectForKey
: kCIAttributeMin
];
2916 minmax
[1] = [attribute objectForKey
: kCIAttributeSliderMax
] ?
[attribute objectForKey
: kCIAttributeSliderMax
] : [attribute objectForKey
: kCIAttributeMax
];
2917 minmax
[2] = [attribute objectForKey
: kCIAttributeDefault
];
2919 if(!minmax
[0] && !minmax
[1] && !minmax
[2]){ // if no slider min or slider max or default - set to nil directly
2925 if(attrType
== kCIAttributeTypeBoolean
)
2927 SetFalse(pyrArray
->slots
+0);
2928 SetTrue(pyrArray
->slots
+1);
2929 SetBool(pyrArray
->slots
+2, ([ minmax
[2] floatValue
] > 0.f
));
2932 attrType
== kCIAttributeTypeAngle || attrType
== kCIAttributeTypeDistance ||
2933 attrType
== kCIAttributeTypeScalar || attrType
== kCIAttributeTypeTime
2937 SetFloat(pyrArray
->slots
+0, [minmax
[0] doubleValue
]);
2939 SetNil(pyrArray
->slots
+0);
2942 SetFloat(pyrArray
->slots
+1, [minmax
[1] doubleValue
]);
2944 SetNil(pyrArray
->slots
+1);
2947 SetFloat(pyrArray
->slots
+2, [minmax
[2] doubleValue
]);
2949 SetNil(pyrArray
->slots
+1);
2951 else if( attrType
== kCIAttributeTypePosition || attrType
== kCIAttributeTypeOffset
)
2954 PyrObject
* vector
[3];
2955 for(int i
=0; i
< 3; ++i
) {
2957 SetNil(pyrArray
->slots
+i
); continue;
2959 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 2, 0, true);
2960 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2961 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2962 vector
[i
]->size
= 2;
2963 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2964 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
2967 else if( attrType
== kCIAttributeTypePosition3
)
2970 PyrObject
* vector
[3];
2971 for(int i
=0; i
< 3; ++i
) {
2973 SetNil(pyrArray
->slots
+i
); continue;
2975 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 3, 0, true);
2976 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2977 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2978 SetFloat( vector
[i
]->slots
+2, [ (CIVector
*)minmax
[i
] Z
]);
2979 vector
[i
]->size
= 3;
2980 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2981 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
2984 else if( attrType
== kCIAttributeTypeRectangle
)
2987 PyrObject
* vector
[3];
2988 for(int i
=0; i
< 3; ++i
) {
2990 SetNil(pyrArray
->slots
+i
); continue;
2992 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 4, 0, true);
2993 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2994 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2995 SetFloat( vector
[i
]->slots
+2, [ (CIVector
*)minmax
[i
] Z
]);
2996 SetFloat( vector
[i
]->slots
+3, [ (CIVector
*)minmax
[i
] W
]);
2997 vector
[i
]->size
= 4;
2998 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2999 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
3002 else if( attrType
== kCIAttributeTypeOpaqueColor
)
3005 PyrObject
* vector
[3];
3006 for(int i
=0; i
< 3; ++i
) {
3007 vector
[i
] = ::instantiateObject(g
->gc
, s_color
->u.classobj
, 0, false, true);
3008 SetFloat( vector
[i
]->slots
+0, (double)[ (CIColor
*)minmax
[i
] red
]);
3009 SetFloat( vector
[i
]->slots
+1, (double)[ (CIColor
*)minmax
[i
] green
]);
3010 SetFloat( vector
[i
]->slots
+2, (double)[ (CIColor
*)minmax
[i
] blue
]);
3011 SetFloat( vector
[i
]->slots
+3, (double)[ (CIColor
*)minmax
[i
] alpha
]);
3012 SetObject(pyrArray
->slots
+i
, vector
[i
]);
3013 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
3022 SetObject(receiver
, pyrArray
);
3026 // SetNil(receiver);
3030 int prSCImageFilter_Attributes(struct VMGlobals
*g
, int numArgsPushed
);
3031 int prSCImageFilter_Attributes(struct VMGlobals
*g
, int numArgsPushed
)
3033 PyrSlot
*receiver
= g
->sp
- 1;
3034 PyrSlot
*filterNameSlot
= g
->sp
;
3037 filter
= [CIFilter filterWithName
: nsStringFromSlot(filterNameSlot
)];
3041 NSDictionary
* attr
= [filter attributes
];
3042 NSArray
*inputKeys
= [filter inputKeys
];
3044 NSEnumerator
* e
= [inputKeys objectEnumerator
];
3048 maxsize
= [inputKeys count
] * 2;
3049 if([inputKeys containsObject
:@
"inputImage"]) {
3050 maxsize
-= 2; // remove the inputImage
3052 PyrSymbolArray
* returnObject
= newPyrSymbolArray(g
->gc
, maxsize
, 0, true);
3053 returnObject
->size
= maxsize
;
3056 while( (key
= [e nextObject
]) )
3058 if(i
>= maxsize
) return errNone
; // in case
3059 if(![key isEqualToString
:@
"inputImage"]) { // we do not need it
3060 cStr
= [[key substringFromIndex
:5] cStringUsingEncoding
:NSASCIIStringEncoding
]; // remove the 'input'
3061 returnObject
->symbols
[i
++] = getsym([ [NSString stringWithFormat
: @
"%c%s", tolower(*cStr
), (cStr
+ 1)] UTF8String
]);
3062 returnObject
->symbols
[i
++] = getsym([ [ [ attr objectForKey
: key
] objectForKey
: @
"CIAttributeClass" ] UTF8String
]);
3066 SetObject(receiver
, returnObject
);
3071 int prSCImageFilter_NamesInCategory(struct VMGlobals
*g
, int numArgsPushed
);
3072 int prSCImageFilter_NamesInCategory(struct VMGlobals
*g
, int numArgsPushed
)
3074 PyrSlot
*receiver
, *category
, *returnArray
;
3078 returnArray
= g
->sp
;
3079 category
= g
->sp
- 1;
3080 receiver
= g
->sp
- 2;
3082 //PyrObject *returnObject = slotRawObject(returnArray);
3083 //int maxsize = MAXINDEXSIZE(returnObject);
3085 if (!IsSym(category
)) return errWrongType
;
3087 type
= nsStringFromSlot(category
);
3088 if(!type
) return errFailed
;
3090 array
= [CIFilter filterNamesInCategory
:type
];
3091 if(!array
) return errFailed
;
3093 int maxsize
= [array count
];
3094 PyrSymbolArray
* returnObject
= newPyrSymbolArray(g
->gc
, maxsize
, 0, true);
3095 returnObject
->size
= maxsize
;
3098 NSEnumerator
*e
= [array objectEnumerator
];
3101 while( (type
= [e nextObject
]) )
3103 if(i
>= maxsize
) break; // in case
3104 returnObject
->symbols
[i
] = getsym([type UTF8String
]);
3108 SetObject(receiver
, returnObject
);
3113 #pragma mark - InitSCImagePrims
3115 void initSCImagePrimitives()
3119 s_scimage
= getsym("SCImage");
3120 s_scfilter
= getsym("SCImageFilter");
3121 s_scimagekernel
= getsym("SCImageKernel");
3124 NSLog(@
"---- SCIMAGE: Init Primitives ----");
3125 NSLog(@
"---- SCIMAGE: Using Mac OS 10.%c Version ----", (SCIMAGE_MAC_OS_10_5
== 1) ?
'5' : '4');
3128 if(!gCIFilterPlugInsLoaded
) {
3130 NSLog(@
"---- SCIMAGE: Loading CIFilter PlugIns ----");
3132 [CIPlugIn loadAllPlugIns
];
3133 gCIFilterPlugInsLoaded
= YES
;
3136 base
= nextPrimitiveIndex();
3140 definePrimitive(base
, index
++, "_SCImage_New", prSCImage_New
, 4, 0);
3141 //definePrimitive(base, index++, "_SCImage_NewFromFile", prSCImage_NewFromFile, 2, 0); // use only URL
3142 definePrimitive(base
, index
++, "_SCImage_NewFromURL", prSCImage_NewFromURL
, 2, 0);
3143 definePrimitive(base
, index
++, "_SCImage_WriteToFile", prSCImage_WriteToFile
, 3, 0);
3144 definePrimitive(base
, index
++, "_SCImage_Free", prSCImage_Free
, 1, 0);
3145 definePrimitive(base
, index
++, "_SCImage_setSize", prSCImage_setSize
, 3, 0);
3146 definePrimitive(base
, index
++, "_SCImage_setScalesWhenResized", prSCImage_setScalesWhenResized
, 2, 0);
3147 definePrimitive(base
, index
++, "_SCImage_scalesWhenResized", prSCImage_scalesWhenResized
, 1, 0);
3148 definePrimitive(base
, index
++, "_SCImage_DrawAtPoint", prSCImage_DrawAtPoint
, 5, 0);
3149 definePrimitive(base
, index
++, "_SCImage_DrawInRect", prSCImage_DrawInRect
, 5, 0);
3150 definePrimitive(base
, index
++, "_SCImage_tileInRect", prSCImage_TileInRect
, 5, 0);
3151 definePrimitive(base
, index
++, "_SCImage_lockFocus", prSCImage_lockFocus
, 1, 0);
3152 definePrimitive(base
, index
++, "_SCImage_unlockFocus", prSCImage_unlockFocus
, 1, 0);
3153 definePrimitive(base
, index
++, "_SCImage_recache", prSCImage_recache
, 1, 0);
3154 definePrimitive(base
, index
++, "_SCImage_setPixelAt", prSCImage_setPixelAt
, 4, 0);
3155 definePrimitive(base
, index
++, "_SCImage_getPixelAt", prSCImage_pixelAt
, 3, 0);
3156 definePrimitive(base
, index
++, "_SCImage_setColorAt", prSCImage_setColorAt
, 4, 0);
3157 definePrimitive(base
, index
++, "_SCImage_getColorAt", prSCImage_getColorAt
, 3, 0);
3158 definePrimitive(base
, index
++, "_SCImage_setAccelerated", prSCImage_setAccelerated
, 2, 0);
3159 definePrimitive(base
, index
++, "_SCImage_isAccelerated", prSCImage_isAccelerated
, 1, 0);
3160 definePrimitive(base
, index
++, "_SCImage_loadPixels", prSCImage_loadPixels
, 4, 0);
3161 definePrimitive(base
, index
++, "_SCImage_updatePixels", prSCImage_updatePixels
, 3, 0);
3162 definePrimitive(base
, index
++, "_SCImage_updatePixelsInRect", prSCImage_updatePixelsInRect
, 4, 0);
3163 definePrimitive(base
, index
++, "_SCImage_interpolation", prSCImage_interpolation
, 1, 0);
3164 definePrimitive(base
, index
++, "_SCImage_setInterpolation", prSCImage_setInterpolation
, 2, 0);
3165 definePrimitive(base
, index
++, "_SCImage_sync", prSCImage_sync
, 1, 0);
3166 definePrimitive(base
, index
++, "_SCImage_fromWindowRect", prSCImage_imageFromSCWindowRect
, 3, 0);
3168 // image Filter - experimental for now
3169 definePrimitive(base
, index
++, "_SCImageFilter_NamesInCategory", prSCImageFilter_NamesInCategory
, 3, 0);
3170 definePrimitive(base
, index
++, "_SCImageFilter_Attributes", prSCImageFilter_Attributes
, 2, 0);
3171 definePrimitive(base
, index
++, "_SCImageFilter_Apply", prSCImageFilter_Apply
, 4, 0);
3172 definePrimitive(base
, index
++, "_SCImageFilter_ApplyMultiple", prSCImageFilter_ApplyMultiple
, 5, 0);
3173 definePrimitive(base
, index
++, "_SCImageFilter_GetAttributeMinMax", prSCImageFilter_GetAttributeMinMax
, 3, 0);
3174 definePrimitive(base
, index
++, "_SCImageFilter_ApplyKernel", prSCImageFilter_ApplyKernel
, 4, 0);
3175 definePrimitive(base
, index
++, "_SCImageKernel_Compile", prSCImageKernel_Compile
, 1, 0);
3181 void initSCImagePrimitives()
3183 // SCImage not supported for os version < 10.4...