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 stringWithCString
:path encoding
:[NSString defaultCStringEncoding
]];
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 SetBool(receiver
, result ?
true : false); // inform the user if save is ok
1243 int prSCImage_interpolation(struct VMGlobals
*g
, int numArgsPushed
);
1244 int prSCImage_interpolation(struct VMGlobals
*g
, int numArgsPushed
)
1246 if (!g
->canCallOS
) return errCantCallOS
;
1248 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1249 SCImage
*image
= (SCImage
*)slotRawPtr(&slotRawObject(receiver
)->slots
[0]);
1253 SetInt(receiver
, [image imageInterpolation
]); //
1257 int prSCImage_setInterpolation(struct VMGlobals
*g
, int numArgsPushed
);
1258 int prSCImage_setInterpolation(struct VMGlobals
*g
, int numArgsPushed
)
1260 if (!g
->canCallOS
) return errCantCallOS
;
1262 PyrSlot
*receiver
= g
->sp
- 1; // SCImage
1263 PyrSlot
*a
= g
->sp
; // interpolation
1265 int interp
= NSImageInterpolationDefault
;
1267 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1271 if(slotIntVal(a
, &interp
) != errNone
)
1274 [image setImageInterpolation
:(NSImageInterpolation
)interp
];
1279 int prSCImage_Free(struct VMGlobals
*g
, int numArgsPushed
);
1280 int prSCImage_Free(struct VMGlobals
*g
, int numArgsPushed
)
1282 if (!g
->canCallOS
) return errCantCallOS
;
1284 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1285 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1290 NSLog(@
"Releasing SCImage (%p)", image
);
1294 SetNil(slotRawObject(receiver
)->slots
+ 0); // ensure slot is NIL
1295 SetNil(slotRawObject(receiver
)->slots
+ 1); // not only the pointer
1296 SetNil(slotRawObject(receiver
)->slots
+ 2);
1301 int prSCImage_sync(struct VMGlobals
*g
, int numArgsPushed
);
1302 int prSCImage_sync(struct VMGlobals
*g
, int numArgsPushed
)
1304 if (!g
->canCallOS
) return errCantCallOS
;
1306 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1307 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1308 [image syncRepresentations
]; // force sync
1311 NSLog(@
"SCImage (%p) Force Sync", image
);
1316 int prSCImage_setSize(struct VMGlobals
*g
, int numArgsPushed
);
1317 int prSCImage_setSize(struct VMGlobals
*g
, int numArgsPushed
)
1319 if (!g
->canCallOS
) return errCantCallOS
;
1321 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1322 PyrSlot
*a
= g
->sp
- 1; // width
1323 PyrSlot
*b
= g
->sp
; // height
1327 err
= slotFloatVal(a
, &width
);
1328 if (err
) return err
;
1331 err
= slotFloatVal(b
, &height
);
1332 if (err
) return err
;
1334 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1335 [image setSize
: NSMakeSize(width
, height
)];
1337 SetFloat(slotRawObject(receiver
)->slots
+ 1, width
);
1338 SetFloat(slotRawObject(receiver
)->slots
+ 2, height
);
1343 int prSCImage_setScalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
);
1344 int prSCImage_setScalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
)
1346 if (!g
->canCallOS
) return errCantCallOS
;
1348 PyrSlot
*receiver
= g
->sp
- 1; // instance of SCImage
1349 PyrSlot
*a
= g
->sp
; // bool flag
1351 BOOL flag
= IsTrue(a
);
1352 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1353 [image setScalesWhenResized
: flag
];
1358 int prSCImage_scalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
);
1359 int prSCImage_scalesWhenResized(struct VMGlobals
*g
, int numArgsPushed
)
1361 if (!g
->canCallOS
) return errCantCallOS
;
1363 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1365 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1366 SetBool(receiver
, [image scalesWhenResized
]);
1370 int prSCImage_DrawAtPoint(struct VMGlobals
*g
, int numArgsPushed
);
1371 int prSCImage_DrawAtPoint(struct VMGlobals
*g
, int numArgsPushed
)
1373 if (!g
->canCallOS
) return errCantCallOS
;
1375 PyrSlot
*d
= g
->sp
; // fraction
1376 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1377 PyrSlot
*b
= g
->sp
- 2; // fromRect
1378 PyrSlot
*a
= g
->sp
- 3; // point
1379 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1384 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1386 return errNone
; // just do nothing
1388 if(![image ciimage
])
1390 NSLog(@
"SCImage CIImage is nil !");
1394 err
= slotGetPoint(a
, &nsPoint
);
1395 if (err
) return err
;
1399 rect
= NSMakeRect(0.0,0.0,[image size
].width
,[image size
].height
);
1401 err
= slotGetNSRect(b
, &rect
);
1402 if (err
) return err
;
1406 err
= slotIntVal(c
, &co
);
1407 if (err
) return err
;
1410 err
= slotFloatVal(d
, &fraction
);
1411 if (err
) return err
;
1413 // [image drawInSCRect:NSMakeRect(nsPoint.x, nsPoint.y, [image size].width, [image size].height) fromRect:rect operation:(NSCompositingOperation)co fraction:fraction];
1414 [image drawInSCRect
:NSMakeRect(nsPoint.x
, nsPoint.y
, rect.size.width
, rect.size.height
) fromRect
:rect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1419 int prSCImage_DrawInRect(struct VMGlobals
*g
, int numArgsPushed
);
1420 int prSCImage_DrawInRect(struct VMGlobals
*g
, int numArgsPushed
)
1422 if (!g
->canCallOS
) return errCantCallOS
;
1424 PyrSlot
*d
= g
->sp
; // fraction
1425 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1426 PyrSlot
*b
= g
->sp
- 2; // fromRect
1427 PyrSlot
*a
= g
->sp
- 3; // rect
1428 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1431 NSRect rect
, fromRect
;
1433 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1438 err
= slotGetNSRect(a
, &rect
);
1439 if (err
) return err
;
1442 fromRect
= NSMakeRect(0.0,0.0,[image size
].width
,[image size
].height
); // CIImage does not support NSZeroRect as argument
1444 err
= slotGetNSRect(b
, &fromRect
);
1445 if (err
) return err
;
1449 err
= slotIntVal(c
, &co
);
1450 if (err
) return err
;
1453 err
= slotFloatVal(d
, &fraction
);
1454 if (err
) return err
;
1456 [image drawInSCRect
:rect fromRect
:fromRect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1461 int prSCImage_TileInRect(struct VMGlobals
*g
, int numArgsPushed
);
1462 int prSCImage_TileInRect(struct VMGlobals
*g
, int numArgsPushed
)
1464 if (!g
->canCallOS
) return errCantCallOS
;
1466 PyrSlot
*d
= g
->sp
; // fraction
1467 PyrSlot
*c
= g
->sp
- 1; // compositing operation
1468 PyrSlot
*b
= g
->sp
- 2; // fromRect
1469 PyrSlot
*a
= g
->sp
- 3; // rect
1470 PyrSlot
*receiver
= g
->sp
- 4; // instance of SCImage
1472 NSRect nsFromRect
, nsRect
;
1477 if(IsNil(slotRawObject(receiver
)->slots
+0))
1480 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1485 err
= slotGetNSRect(a
, &nsRect
);
1486 if (err
) return err
;
1488 err
= slotGetNSRect(b
, &nsFromRect
);
1489 if (err
) return err
;
1491 err
= slotFloatVal(d
, &fraction
);
1492 if (err
) return err
;
1494 err
= slotIntVal(c
, &co
);
1495 if (err
) return err
;
1497 [image tileInSCRect
:nsRect fromRect
:nsFromRect operation
:(NSCompositingOperation
)co fraction
:fraction
];
1501 int prSCImage_lockFocus(struct VMGlobals
*g
, int numArgsPushed
);
1502 int prSCImage_lockFocus(struct VMGlobals
*g
, int numArgsPushed
)
1504 if (!g
->canCallOS
) return errCantCallOS
;
1506 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1507 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1508 // here we do not use the set flipped because it will create problem
1509 // if we draw on top of an already image loaded with URL and write it after
1510 // better to S(T(ctx)) directly so everything is fine now
1511 // and we can write it with no problem
1513 CGContextRef ctx
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
1514 CGContextSaveGState(ctx
);
1515 CGContextTranslateCTM(ctx
, 0, [image size
].height
);
1516 CGContextScaleCTM(ctx
, 1, -1.0f
);
1521 int prSCImage_unlockFocus(struct VMGlobals
*g
, int numArgsPushed
);
1522 int prSCImage_unlockFocus(struct VMGlobals
*g
, int numArgsPushed
)
1524 if (!g
->canCallOS
) return errCantCallOS
;
1526 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1527 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1528 // revert the coordinate system
1529 CGContextRef ctx
= (CGContextRef
)[[NSGraphicsContext currentContext
]graphicsPort
];
1530 CGContextRestoreGState(ctx
);
1532 [image unlockFocus
];
1537 int prSCImage_recache(struct VMGlobals
*g
, int numArgsPushed
);
1538 int prSCImage_recache(struct VMGlobals
*g
, int numArgsPushed
)
1540 if (!g
->canCallOS
) return errCantCallOS
;
1542 PyrSlot
*receiver
= g
->sp
; // instance of SCImage
1544 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1549 // returns a premultipled alpha pixel as an uint32
1550 int prSCImage_pixelAt(struct VMGlobals
*g
, int numArgsPushed
);
1551 int prSCImage_pixelAt(struct VMGlobals
*g
, int numArgsPushed
)
1553 if (!g
->canCallOS
) return errCantCallOS
;
1555 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1556 PyrSlot
*xSlot
= g
->sp
- 1;
1557 PyrSlot
*ySlot
= g
->sp
;
1561 PixelData pixelAsArray
[4] = {0, 0, 0, 0};
1565 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1566 if(!image
) return errNone
;
1568 err
= slotIntVal(xSlot
, &x
);
1571 err
= slotIntVal(ySlot
, &y
);
1574 [image setAccelerated
:NO
];
1575 [image getPixel
:pixelAsArray atX
:x y
:y
];
1576 //SetInt(receiver, ((pixelAsArray[0] << 24) | (pixelAsArray[1] << 16) | (pixelAsArray[2] << 8) | pixelAsArray[3]));
1577 if( pixelAsArray
[3] == 0 ) { // avoid EXC_ARITHMETIC
1579 (pixelAsArray
[0] << 24) |
1580 (pixelAsArray
[1] << 16) |
1581 (pixelAsArray
[2] << 8)
1585 (COLOR_UNSCALE( pixelAsArray
[0], pixelAsArray
[3] ) << 24) |
1586 (COLOR_UNSCALE( pixelAsArray
[1], pixelAsArray
[3] ) << 16) |
1587 (COLOR_UNSCALE( pixelAsArray
[2], pixelAsArray
[3] ) << 8) |
1594 int prSCImage_setPixelAt(struct VMGlobals
*g
, int numArgsPushed
);
1595 int prSCImage_setPixelAt(struct VMGlobals
*g
, int numArgsPushed
)
1597 if (!g
->canCallOS
) return errCantCallOS
;
1599 PyrSlot
*receiver
= g
->sp
- 3; // instance of SCImage
1600 PyrSlot
*pixelSlot
= g
->sp
- 2;
1601 PyrSlot
*xSlot
= g
->sp
- 1;
1602 PyrSlot
*ySlot
= g
->sp
;
1604 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1610 PixelData pixelData
[4]={0, 0, 0, 0};
1612 err
= slotIntVal(pixelSlot
, (int*)&pixel
);
1615 err
= slotIntVal(xSlot
, &x
);
1618 err
= slotIntVal(ySlot
, &y
);
1621 [image setAccelerated
:NO
];
1623 pixelData
[0] = COLOR_SCALE(PIXEL_RED(pixel
), PIXEL_ALPHA(pixel
));
1624 pixelData
[1] = COLOR_SCALE(PIXEL_GREEN(pixel
), PIXEL_ALPHA(pixel
));
1625 pixelData
[2] = COLOR_SCALE(PIXEL_BLUE(pixel
), PIXEL_ALPHA(pixel
));
1626 pixelData
[3] = PIXEL_ALPHA(pixel
);
1628 [image setPixel
:pixelData atX
:x y
:y
];
1633 int prSCImage_setColorAt(struct VMGlobals
*g
, int numArgsPushed
);
1634 int prSCImage_setColorAt(struct VMGlobals
*g
, int numArgsPushed
)
1636 if (!g
->canCallOS
) return errCantCallOS
;
1638 PyrSlot
*receiver
= g
->sp
- 3; // instance of SCImage
1639 PyrSlot
*colorSlot
= g
->sp
- 2;
1640 PyrSlot
*xSlot
= g
->sp
- 1;
1641 PyrSlot
*ySlot
= g
->sp
;
1643 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1647 [image setAccelerated
:NO
];
1652 err
= slotColorVal(colorSlot
, &color
);
1655 err
= slotIntVal(xSlot
, &x
);
1658 err
= slotIntVal(ySlot
, &y
);
1662 setColor
:[NSColor colorWithCalibratedRed
:color.red green
:color.green blue
:color.blue alpha
:color.alpha
]
1670 int prSCImage_getColorAt(struct VMGlobals
*g
, int numArgsPushed
);
1671 int prSCImage_getColorAt(struct VMGlobals
*g
, int numArgsPushed
)
1673 if (!g
->canCallOS
) return errCantCallOS
;
1675 PyrSlot
*receiver
= g
->sp
- 2; // instance of SCImage
1676 PyrSlot
*xSlot
= g
->sp
- 1;
1677 PyrSlot
*ySlot
= g
->sp
;
1680 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1686 err
= slotIntVal(xSlot
, &x
);
1689 err
= slotIntVal(ySlot
, &y
);
1692 [image setAccelerated
:NO
];
1702 nsColor
= [nsColor colorUsingColorSpaceName
:NSCalibratedRGBColorSpace
];
1703 PyrObject
*color
= instantiateObject(g
->gc
, s_color
->u.classobj
, 0, false, true);
1704 PyrSlot
*slots
= color
->slots
;
1705 SetFloat(slots
+0, [nsColor redComponent
]);
1706 SetFloat(slots
+1, [nsColor greenComponent
]);
1707 SetFloat(slots
+2, [nsColor blueComponent
]);
1708 SetFloat(slots
+3, [nsColor alphaComponent
]);
1709 SetObject(receiver
, color
);
1715 int prSCImage_loadPixels(struct VMGlobals
*g
, int numArgsPushed
);
1716 int prSCImage_loadPixels(struct VMGlobals
*g
, int numArgsPushed
)
1718 if (!g
->canCallOS
) return errCantCallOS
;
1720 PyrSlot
*receiver
= g
->sp
- 3;
1721 PyrSlot
*pixelSlot
= g
->sp
- 2;
1722 PyrSlot
*regionSlot
= g
->sp
- 1;
1726 NSBitmapImageRep
*bitmap
;
1728 int height
, width
, y
=0, x
=0, startIndex
=0;
1732 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1737 size
= [image size
];
1739 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1740 if(pyrclass
!= class_int32array
) {
1741 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1745 slotIntVal(g
->sp
, &startIndex
);
1747 return errIndexOutOfRange
;
1749 PyrInt32Array
* allocatedPixelArray
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1751 bitmap
= [image bitmapRepresentation
];
1753 if(IsNil(regionSlot
)) {
1754 region
= NSIntegralRect(NSMakeRect(0.f
, 0.f
, [bitmap pixelsWide
], [bitmap pixelsHigh
]));
1756 if(slotGetNSRect(regionSlot
, ®ion
) != errNone
)
1757 return errWrongType
;
1758 region
= NSIntegralRect(region
);
1759 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
]) )
1760 return errIndexOutOfRange
;
1763 height
= region.size.height
;
1764 width
= region.size.width
;
1765 pixelsData
= (uint32
*)allocatedPixelArray
->i
+ startIndex
;
1766 PixelData pixel
[4]={0, 0, 0, 0};
1768 if((allocatedPixelArray
->size
- startIndex
) < ( height
* width
/** 4*/ ) ) {
1769 post("Error: pixel array is not of good size ! should be %i bytes long\n", height
* width
/** 4*/);
1770 return errIndexOutOfRange
;
1774 unsigned char alpha
;
1775 height
= height
+ region.origin.y
; //padding h and w to meet origin
1776 width
= width
+ region.origin.x
;
1777 for(y
=(int)region.origin.y
; y
< height
; y
++) {
1778 for(x
=(int)region.origin.x
; x
< width
; x
++) {
1780 // most of the unscale routines may be not as precise as we need
1781 // especially when dealing with CIImage <-> NSImage conversion...
1782 // it should be better to use vImage framework directly !
1784 [bitmap getPixel
:pixel atX
:x y
:y
];
1786 SET_PIXEL_RED ( *pixelsData
, COLOR_UNSCALE(pixel
[0], pixel
[3]) );
1787 SET_PIXEL_GREEN( *pixelsData
, COLOR_UNSCALE(pixel
[1], pixel
[3]) );
1788 SET_PIXEL_BLUE ( *pixelsData
, COLOR_UNSCALE(pixel
[2], pixel
[3]) );
1789 SET_PIXEL_ALPHA( *pixelsData
, pixel
[3]);
1791 SET_PIXEL_RED ( *pixelsData
, pixel
[0] );
1792 SET_PIXEL_GREEN( *pixelsData
, pixel
[1] );
1793 SET_PIXEL_BLUE ( *pixelsData
, pixel
[2] );
1794 SET_PIXEL_ALPHA( *pixelsData
, pixel
[3] );
1798 //bitmapData += bytesLeft;
1805 int prSCImage_updatePixels(struct VMGlobals
*g
, int numArgsPushed
);
1806 int prSCImage_updatePixels(struct VMGlobals
*g
, int numArgsPushed
)
1808 if (!g
->canCallOS
) return errCantCallOS
;
1810 PyrSlot
*receiver
= g
->sp
- 2;
1811 PyrSlot
*pixelSlot
= g
->sp
- 1;
1814 NSBitmapImageRep
*bitmap
;
1815 int width
, height
, bytesPerRow
, bytesLeft
, startIndex
=0, y
=0, x
=0;
1816 unsigned char *bitmapData
;
1818 PyrInt32Array
*pixels
;
1821 if(IsNil(pixelSlot
))
1824 slotIntVal(g
->sp
, &startIndex
);
1826 return errIndexOutOfRange
;
1828 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1834 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1835 if(pyrclass
!= class_int32array
) {
1836 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1840 pixels
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1842 bitmap
= [image bitmapRepresentation
];
1844 NSLog(@
"prSCImage_updatePixels failed retrieving valid NSBitmapImageRep...");
1848 width
= [bitmap pixelsWide
]; // RGBA
1849 height
= [bitmap pixelsHigh
];
1850 bytesPerRow
= [bitmap bytesPerRow
];
1851 bitmapData
= [bitmap bitmapData
];
1852 pixelsData
= (uint32
*)pixels
->i
+ startIndex
;
1853 bytesLeft
= bytesPerRow
- (width
*4);
1855 if( (pixels
->size
- startIndex
) < (int)(width
*height
/* *4 */)) {
1856 post("Error: pixel array is not of good size ! should be %i bytes long from index: %i\n", (int)(width
*height
/**4*/), startIndex
);
1857 return errIndexOutOfRange
;
1861 unsigned char alpha
;
1862 for(y
=0; y
< height
; ++y
) {
1863 for(x
=0; x
< width
; ++x
) {
1864 alpha
= PIXEL_ALPHA(*pixelsData
);
1865 *bitmapData
++ = COLOR_SCALE(PIXEL_RED(*pixelsData
), alpha
);
1866 *bitmapData
++ = COLOR_SCALE(PIXEL_GREEN(*pixelsData
), alpha
);
1867 *bitmapData
++ = COLOR_SCALE(PIXEL_BLUE(*pixelsData
), alpha
);
1868 *bitmapData
++ = alpha
;
1871 bitmapData
+= bytesLeft
;
1875 [image setShouldSyncCIImage
:YES
];
1881 int prSCImage_updatePixelsInRect(struct VMGlobals
*g
, int numArgsPushed
);
1882 int prSCImage_updatePixelsInRect(struct VMGlobals
*g
, int numArgsPushed
)
1884 if (!g
->canCallOS
) return errCantCallOS
;
1886 PyrSlot
*receiver
= g
->sp
- 3;
1887 PyrSlot
*pixelSlot
= g
->sp
- 2;
1888 PyrSlot
*rectSlot
= g
->sp
- 1;
1891 NSBitmapImageRep
*bitmap
;
1892 int width
, height
, bytesPerRow
, bytesLeft
, y
=0, x
=0, startIndex
=0, err
;
1893 unsigned char *bitmapData
;
1895 PyrInt32Array
*pixels
;
1899 if(IsNil(pixelSlot
))
1902 slotIntVal(g
->sp
, &startIndex
); // get the Array start index
1904 return errIndexOutOfRange
;
1906 image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1912 err
= slotGetNSRect(rectSlot
, &rect
);
1913 if (err
) return err
;
1914 rect
= NSIntegralRect(rect
);
1916 pyrclass
= slotRawObject(pixelSlot
)->classptr
;
1917 if(pyrclass
!= class_int32array
) {
1918 NSLog(@
"prSCImage_loadPixels array argument is not a PyrInt32Array !");
1922 pixels
= (PyrInt32Array
*)slotRawObject(pixelSlot
);
1923 bitmap
= [image bitmapRepresentation
];
1925 NSLog(@
"prSCImage_updatePixels failed retrieving valid NSBitmapImageRep...");
1926 return errIndexOutOfRange
;
1929 width
= [bitmap pixelsWide
]; // RGBA
1930 height
= [bitmap pixelsHigh
];
1931 bytesPerRow
= [bitmap bytesPerRow
];
1932 bitmapData
= [bitmap bitmapData
];
1933 pixelsData
= (uint32
*)pixels
->i
+ startIndex
;
1936 rect.origin.x
= sc_max(rect.origin.x
, 0); // negative idx not allowed
1937 rect.origin.y
= sc_max(rect.origin.y
, 0); // negative idx not allowed
1938 rect.size.width
= sc_min(rect.size.width
, width
); // clip to image width max
1939 rect.size.height
= sc_min(rect.size.height
, height
); // clip to image height max
1941 // what is the best :
1942 // 1 - clipping + wrapping thus giving strange results ?
1943 // 2 - throw an error ?
1944 // just throw an error for now -> so no strange results and no scratching head... :)
1945 // zero tolerance >:^(
1947 ((rect.origin.x
+ rect.size.width
) > width
) ||
1948 ((rect.origin.y
+ rect.size.height
) > height
)
1950 return errIndexOutOfRange
;
1952 bytesLeft
= (bytesPerRow
- (rect.size.width
* 4));
1953 if( (pixels
->size
- startIndex
) < (int)(rect.size.width
* rect.size.height
)) {
1954 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
);
1959 unsigned char alpha
;
1960 bitmapData
+= ((int)rect.origin.y
* bytesPerRow
) + ((int)rect.origin.x
* 4);
1961 for(y
=0; y
< rect.size.height
; ++y
) {
1962 for(x
=0; x
< rect.size.width
; ++x
) {
1963 alpha
= PIXEL_ALPHA(*pixelsData
);
1964 *bitmapData
++ = COLOR_SCALE(PIXEL_RED(*pixelsData
), alpha
);
1965 *bitmapData
++ = COLOR_SCALE(PIXEL_GREEN(*pixelsData
), alpha
);
1966 *bitmapData
++ = COLOR_SCALE(PIXEL_BLUE(*pixelsData
), alpha
);
1967 *bitmapData
++ = alpha
;
1970 bitmapData
+= bytesLeft
;
1974 [image setShouldSyncCIImage
:YES
];
1979 int prSCImage_isAccelerated(struct VMGlobals
*g
, int numArgsPushed
);
1980 int prSCImage_isAccelerated(struct VMGlobals
*g
, int numArgsPushed
)
1982 if (!g
->canCallOS
) return errCantCallOS
;
1984 PyrSlot
*receiver
= g
->sp
;
1986 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
1992 SetBool(receiver
, [image isAccelerated
]);
1997 int prSCImage_setAccelerated(struct VMGlobals
*g
, int numArgsPushed
);
1998 int prSCImage_setAccelerated(struct VMGlobals
*g
, int numArgsPushed
)
2000 if (!g
->canCallOS
) return errCantCallOS
;
2002 PyrSlot
*receiver
= g
->sp
- 1;
2003 PyrSlot
*yornSlot
= g
->sp
;
2005 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2011 [image setAccelerated
:IsTrue(yornSlot
)];
2018 // Currently it grabs a portion from the scgraphview
2019 // user should here pass the ABSOLUTE view bounds or a specific rect
2020 int prSCImage_imageFromSCWindowRect(struct VMGlobals
*g
, int numArgsPushed
);
2021 int prSCImage_imageFromSCWindowRect(struct VMGlobals
*g
, int numArgsPushed
)
2023 if (!g
->canCallOS
) return errCantCallOS
;
2025 PyrSlot
*receiver
= g
->sp
- 2; // SCImage class
2026 PyrSlot
*a
= g
->sp
- 1; // SCWindow instance
2027 PyrSlot
*b
= g
->sp
; // SCRect instance - portion in the SCGraphView
2030 NSBitmapImageRep
*nsbitmap
= nil;
2031 NSImage
*nsimage
= nil;
2032 SCGraphView
*nsview
= nil;
2033 SCImage
*scimage
= nil;
2036 if(!IsPtr(&slotRawObject(a
)->slots
[0])) {
2040 nsview
= (SCGraphView
*)slotRawPtr(&slotRawObject(a
)->slots
[0]); // get SCGraphView instance
2041 err
= slotGetNSRect(b
, &rect
);
2046 nsbitmap
= [[NSBitmapImageRep alloc
]initWithFocusedViewRect
:rect
];
2047 [nsview unlockFocus
];
2051 post("Error: Failed getting valid image from SCView !\n");
2055 PyrObject
* object
= NULL
;
2058 [[NSImage alloc
]initWithSize
:NSMakeSize((float)[nsbitmap pixelsWide
], (float)[nsbitmap pixelsHigh
])];
2061 post("Error: Failed creating valid NSImage !\n");
2066 [nsimage addRepresentation
:nsbitmap
];
2068 scimage
= [[SCImage alloc
]initWithNSImage
:nsimage
];
2070 post("Error: Failed creating valid SCImage !\n");
2075 // Instantiate and set the SCObject
2076 object
= newPyrSCImage(g
);
2078 post("Error: Failed creating valid SCImage class !");
2084 SetPtr(object
->slots
+ 0, scimage
);
2085 SetFloat(object
->slots
+ 1, (float)[nsbitmap pixelsWide
]);
2086 SetFloat(object
->slots
+ 2, (float)[nsbitmap pixelsHigh
]);
2087 SetObject(receiver
, object
);
2091 if(nsimage
) [nsimage release
];
2092 if(nsbitmap
) [nsbitmap release
];
2097 #pragma mark --- SCImageFilter Primitive Set
2099 PyrClass
* slotArrayGetCommonClass(PyrObject
* array
)
2101 int size
= array
->size
;
2105 PyrClass
*commonClass
= slotRawObject(&array
->slots
[0])->classptr
;
2107 for(int i
=1; i
< size
; ++i
) {
2108 if(slotRawObject(&array
->slots
[0])->classptr
!= commonClass
)
2115 BOOL nsClassIsKindOfClass(Class currentClass
, Class match
);
2116 BOOL nsClassIsKindOfClass(Class currentClass
, Class match
)
2118 if(currentClass
== match
)
2122 while( (superClass
= class_getSuperclass(currentClass
)) ) {
2123 if(superClass
== match
)
2130 id ciVectorFromSlot(PyrObject
* slot
);
2131 id ciVectorFromSlot(PyrObject
* slot
)
2133 ColorData values
[4] = {0.f
, 0.f
, 0.f
, 0.f
};
2134 int size
= slot
->size
, err
;
2136 for (int i
=0; i
< size
; ++i
) {
2138 err
= slotFloatVal(slot
->slots
+ i
, &val
);
2143 return [CIVector vectorWithValues
:values count
:(size_t)4];
2146 int safeSlotFloatVal(PyrSlot
* slot
, float* value
);
2147 int safeSlotFloatVal(PyrSlot
* slot
, float* value
)
2153 return slotFloatVal(slot
, value
);
2156 CGRect
OutsetRect(CGRect r
, const float dx
, const float dy
)
2158 CGRect ret
= CGRectMake(r.origin.x
- dx
, r.origin.y
- dy
, r.size.width
+ dx
+ dx
, r.size.height
+ dy
+ dy
);
2162 CIImage
* CropAndCenterCIImage(CIImage
*image
, CGRect originalExtent
, CGRect
* cropRegionRef
);
2163 CIImage
* CropAndCenterCIImage(CIImage
*image
, CGRect originalExtent
, CGRect
* cropRegionRef
)
2165 #if SCIMAGE_FILTER_DEBUG
2166 NSLog(@
"Cropping and centering CIImage %p", image
);
2168 CGRect extent
= [image extent
];
2169 CIFilter
* ciFilter
;
2174 CGRect cropRegion
= *cropRegionRef
;
2175 // Crop to specified rectangle.
2176 if(extent.size.width
> cropRegion.size.width || extent.size.height
> cropRegion.size.height
)
2178 if(extent.origin.x
> 0) {cropRegion.origin.x
= extent.origin.x
;}
2179 if(extent.origin.y
> 0) {cropRegion.origin.y
= extent.origin.y
;}
2182 // quite strange but happens sometime...
2183 if(extent.origin.x
< 0 && ((extent.origin.x
+ extent.size.width
) < cropRegion.size.width
)) {
2184 float diff
= extent.size.width
+ extent.origin.x
;
2185 cropRegion.origin.x
-= (cropRegion.size.width
- diff
);
2188 if(extent.origin.y
< 0 && ((extent.origin.y
+ extent.size.height
) < cropRegion.size.height
)) {
2189 float diff
= extent.size.height
+ extent.origin.y
;
2190 cropRegion.origin.y
-= (cropRegion.size.height
- diff
);
2193 #if SCIMAGE_FILTER_DEBUG
2194 NSLog(@
"SCImageFilter: Cropping To Size: (%4.2f, %4.2f, %4.2f, %4.2f) fromExtent: (%4.2f, %4.2f, %4.2f, %4.2f)",
2195 cropRegion.origin.x
,cropRegion.origin.y
,cropRegion.size.width
,cropRegion.size.height
,
2196 extent.origin.x
,extent.origin.y
,extent.size.width
,extent.size.height
2200 ciFilter
= [CIFilter filterWithName
:@
"CICrop"]; // crop the final result according
2201 [ciFilter setValue
:image forKey
:@
"inputImage"];
2202 [ciFilter setValue
:[CIVector vectorWithX
:cropRegion.origin.x Y
:cropRegion.origin.y Z
:cropRegion.size.width W
:cropRegion.size.height
] forKey
:@
"inputRectangle"];
2203 image
= [ciFilter valueForKey
:@
"outputImage"];
2204 extent
= [image extent
];
2205 #if SCIMAGE_FILTER_DEBUG
2206 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
);
2211 // translating origin and center it if we need it
2212 // currently auto translation is now deactivated by default - let the user choose
2215 if(extent.origin.x != 0 || extent.origin.y != 0) {
2216 ciFilter = [CIFilter filterWithName:@"CIAffineTransform"];
2217 NSAffineTransform* trs = [NSAffineTransform transform];
2218 [trs translateXBy:-extent.origin.x yBy:-extent.origin.y]; // move to zero
2219 [ciFilter setValue:trs forKey:@"inputTransform"];
2220 [ciFilter setValue:image forKey:@"inputImage"];
2221 image = [ciFilter valueForKey:@"outputImage"];
2222 #if SCIMAGE_FILTER_DEBUG
2223 NSLog(@"SCImageFilter: After Translate: (%4.2f, %4.2f, %4.2f, %4.2f)", extent.origin.x,extent.origin.y,extent.size.width, extent.size.height);
2231 id nsciObjectFromSlot(PyrSlot
*slot
, Class attributeClass
, NSString
*attributeType
);
2232 id nsciObjectFromSlot(PyrSlot
*slot
, Class attributeClass
, NSString
*attributeType
)
2235 if(attributeClass
== [CIImage
class] || attributeType
== kCIAttributeTypeGradient
)
2237 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(slot
)->slots
);
2238 return [image ciimage
];
2240 else if(isKindOfSlot(slot
, s_scimage
->u.classobj
) && (attributeClass
== NULL
) && (attributeType
== NULL
)) // here returns the CISampler by default
2242 SCImage
*image
= (SCImage
*)slotRawPtr(slotRawObject(slot
)->slots
);
2243 return [CISampler samplerWithImage
:[image ciimage
]];
2245 // else if(isKindOfSlot(slot, s_vector->u.classobj)) {
2247 else if(isKindOfSlot(slot, s_array->u.classobj)) {
2248 #if SCIMAGE_FILTER_DEBUG
2249 NSLog(@"Creating CIVector From Vector Slot");
2252 return ciVectorFromSlot(slotRawObject(slot));
2255 else if(isKindOfSlot(slot
, s_color
->u.classobj
))
2257 PyrSlot
* color_slots
= slotRawObject(slot
)->slots
;
2259 err
= slotFloatVal(color_slots
+0, &cr
);
2261 err
= slotFloatVal(color_slots
+1, &cg
);
2263 err
= slotFloatVal(color_slots
+2, &cb
);
2265 err
= slotFloatVal(color_slots
+3, &ca
);
2268 #if SCIMAGE_FILTER_DEBUG
2269 NSLog(@
"Creating CIColor/NSColor From Color Slot");
2272 if(attributeClass
== [NSColor
class])
2274 return [NSColor colorWithCalibratedRed
:cr green
:cg blue
:cb alpha
:ca
];
2276 return [CIColor colorWithRed
:cr green
:cg blue
:cb alpha
:ca
];
2278 else if(isKindOfSlot(slot
, s_array
->u.classobj
))
2280 if(attributeClass
== [NSAffineTransform
class]) {
2281 #if SCIMAGE_FILTER_DEBUG
2282 NSLog(@
"Creating NSAffineTransform From Array Slot");
2284 // array containing [Tx, Ty, Sx, Sy, Rot in radians]
2285 PyrObject
* array
= slotRawObject(slot
);
2286 int size
= sc_min(array
->size
, 5), err
;
2287 float attributes
[5] = {0.f
, 0.f
, 1.f
, 1.f
, 0.f
};
2288 for(int i
=0; i
< size
; ++i
) {
2289 err
= slotFloatVal(array
->slots
+i
, attributes
+i
);
2291 attributes
[i
] = 0.f
;
2294 NSAffineTransform
*transform
= [NSAffineTransform transform
];
2295 [transform translateXBy
:attributes
[0] yBy
:attributes
[1]];
2296 [transform scaleXBy
:attributes
[2] yBy
:attributes
[3]];
2297 [transform rotateByRadians
:attributes
[4]];
2301 if(attributeClass
== [CIVector
class] || attributeClass
== NULL
) {
2302 #if SCIMAGE_FILTER_DEBUG
2303 NSLog(@
"Creating CIVector From Array Slot");
2305 return ciVectorFromSlot(slotRawObject(slot
));
2309 if(nsClassIsKindOfClass(attributeClass
, [NSData
class])) {
2310 // handle specific case here...
2311 // mostly for CIColorCube Filter
2312 #if SCIMAGE_FILTER_DEBUG
2313 NSLog(@
"Creating NSData From Array Slot");
2315 PyrClass
*support
= slotArrayGetCommonClass(slotRawObject(slot
));
2320 support != s_int8array->u.classobj &&
2321 support != s_int16array->u.classobj &&
2322 support != s_int32array->u.classobj &&
2323 support != s_doublearray->u.classobj &&
2324 support != class_floatarray->u.classobj
2333 else if(IsTrue(slot
) ||
IsFalse(slot
) )
2335 #if SCIMAGE_FILTER_DEBUG
2336 NSLog(@
"Creating NSNumber From Boolean Slot");
2338 return [NSNumber numberWithBool
:(IsTrue(slot
))];
2340 else if(IsFloat(slot
) ||
IsInt(slot
))
2342 #if SCIMAGE_FILTER_DEBUG
2343 NSLog(@
"Creating NSNumber From Float/Int Slot");
2347 err
= safeSlotFloatVal(slot
, &val
);
2350 if(attributeType
== kCIAttributeTypeBoolean
) {
2351 return [NSNumber numberWithBool
:val
> 0];
2353 return [NSNumber numberWithFloat
:val
];
2356 post("Non supported type of class: %s", slotRawObject(slot
)->classptr
->name
);
2357 return nil; // failure
2361 int prSCImageFilter_ApplyMultiple(struct VMGlobals
*g
, int numArgsPushed
);
2362 int prSCImageFilter_ApplyMultiple(struct VMGlobals
*g
, int numArgsPushed
)
2364 PyrSlot
*receiver
= g
->sp
- 4;
2365 PyrSlot
*filtersSlot
= g
->sp
- 3;
2366 PyrSlot
*inPlace
= g
->sp
- 2;
2367 // PyrSlot *updateRegionSlot = g->sp - 1;
2368 PyrSlot
*cropRegionSlot
= g
->sp
;
2371 SCImage
*scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2377 int numberOfFilters
;
2378 PyrObject
* scFilter
;
2379 PyrObject
*arguments
;
2383 //NSArray *inputKeys;
2388 CGRect origExtent
= [scimage extent
];
2392 numberOfFilters
= slotRawObject(filtersSlot
)->size
;
2394 // Get the CIImage rep in the SCImage
2395 if(![scimage isAccelerated
])
2396 [scimage syncCIImage
]; // update ciimage rep
2397 ciimage
= [scimage ciimage
]; // now we can get it
2399 // Iterate through all the filters
2400 for(int i
=0; i
< numberOfFilters
; ++i
)
2404 scFilter
= slotRawObject(&(slotRawObject(filtersSlot
)->slots
[i
]));
2406 if(IsFalse(scFilter
->slots
+3)) // filter enabled ?
2409 ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(scFilter
->slots
+0)]; // filter name
2410 if(!ciFilter
) return errFailed
;
2411 #if SCIMAGE_FILTER_DEBUG
2412 NSLog(@
"SCImageFilter --- Setting Filter Named %@", nsStringFromSlot(scFilter
->slots
+0));
2414 [ciFilter setDefaults
];
2416 arguments
= slotRawObject(&scFilter
->slots
[2]); // filter values
2417 size
= (arguments
->size
>> 1);
2419 for(int i
=0; i
< size
; ++i
)
2421 key
= slotRawSymbol(arguments
->slots
+ (i
<<1));
2422 value
= arguments
->slots
+ ((i
<<1) + 1);
2423 nskey
= [NSString stringWithFormat
:@
"input%c%s", toupper(*key
->name
), key
->name
+1];
2424 valueClass
= NSClassFromString( [[[ciFilter attributes
] objectForKey
:nskey
] objectForKey
:@
"CIAttributeClass"]);
2425 nsvalue
= nsciObjectFromSlot(value
, valueClass
, [[ciFilter attributes
] objectForKey
:kCIAttributeType
]);
2429 #if SCIMAGE_FILTER_DEBUG
2430 NSLog(@
"Setting Key: %@ Value: %@ Class: %@", nskey
, nsvalue
, valueClass
);
2432 [ciFilter setValue
:nsvalue forKey
:nskey
];
2436 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
));
2440 // concatenate filters
2441 if([[ciFilter inputKeys
]containsObject
:@
"inputImage"])
2443 [ciFilter setValue
:ciimage forKey
:@
"inputImage"];
2447 ciimage
= [ciFilter valueForKey
:@
"outputImage"];
2451 destExtent
= [ciimage extent
];
2453 #if SCIMAGE_MAC_OS_10_5
2455 //CGRectIsInfinite(destExtent) || // infinite rects are mosly results from generator filters
2456 !IsNil(updateRegionSlot
) // better to keep original extent if constrained update
2459 destExtent
= origExtent
;
2464 // if the rect is not infinite :
2465 // 1 - crop the image if a cropRegion is specified
2466 // 2 - translate the image to align origin of extent with coordindate origin of image (0,0)
2468 if(IsNil(cropRegionSlot
)) {
2469 #if SCIMAGE_FILTER_DEBUG
2470 NSLog(@
"SCImageFilter: Nil Crop Region - creating from %i, %i maximum crop size", SCCIIMAGE_MAX_WIDTH
, SCCIIMAGE_MAX_HEIGHT
);
2472 cropRegion
= OutsetRect(origExtent
, floorf((SCCIIMAGE_MAX_WIDTH
- origExtent.size.width
) * 0.5), floorf((SCCIIMAGE_MAX_HEIGHT
- origExtent.size.height
) * 0.5));
2474 err
= slotGetNSRect(cropRegionSlot
, (NSRect
*)&cropRegion
);
2477 ciimage
= CropAndCenterCIImage(ciimage
, origExtent
, &cropRegion
);
2478 destExtent
= [ciimage extent
];
2480 #if SCIMAGE_MAC_OS_10_5
2485 PyrObject
*receiverObj
;
2488 // Here the caller should be directly updated !
2489 // Size will be equal if :
2490 // 1 - the filter does not extend the image bounds (modified / infinite extent)
2491 // 2 - the update region slot if not nil to constrain updates
2492 if(CGSizeEqualToSize(destExtent.size
, origExtent.size
))
2494 #if SCIMAGE_MAC_OS_10_5
2495 if(!IsNil(updateRegionSlot
))
2497 CGRect updateRegion
;
2498 err
= slotGetNSRect(updateRegionSlot
, (NSRect
*)&updateRegion
);
2500 // Invert SC Coordinates
2501 updateRegion.origin.y
= [[scimage accumulator
]extent
].size.height
- (updateRegion.origin.y
+ updateRegion.size.height
);
2502 [[scimage accumulator
] setImage
:ciimage dirtyRect
:updateRegion
];
2506 [[scimage accumulator
] setImage
:ciimage
];
2510 [scimage
->_ciimage release
];
2511 scimage
->_ciimage
= ciimage
;
2513 [scimage setShouldSyncBitmap
:YES
]; // keep the sync info
2518 receiverObj
= slotRawObject(receiver
);
2520 #if SCIMAGE_FILTER_DEBUG
2521 NSLog(@
"SCImageFilter: New Extent (%4.2f, %4.2f, %4.2f, %4.2f)", destExtent.origin.x
, destExtent.origin.y
, destExtent.size.width
, destExtent.size.height
);
2526 receiverObj
= newPyrSCImage(g
);
2529 post("Failed creating valid SCImage class !");
2534 #if SCIMAGE_DEBUG || SCIMAGE_FILTER_DEBUG
2535 NSLog(@
"SCImageFilter: Creating New SCImage Class");
2536 NSLog(@
"SCImageFilter: OriginalImage Extent: (%4.2f, %4.2f, %4.2f, %4.2f) NewImage Extent: (%4.2f, %4.2f, %4.2f, %4.2f)",
2537 origExtent.origin.x
, origExtent.origin.y
, origExtent.size.width
, origExtent.size.height
,
2538 destExtent.origin.x
,destExtent.origin.y
,destExtent.size.width
, destExtent.size.height
2542 SCImage
*newSCImage
= [[SCImage alloc
]initWithCIImage
:ciimage extent
:destExtent format
:[scimage format
]];
2545 post("Error: Failed creating valid CIImage cache !!!");
2549 value
= receiverObj
->slots
;
2550 SetPtr(value
+ 0, newSCImage
);
2551 SetFloat(value
+ 1, destExtent.size.width
);
2552 SetFloat(value
+ 2, destExtent.size.height
);
2554 if(receiverObj
== slotRawObject(receiver
))
2557 SetObject(receiver
, receiverObj
);
2562 int prSCImageFilter_Apply(struct VMGlobals
*g
, int numArgsPushed
);
2563 int prSCImageFilter_Apply(struct VMGlobals
*g
, int numArgsPushed
)
2565 PyrSlot
*receiver
= g
->sp
- 3;
2566 PyrSlot
*filterNameSlot
= g
->sp
- 2;
2567 PyrSlot
*argumentsSlot
= g
->sp
- 1;
2568 PyrSlot
*inPlace
= g
->sp
;
2570 SCImage
*scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2576 CIFilter
* ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(filterNameSlot
)];
2580 [ciFilter setDefaults
];
2582 PyrObject
*arguments
= slotRawObject(argumentsSlot
); // array
2589 int size
= (arguments
->size
>> 1);
2591 for(int i
=0; i
< size
; ++i
) {
2592 key
= (PyrSymbol
*)slotRawSymbol(arguments
->slots
+ (i
<<1));
2593 value
= arguments
->slots
+ ((i
<<1) + 1);
2594 nskey
= [NSString stringWithFormat
:@
"input%c%s", toupper(*key
->name
), key
->name
+1];
2595 valueClass
= NSClassFromString( [[[ciFilter attributes
] objectForKey
:nskey
] objectForKey
:@
"CIAttributeClass"]);
2596 nsvalue
= nsciObjectFromSlot(value
, valueClass
, [[ciFilter attributes
] objectForKey
:kCIAttributeType
]);
2598 #if SCIMAGE_FILTER_DEBUG
2599 NSLog(@
"Setting Key: %@ Value: %@ Class: %@", nskey
, nsvalue
, valueClass
);
2601 [ciFilter setValue
:nsvalue forKey
:nskey
];
2603 post("Error: bad (nil) slot value for key %s, NSObject conversion failed for class %s !", [nskey UTF8String
], class_getName(valueClass
));
2607 if(IsTrue(inPlace
)) {
2608 [scimage applyFilter
:ciFilter
]; // in place filter
2612 NSLog(@
"Creating New SCImage Class");
2615 scimage
= [scimage imageFilteredWith
:ciFilter
]; // filtered copy
2616 PyrObject
* object
= newPyrSCImage(g
);
2617 PyrSlot
*slots
= object
->slots
;
2618 SetPtr(slots
+ 0, scimage
);
2619 SetFloat(slots
+ 1, (float)[scimage width
]);
2620 SetFloat(slots
+ 2, (float)[scimage height
]);
2621 SetObject(receiver
, object
);
2629 * Currently only cache the CIKernel object + install a finalizer on it
2631 int cachePyrKernel(VMGlobals
*g
, PyrObject
* kernelObject
)
2633 NSString
* kernelCmd
= nsStringFromSlot(kernelObject
->slots
+0);
2635 post("Error: Kernel string command does not seem valid !\n");
2639 id kernel
= [CIKernel kernelsWithString
:kernelCmd
];
2641 post("Error: Failed creating valid Kernel from shader string !!\n");
2645 // Create the Kernel
2646 kernel
= [(NSArray
*)kernel objectAtIndex
:0];
2648 post("Error: Failed retrieving valid CIKernel !");
2653 if( !IsNil(kernelObject
->slots
+4) ) {
2654 id current
= (id)slotRawPtr(&kernelObject
->slots
[4]);
2659 SetPtr(kernelObject
->slots
+4, kernel
);
2661 if( IsNil(kernelObject
->slots
+5) ) {
2663 post("install finalizer scimagekernel (%p)\n", kernelObject
);
2665 InstallFinalizer(g
, kernelObject
, 5, FinalizeSCImageKernelObject
);
2668 post("caching scimagekernel (%p)\n", kernelObject
);
2673 int prSCImageKernel_Compile(struct VMGlobals
*g
, int numArgsPushed
);
2674 int prSCImageKernel_Compile(struct VMGlobals
*g
, int numArgsPushed
)
2676 PyrSlot
* receiver
= g
->sp
;
2677 return cachePyrKernel(g
, slotRawObject(receiver
));
2681 * This function is intended to apply a specific CIKernel to the image
2682 * Still experimental
2684 int prSCImageFilter_ApplyKernel(struct VMGlobals
*g
, int numArgsPushed
);
2685 int prSCImageFilter_ApplyKernel(struct VMGlobals
*g
, int numArgsPushed
)
2687 PyrSlot
*receiver
= g
->sp
- 3;
2688 PyrSlot
*kernelSlot
= g
->sp
- 2;
2689 PyrSlot
*cropRegionSlot
= g
->sp
- 1;
2690 PyrSlot
*inPlace
= g
->sp
;
2692 PyrSlot
*argumentSlot
;
2693 SCImage
*newSCImage
=nil;
2695 PyrObject
*kernelObject
=nil;
2696 CIKernel
*kernel
=nil;
2704 scimage
= (SCImage
*)slotRawPtr(slotRawObject(receiver
)->slots
);
2710 [scimage setAccelerated
:YES
];
2711 CIFilter
* ciFilter
= [[CIFilter
new]autorelease
];
2713 ///// Setting and caching the Kernel Object
2714 kernelObject
= slotRawObject(kernelSlot
);
2715 if(IsNil(kernelObject
->slots
+4)) {
2716 err
= cachePyrKernel(g
, kernelObject
);
2719 argumentSlot
= kernelObject
->slots
+1;
2720 kernel
= (CIKernel
*)(slotRawPtr(&kernelObject
->slots
[4]));
2724 // Get the extent of the image
2725 CGRect extent
= [[scimage ciimage
]extent
];
2727 #if SCIMAGE_FILTER_DEBUG
2728 NSLog(@
"SCImageFilter: CIKernel created Successfully !");
2730 // Setting the Argument Array + PyrObject->Cocoa conversion
2733 You can pass the following types to a kernel routine:
2735 Requires a CISampler object when applied. // directly added in SCApp
2737 A qualifier for a sampler type.
2738 float, vec2, vec3, vec4:
2739 Requires an NSNumber or CIVector.
2741 A color that will be matched to the CIContext working color space when passed into the program.
2742 It requires a CIColor object when applied. To the kernel program it appears to be a vec4 type in premultiplied RGBA format.
2745 NSMutableArray
* arguments
= [NSMutableArray arrayWithCapacity
:16];
2747 post("Error: memory error ? allocation failed for NSMutableArray. applying Kernel aborted !");
2751 #if SCIMAGE_FILTER_DEBUG
2752 NSLog(@
"SCImageFilter: CIKernel setting Arguments !");
2754 // set all the arguments
2755 if( !IsNil(argumentSlot
) ) { // iterate through all the arguments
2756 PyrObject
* pyrArray
= slotRawObject(argumentSlot
);
2757 int size
= pyrArray
->size
;
2758 for(int i
=0; i
< size
; ++i
) {
2759 id object
= nsciObjectFromSlot(pyrArray
->slots
+i
, NULL
, NULL
);
2761 [arguments addObject
:object
];
2764 return errFailed
; // Kernels require no bad arguments
2768 // Create the Option Dictionary that contains additional info about final rendering
2769 // kCIApplyOptionDefinition : DOD of image
2770 // kCIApplyOptionExtent : size of the resulting image
2771 NSMutableDictionary
* dictionary
= [[[NSDictionary dictionary
] mutableCopy
] autorelease
];
2774 setValue
:[[scimage ciimage
] definition
] // better to pass directly the filterShape
2775 forKey
:kCIApplyOptionDefinition
2778 // Set the Extent of the result image if one is specified
2780 if(!IsNil(maxBounds)) {
2782 err = slotGetNSRect(maxBounds, (NSRect*)&maxRect);
2784 [dictionary setValue:
2785 [NSArray arrayWithObjects:
2786 [NSNumber numberWithFloat:maxRect.origin.x], // x
2787 [NSNumber numberWithFloat:maxRect.origin.y], // y
2788 [NSNumber numberWithFloat:maxRect.size.width], // w
2789 [NSNumber numberWithFloat:maxRect.size.height] // h
2792 forKey:kCIApplyOptionExtent
2797 #if SCIMAGE_FILTER_DEBUG
2798 NSLog(@
"SCImageFilter: CIKernel created Options successfully !");
2803 ciimage
= [ciFilter apply
:kernel arguments
:arguments options
:dictionary
];
2805 // if the rect is not infinite :
2806 // 1 - crop the image if a cropRegion is specified
2807 // 2 - translate the image to align origin of extent with coordindate origin of image (0,0)
2809 if(IsNil(cropRegionSlot
)) {
2810 cropRegion
= OutsetRect(extent
, floorf((SCCIIMAGE_MAX_WIDTH
- extent.size.width
) * 0.5), floorf((SCCIIMAGE_MAX_HEIGHT
- extent.size.height
) * 0.5));
2812 err
= slotGetNSRect(cropRegionSlot
, (NSRect
*)&cropRegion
);
2816 ciimage
= CropAndCenterCIImage(ciimage
, extent
, &cropRegion
);
2818 destExtent
= [ciimage extent
];
2820 #if SCIMAGE_FILTER_DEBUG
2821 NSLog(@
"SCImageFilter: applied Kernel Successfully !");
2824 // Setting the PyrSlot
2825 PyrObject
* receiverObj
;
2828 if( CGSizeEqualToSize(extent.size
, destExtent.size
) ) {
2829 #if SCIMAGE_MAC_OS_10_5
2830 [[scimage accumulator
] setImage
:ciimage
];
2832 [scimage
->_ciimage release
];
2833 scimage
->_ciimage
= [ciimage retain
];
2835 [scimage setShouldSyncBitmap
:YES
]; // invalidates bitmap
2838 NSLog(@
"CIKernel different size returned");
2839 receiverObj
= slotRawObject(receiver
);
2844 receiverObj
= newPyrSCImage(g
);
2847 #if SCIMAGE_FILTER_DEBUG
2848 NSLog(@
"SCImageFilter: Creating New SCImage Class");
2851 newSCImage
= [[SCImage alloc
]initWithCIImage
:ciimage extent
:destExtent format
:[scimage format
]];
2853 PyrSlot
*slots
= receiverObj
->slots
;
2854 [(id)slotRawPtr(slots
) release
];
2856 SetPtr(slots
+ 0, newSCImage
);
2857 SetFloat(slots
+ 1, destExtent.size.width
);
2858 SetFloat(slots
+ 2, destExtent.size.height
);
2860 if(receiverObj
!= slotRawObject(receiver
)) {
2861 SetObject(receiver
, receiverObj
);
2864 @catch ( NSException
*e
)
2866 //if([[e name]isEqualToString: @"CIKernelMissingArgument"])
2867 post("Error: %s\n", [[NSString stringWithFormat
:@
"%@ %@", @
"SCImageKernel", e
]UTF8String
]);
2874 int prSCImageFilter_GetAttributeMinMax(struct VMGlobals
*g
, int numArgsPushed
)
2876 PyrSlot
*receiver
= g
->sp
- 2;
2877 PyrSlot
*filterAttributeSlot
= g
->sp
- 1;
2878 PyrSlot
*returnedArraySlot
= g
->sp
;
2881 ciFilter
= [CIFilter filterWithName
: nsStringFromSlot(slotRawObject(receiver
)->slots
+0)]; // filter name
2882 if(!ciFilter
) return errFailed
;
2884 NSDictionary
* attrDict
= [ciFilter attributes
];
2885 NSString
*key
= nsStringFromSlot(filterAttributeSlot
);
2888 #if SCIMAGE_FILTER_DEBUG
2889 NSLog(@
"Checking for CIFilter MinMax of attribute: %@", key
);
2898 const char* cStr
= [key cStringUsingEncoding
:NSASCIIStringEncoding
];
2899 attribute
= [attrDict objectForKey
: [NSString stringWithFormat
:@
"input%c%s", toupper(*cStr
), cStr
+1]];
2901 post("SCImageFilter : no attributes named %s found !\n", [key UTF8String
]);
2907 PyrObject
* pyrArray
= slotRawObject(returnedArraySlot
); // should be an array of size 3
2908 NSString
* attrType
= [attribute objectForKey
:kCIAttributeType
];
2911 minmax
[0] = [attribute objectForKey
: kCIAttributeSliderMin
] ?
[attribute objectForKey
: kCIAttributeSliderMin
] : [attribute objectForKey
: kCIAttributeMin
];
2912 minmax
[1] = [attribute objectForKey
: kCIAttributeSliderMax
] ?
[attribute objectForKey
: kCIAttributeSliderMax
] : [attribute objectForKey
: kCIAttributeMax
];
2913 minmax
[2] = [attribute objectForKey
: kCIAttributeDefault
];
2915 if(!minmax
[0] && !minmax
[1] && !minmax
[2]){ // if no slider min or slider max or default - set to nil directly
2921 if(attrType
== kCIAttributeTypeBoolean
)
2923 SetFalse(pyrArray
->slots
+0);
2924 SetTrue(pyrArray
->slots
+1);
2925 SetBool(pyrArray
->slots
+2, ([ minmax
[2] floatValue
] > 0.f
));
2928 attrType
== kCIAttributeTypeAngle || attrType
== kCIAttributeTypeDistance ||
2929 attrType
== kCIAttributeTypeScalar || attrType
== kCIAttributeTypeTime
2933 SetFloat(pyrArray
->slots
+0, [minmax
[0] doubleValue
]);
2935 SetNil(pyrArray
->slots
+0);
2938 SetFloat(pyrArray
->slots
+1, [minmax
[1] doubleValue
]);
2940 SetNil(pyrArray
->slots
+1);
2943 SetFloat(pyrArray
->slots
+2, [minmax
[2] doubleValue
]);
2945 SetNil(pyrArray
->slots
+1);
2947 else if( attrType
== kCIAttributeTypePosition || attrType
== kCIAttributeTypeOffset
)
2950 PyrObject
* vector
[3];
2951 for(int i
=0; i
< 3; ++i
) {
2953 SetNil(pyrArray
->slots
+i
); continue;
2955 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 2, 0, true);
2956 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2957 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2958 vector
[i
]->size
= 2;
2959 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2960 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
2963 else if( attrType
== kCIAttributeTypePosition3
)
2966 PyrObject
* vector
[3];
2967 for(int i
=0; i
< 3; ++i
) {
2969 SetNil(pyrArray
->slots
+i
); continue;
2971 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 3, 0, true);
2972 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2973 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2974 SetFloat( vector
[i
]->slots
+2, [ (CIVector
*)minmax
[i
] Z
]);
2975 vector
[i
]->size
= 3;
2976 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2977 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
2980 else if( attrType
== kCIAttributeTypeRectangle
)
2983 PyrObject
* vector
[3];
2984 for(int i
=0; i
< 3; ++i
) {
2986 SetNil(pyrArray
->slots
+i
); continue;
2988 vector
[i
] = newPyrArray(g
->gc
, sizeof(double) * 4, 0, true);
2989 SetFloat( vector
[i
]->slots
+0, [ (CIVector
*)minmax
[i
] X
]);
2990 SetFloat( vector
[i
]->slots
+1, [ (CIVector
*)minmax
[i
] Y
]);
2991 SetFloat( vector
[i
]->slots
+2, [ (CIVector
*)minmax
[i
] Z
]);
2992 SetFloat( vector
[i
]->slots
+3, [ (CIVector
*)minmax
[i
] W
]);
2993 vector
[i
]->size
= 4;
2994 SetObject(pyrArray
->slots
+i
, vector
[i
]);
2995 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
2998 else if( attrType
== kCIAttributeTypeOpaqueColor
)
3001 PyrObject
* vector
[3];
3002 for(int i
=0; i
< 3; ++i
) {
3003 vector
[i
] = ::instantiateObject(g
->gc
, s_color
->u.classobj
, 0, false, true);
3004 SetFloat( vector
[i
]->slots
+0, (double)[ (CIColor
*)minmax
[i
] red
]);
3005 SetFloat( vector
[i
]->slots
+1, (double)[ (CIColor
*)minmax
[i
] green
]);
3006 SetFloat( vector
[i
]->slots
+2, (double)[ (CIColor
*)minmax
[i
] blue
]);
3007 SetFloat( vector
[i
]->slots
+3, (double)[ (CIColor
*)minmax
[i
] alpha
]);
3008 SetObject(pyrArray
->slots
+i
, vector
[i
]);
3009 g
->gc
->GCWrite(pyrArray
, vector
[i
]);
3018 SetObject(receiver
, pyrArray
);
3022 // SetNil(receiver);
3026 int prSCImageFilter_Attributes(struct VMGlobals
*g
, int numArgsPushed
);
3027 int prSCImageFilter_Attributes(struct VMGlobals
*g
, int numArgsPushed
)
3029 PyrSlot
*receiver
= g
->sp
- 1;
3030 PyrSlot
*filterNameSlot
= g
->sp
;
3033 filter
= [CIFilter filterWithName
: nsStringFromSlot(filterNameSlot
)];
3037 NSDictionary
* attr
= [filter attributes
];
3038 NSArray
*inputKeys
= [filter inputKeys
];
3040 NSEnumerator
* e
= [inputKeys objectEnumerator
];
3044 maxsize
= [inputKeys count
] * 2;
3045 if([inputKeys containsObject
:@
"inputImage"]) {
3046 maxsize
-= 2; // remove the inputImage
3048 PyrSymbolArray
* returnObject
= newPyrSymbolArray(g
->gc
, maxsize
, 0, true);
3049 returnObject
->size
= maxsize
;
3052 while( (key
= [e nextObject
]) )
3054 if(i
>= maxsize
) return errNone
; // in case
3055 if(![key isEqualToString
:@
"inputImage"]) { // we do not need it
3056 cStr
= [[key substringFromIndex
:5] cStringUsingEncoding
:NSASCIIStringEncoding
]; // remove the 'input'
3057 returnObject
->symbols
[i
++] = getsym([ [NSString stringWithFormat
: @
"%c%s", tolower(*cStr
), (cStr
+ 1)] UTF8String
]);
3058 returnObject
->symbols
[i
++] = getsym([ [ [ attr objectForKey
: key
] objectForKey
: @
"CIAttributeClass" ] UTF8String
]);
3062 SetObject(receiver
, returnObject
);
3067 int prSCImageFilter_NamesInCategory(struct VMGlobals
*g
, int numArgsPushed
);
3068 int prSCImageFilter_NamesInCategory(struct VMGlobals
*g
, int numArgsPushed
)
3070 PyrSlot
*receiver
, *category
, *returnArray
;
3074 returnArray
= g
->sp
;
3075 category
= g
->sp
- 1;
3076 receiver
= g
->sp
- 2;
3078 //PyrObject *returnObject = slotRawObject(returnArray);
3079 //int maxsize = MAXINDEXSIZE(returnObject);
3081 if (!IsSym(category
)) return errWrongType
;
3083 type
= nsStringFromSlot(category
);
3084 if(!type
) return errFailed
;
3086 array
= [CIFilter filterNamesInCategory
:type
];
3087 if(!array
) return errFailed
;
3089 int maxsize
= [array count
];
3090 PyrSymbolArray
* returnObject
= newPyrSymbolArray(g
->gc
, maxsize
, 0, true);
3091 returnObject
->size
= maxsize
;
3094 NSEnumerator
*e
= [array objectEnumerator
];
3097 while( (type
= [e nextObject
]) )
3099 if(i
>= maxsize
) break; // in case
3100 returnObject
->symbols
[i
] = getsym([type UTF8String
]);
3104 SetObject(receiver
, returnObject
);
3109 #pragma mark - InitSCImagePrims
3111 void initSCImagePrimitives()
3115 s_scimage
= getsym("SCImage");
3116 s_scfilter
= getsym("SCImageFilter");
3117 s_scimagekernel
= getsym("SCImageKernel");
3120 NSLog(@
"---- SCIMAGE: Init Primitives ----");
3121 NSLog(@
"---- SCIMAGE: Using Mac OS 10.%c Version ----", (SCIMAGE_MAC_OS_10_5
== 1) ?
'5' : '4');
3124 if(!gCIFilterPlugInsLoaded
) {
3126 NSLog(@
"---- SCIMAGE: Loading CIFilter PlugIns ----");
3128 [CIPlugIn loadAllPlugIns
];
3129 gCIFilterPlugInsLoaded
= YES
;
3132 base
= nextPrimitiveIndex();
3136 definePrimitive(base
, index
++, "_SCImage_New", prSCImage_New
, 4, 0);
3137 //definePrimitive(base, index++, "_SCImage_NewFromFile", prSCImage_NewFromFile, 2, 0); // use only URL
3138 definePrimitive(base
, index
++, "_SCImage_NewFromURL", prSCImage_NewFromURL
, 2, 0);
3139 definePrimitive(base
, index
++, "_SCImage_WriteToFile", prSCImage_WriteToFile
, 3, 0);
3140 definePrimitive(base
, index
++, "_SCImage_Free", prSCImage_Free
, 1, 0);
3141 definePrimitive(base
, index
++, "_SCImage_setSize", prSCImage_setSize
, 3, 0);
3142 definePrimitive(base
, index
++, "_SCImage_setScalesWhenResized", prSCImage_setScalesWhenResized
, 2, 0);
3143 definePrimitive(base
, index
++, "_SCImage_scalesWhenResized", prSCImage_scalesWhenResized
, 1, 0);
3144 definePrimitive(base
, index
++, "_SCImage_DrawAtPoint", prSCImage_DrawAtPoint
, 5, 0);
3145 definePrimitive(base
, index
++, "_SCImage_DrawInRect", prSCImage_DrawInRect
, 5, 0);
3146 definePrimitive(base
, index
++, "_SCImage_tileInRect", prSCImage_TileInRect
, 5, 0);
3147 definePrimitive(base
, index
++, "_SCImage_lockFocus", prSCImage_lockFocus
, 1, 0);
3148 definePrimitive(base
, index
++, "_SCImage_unlockFocus", prSCImage_unlockFocus
, 1, 0);
3149 definePrimitive(base
, index
++, "_SCImage_recache", prSCImage_recache
, 1, 0);
3150 definePrimitive(base
, index
++, "_SCImage_setPixelAt", prSCImage_setPixelAt
, 4, 0);
3151 definePrimitive(base
, index
++, "_SCImage_getPixelAt", prSCImage_pixelAt
, 3, 0);
3152 definePrimitive(base
, index
++, "_SCImage_setColorAt", prSCImage_setColorAt
, 4, 0);
3153 definePrimitive(base
, index
++, "_SCImage_getColorAt", prSCImage_getColorAt
, 3, 0);
3154 definePrimitive(base
, index
++, "_SCImage_setAccelerated", prSCImage_setAccelerated
, 2, 0);
3155 definePrimitive(base
, index
++, "_SCImage_isAccelerated", prSCImage_isAccelerated
, 1, 0);
3156 definePrimitive(base
, index
++, "_SCImage_loadPixels", prSCImage_loadPixels
, 4, 0);
3157 definePrimitive(base
, index
++, "_SCImage_updatePixels", prSCImage_updatePixels
, 3, 0);
3158 definePrimitive(base
, index
++, "_SCImage_updatePixelsInRect", prSCImage_updatePixelsInRect
, 4, 0);
3159 definePrimitive(base
, index
++, "_SCImage_interpolation", prSCImage_interpolation
, 1, 0);
3160 definePrimitive(base
, index
++, "_SCImage_setInterpolation", prSCImage_setInterpolation
, 2, 0);
3161 definePrimitive(base
, index
++, "_SCImage_sync", prSCImage_sync
, 1, 0);
3162 definePrimitive(base
, index
++, "_SCImage_fromWindowRect", prSCImage_imageFromSCWindowRect
, 3, 0);
3164 // image Filter - experimental for now
3165 definePrimitive(base
, index
++, "_SCImageFilter_NamesInCategory", prSCImageFilter_NamesInCategory
, 3, 0);
3166 definePrimitive(base
, index
++, "_SCImageFilter_Attributes", prSCImageFilter_Attributes
, 2, 0);
3167 definePrimitive(base
, index
++, "_SCImageFilter_Apply", prSCImageFilter_Apply
, 4, 0);
3168 definePrimitive(base
, index
++, "_SCImageFilter_ApplyMultiple", prSCImageFilter_ApplyMultiple
, 5, 0);
3169 definePrimitive(base
, index
++, "_SCImageFilter_GetAttributeMinMax", prSCImageFilter_GetAttributeMinMax
, 3, 0);
3170 definePrimitive(base
, index
++, "_SCImageFilter_ApplyKernel", prSCImageFilter_ApplyKernel
, 4, 0);
3171 definePrimitive(base
, index
++, "_SCImageKernel_Compile", prSCImageKernel_Compile
, 1, 0);
3177 void initSCImagePrimitives()
3179 // SCImage not supported for os version < 10.4...