1 /*------------------------------------------------------------------------
3 * Derivative of the OpenVG 1.0.1 Reference Implementation
4 * -------------------------------------
6 * Copyright (c) 2007 The Khronos Group Inc.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and /or associated documentation files
10 * (the "Materials "), to deal in the Materials without restriction,
11 * including without limitation the rights to use, copy, modify, merge,
12 * publish, distribute, sublicense, and/or sell copies of the Materials,
13 * and to permit persons to whom the Materials are furnished to do so,
14 * subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Materials.
19 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
25 * THE USE OR OTHER DEALINGS IN THE MATERIALS.
27 *-------------------------------------------------------------------*/
29 #import <Onyx2D/O2Surface.h>
30 #import <Onyx2D/O2ColorSpace.h>
31 #import <Onyx2D/O2DataProvider.h>
33 @implementation O2Surface
35 #define RI_MAX_GAUSSIAN_STD_DEVIATION 128.0f
37 /*-------------------------------------------------------------------*//*!
38 * \brief Converts from the current internal format to another.
42 *//*-------------------------------------------------------------------*/
44 //From Section 3.4.2 of OpenVG 1.0.1 spec
45 //1: sRGB = gamma(lRGB)
46 //2: lRGB = invgamma(sRGB)
47 //3: lL = 0.2126 lR + 0.7152 lG + 0.0722 lB
50 //6: lL = invgamma(sL)
53 //Source/Dest lRGB sRGB lL sL
60 // Can't use 'gamma' ?
61 static O2Float dogamma(O2Float c)
66 c = 1.0556f * (O2Float)pow(c, 1.0f/2.4f) - 0.0556f;
70 static O2Float invgamma(O2Float c)
75 c = (O2Float)pow((c + 0.0556f)/1.0556f, 2.4f);
80 static O2Float lRGBtoL(O2Float r, O2Float g, O2Float b)
82 return 0.2126f*r + 0.7152f*g + 0.0722f*b;
85 static void colorToBytesLittle(O2Float color,uint8_t *scanline){
87 unsigned char bytes[4];
93 #ifdef __LITTLE_ENDIAN__
94 scanline[0]=u.bytes[0];
95 scanline[1]=u.bytes[1];
96 scanline[2]=u.bytes[2];
97 scanline[3]=u.bytes[3];
99 scanline[3]=u.bytes[0];
100 scanline[2]=u.bytes[1];
101 scanline[1]=u.bytes[2];
102 scanline[0]=u.bytes[3];
106 static void O2SurfaceWrite_argb32f_to_argb32fLittle(O2Surface *self,int x,int y,O2argb32f *span,int length){
107 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
111 for(i=0;i<length;i++){
112 O2argb32f rgba=*span++;
114 colorToBytesLittle(rgba.r,scanline);
116 colorToBytesLittle(rgba.g,scanline);
118 colorToBytesLittle(rgba.b,scanline);
120 colorToBytesLittle(rgba.a,scanline);
125 static void colorToBytesBig(O2Float color,uint8_t *scanline){
127 unsigned char bytes[4];
133 #ifdef __BIG_ENDIAN__
134 scanline[0]=u.bytes[0];
135 scanline[1]=u.bytes[1];
136 scanline[2]=u.bytes[2];
137 scanline[3]=u.bytes[3];
139 scanline[3]=u.bytes[0];
140 scanline[2]=u.bytes[1];
141 scanline[1]=u.bytes[2];
142 scanline[0]=u.bytes[3];
146 static void O2SurfaceWrite_argb32f_to_argb32fBig(O2Surface *self,int x,int y,O2argb32f *span,int length){
147 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
151 for(i=0;i<length;i++){
152 O2argb32f rgba=*span++;
154 colorToBytesBig(rgba.r,scanline);
156 colorToBytesBig(rgba.g,scanline);
158 colorToBytesBig(rgba.b,scanline);
160 colorToBytesBig(rgba.a,scanline);
165 static unsigned char colorToNibble(O2Float c){
166 return RI_INT_MIN(RI_INT_MAX(RI_FLOOR_TO_INT(c * (O2Float)0xF + 0.5f), 0), 0xF);
169 static void O2SurfaceWrite_argb32f_to_GA88(O2Surface *self,int x,int y,O2argb32f *span,int length){
170 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
174 for(i=0;i<length;i++){
175 O2argb32f rgba=*span++;
177 *scanline++=O2ByteFromFloat(rgba.r);
178 *scanline++=O2ByteFromFloat(rgba.a);
182 static void O2SurfaceWrite_argb32f_to_G8(O2Surface *self,int x,int y,O2argb32f *span,int length){
183 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
187 for(i=0;i<length;i++){
188 O2argb32f rgba=*span++;
190 *scanline++=O2ByteFromFloat(lRGBtoL(rgba.r,rgba.g,rgba.b));
195 static void O2SurfaceWrite_argb32f_to_argb8u(O2Surface *self,int x,int y,O2argb32f *span,int length){
196 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
200 for(i=0;i<length;i++){
201 O2argb32f rgba=*span++;
203 *scanline++=O2ByteFromFloat(rgba.r);
204 *scanline++=O2ByteFromFloat(rgba.g);
205 *scanline++=O2ByteFromFloat(rgba.b);
206 *scanline++=O2ByteFromFloat(rgba.a);
210 static void O2SurfaceWrite_argb8u_to_argb8u(O2Surface *self,int x,int y,O2argb8u *span,int length){
211 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
215 for(i=0;i<length;i++){
216 O2argb8u rgba=*span++;
225 static void O2SurfaceWrite_argb32f_to_ABGR8888(O2Surface *self,int x,int y,O2argb32f *span,int length){
226 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
230 for(i=0;i<length;i++){
231 O2argb32f rgba=*span++;
233 *scanline++=O2ByteFromFloat(rgba.a);
234 *scanline++=O2ByteFromFloat(rgba.b);
235 *scanline++=O2ByteFromFloat(rgba.g);
236 *scanline++=O2ByteFromFloat(rgba.r);
240 static void O2SurfaceWrite_argb8u_to_ABGR8888(O2Surface *self,int x,int y,O2argb8u *span,int length){
241 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
245 for(i=0;i<length;i++){
246 O2argb8u rgba=*span++;
255 static void O2SurfaceWrite_argb8u_to_BGRA8888(O2Surface *self,int x,int y,O2argb8u *span,int length){
256 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
260 for(i=0;i<length;i++){
261 O2argb8u rgba=*span++;
270 static void O2SurfaceWrite_argb32f_to_RGBA4444(O2Surface *self,int x,int y,O2argb32f *span,int length){
271 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
275 for(i=0;i<length;i++){
276 O2argb32f rgba=*span++;
278 *scanline++=colorToNibble(rgba.r)<<4|colorToNibble(rgba.g);
279 *scanline++=colorToNibble(rgba.b)<<4|colorToNibble(rgba.a);
283 static void O2SurfaceWrite_argb32f_to_BARG4444(O2Surface *self,int x,int y,O2argb32f *span,int length){
284 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
288 for(i=0;i<length;i++){
289 O2argb32f rgba=*span++;
291 *scanline++=colorToNibble(rgba.b)<<4|colorToNibble(rgba.a);
292 *scanline++=colorToNibble(rgba.r)<<4|colorToNibble(rgba.g);
296 static void O2SurfaceWrite_argb32f_to_RGBA2222(O2Surface *self,int x,int y,O2argb32f *span,int length){
297 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
301 for(i=0;i<length;i++){
302 O2argb32f rgba=*span++;
304 *scanline++=colorToNibble(rgba.a)<<6|colorToNibble(rgba.a)<<6|colorToNibble(rgba.a)<<2|colorToNibble(rgba.b);
308 static void O2SurfaceWrite_argb32f_to_CMYK8888(O2Surface *self,int x,int y,O2argb32f *span,int length){
309 uint8_t* scanline = self->_pixelBytes + y * self->_bytesPerRow;
313 for(i=0;i<length;i++){
314 O2argb32f rgba=*span++;
316 *scanline++=O2ByteFromFloat(1.0-rgba.r);
317 *scanline++=O2ByteFromFloat(1.0-rgba.g);
318 *scanline++=O2ByteFromFloat(1.0-rgba.b);
319 *scanline++=O2ByteFromFloat(0);
323 static void O2SurfaceWrite_argb32f_to_argb8u_to_ANY(O2Surface *self,int x,int y,O2argb32f *span,int length){
324 O2argb8u span8888[length];
327 for(i=0;i<length;i++){
328 O2argb32f rgba=*span++;
330 span8888[i].r=O2ByteFromFloat(rgba.r);
331 span8888[i].g=O2ByteFromFloat(rgba.g);
332 span8888[i].b=O2ByteFromFloat(rgba.b);
333 span8888[i].a=O2ByteFromFloat(rgba.a);
335 self->_writeargb8u(self,x,y,span8888,length);
338 static BOOL initFunctionsForParameters(O2Surface *self,size_t bitsPerComponent,size_t bitsPerPixel,O2ColorSpaceRef colorSpace,O2BitmapInfo bitmapInfo){
339 self->_writeargb32f=O2SurfaceWrite_argb32f_to_argb8u_to_ANY;// default
341 switch(bitsPerComponent){
344 switch(bitsPerPixel){
348 switch(bitmapInfo&kO2BitmapByteOrderMask){
349 case kO2BitmapByteOrderDefault:
350 case kO2BitmapByteOrder16Little:
351 case kO2BitmapByteOrder32Little:
352 self->_writeargb32f=O2SurfaceWrite_argb32f_to_argb32fLittle;
355 case kO2BitmapByteOrder16Big:
356 case kO2BitmapByteOrder32Big:
357 self->_writeargb32f=O2SurfaceWrite_argb32f_to_argb32fBig;
364 switch(bitsPerPixel){
367 self->_writeargb32f=O2SurfaceWrite_argb32f_to_G8;
371 self->_writeargb32f=O2SurfaceWrite_argb32f_to_GA88;
378 if([colorSpace type]==kO2ColorSpaceModelRGB){
380 switch(bitmapInfo&kO2BitmapAlphaInfoMask){
381 case kO2ImageAlphaNone:
384 case kO2ImageAlphaLast:
385 case kO2ImageAlphaPremultipliedLast:
386 switch(bitmapInfo&kO2BitmapByteOrderMask){
387 case kO2BitmapByteOrderDefault:
388 case kO2BitmapByteOrder16Little:
389 case kO2BitmapByteOrder32Little:
390 self->_writeargb32f=O2SurfaceWrite_argb32f_to_ABGR8888;
391 self->_writeargb8u=O2SurfaceWrite_argb8u_to_ABGR8888;
394 case kO2BitmapByteOrder16Big:
395 case kO2BitmapByteOrder32Big:
396 self->_writeargb32f=O2SurfaceWrite_argb32f_to_argb8u;
397 self->_writeargb8u=O2SurfaceWrite_argb8u_to_argb8u;
403 case kO2ImageAlphaPremultipliedFirst:
404 switch(bitmapInfo&kO2BitmapByteOrderMask){
405 case kO2BitmapByteOrderDefault:
406 case kO2BitmapByteOrder16Little:
407 case kO2BitmapByteOrder32Little:
408 self->_writeargb8u=O2SurfaceWrite_argb8u_to_BGRA8888;
413 case kO2ImageAlphaFirst:
416 case kO2ImageAlphaNoneSkipLast:
419 case kO2ImageAlphaNoneSkipFirst:
423 else if([colorSpace type]==kO2ColorSpaceModelCMYK){
424 switch(bitmapInfo&kO2BitmapByteOrderMask){
425 case kO2BitmapByteOrderDefault:
426 case kO2BitmapByteOrder16Little:
427 case kO2BitmapByteOrder32Little:
430 case kO2BitmapByteOrder16Big:
431 case kO2BitmapByteOrder32Big:
432 self->_writeargb32f=O2SurfaceWrite_argb32f_to_CMYK8888;
441 switch(bitsPerPixel){
447 switch(bitmapInfo&kO2BitmapByteOrderMask){
448 case kO2BitmapByteOrderDefault:
449 case kO2BitmapByteOrder16Little:
450 case kO2BitmapByteOrder32Little:
451 self->_writeargb32f=O2SurfaceWrite_argb32f_to_BARG4444;
454 case kO2BitmapByteOrder16Big:
455 case kO2BitmapByteOrder32Big:
456 self->_writeargb32f=O2SurfaceWrite_argb32f_to_RGBA4444;
463 switch(bitsPerPixel){
469 self->_writeargb32f=O2SurfaceWrite_argb32f_to_RGBA2222;
475 switch(bitsPerPixel){
477 // self->_writeargb32f=O2SurfaceWriteSpan_largb32f_PRE_01;
488 -initWithBytes:(void *)bytes width:(size_t)width height:(size_t)height bitsPerComponent:(size_t)bitsPerComponent bytesPerRow:(size_t)bytesPerRow colorSpace:(O2ColorSpaceRef)colorSpace bitmapInfo:(O2BitmapInfo)bitmapInfo {
489 O2DataProvider *provider;
493 provider=[[[O2DataProvider alloc] initWithBytes:bytes length:bytesPerRow*height] autorelease];
497 if(bytesPerRow>0 && bytesPerRow<(width*bitsPerPixel)/8){
498 NSLog(@"invalid bytes per row=%zu",bytesPerRow);
503 bytesPerRow=(width*bitsPerPixel)/8;
505 NSMutableData *data=[NSMutableData dataWithLength:bytesPerRow*height*sizeof(uint8_t)]; // this will also zero the bytes
506 provider=[O2DataProviderCreateWithCFData((CFDataRef)data) autorelease];
510 if([super initWithWidth:width height:height bitsPerComponent:bitsPerComponent bitsPerPixel:bitsPerPixel bytesPerRow:bytesPerRow colorSpace:colorSpace bitmapInfo:bitmapInfo decoder: NULL provider:provider decode:NULL interpolate:YES renderingIntent:kO2RenderingIntentDefault]==nil)
513 if([provider isDirectAccess])
514 _pixelBytes=(void *)[provider bytes];
516 if(!initFunctionsForParameters(self,bitsPerComponent,_bitsPerPixel,colorSpace,bitmapInfo))
517 NSLog(@"O2Surface -init error, return");
519 _clampExternalPixels=NO; // only set to yes if premultiplied
520 pthread_mutex_init(&_lock,NULL);
525 _pixelBytes=NULL; // if we own it, it's in the provider, if not, no release
526 pthread_mutex_destroy(&_lock);
531 void O2SurfaceLock(O2Surface *surface) {
532 pthread_mutex_lock(&(surface->_lock));
535 void O2SurfaceUnlock(O2Surface *surface) {
536 pthread_mutex_unlock(&(surface->_lock));
539 -(void *)pixelBytes {
543 -(void)setWidth:(size_t)width height:(size_t)height reallocateOnlyIfRequired:(BOOL)roir {
550 _bytesPerRow=width*_bitsPerPixel/8;
552 NSUInteger size=_bytesPerRow*height*sizeof(uint8_t);
553 NSUInteger allocateSize=[[_provider data] length];
555 if((size>allocateSize) || (!roir && size!=allocateSize)){
558 NSMutableData *data=[NSMutableData dataWithLength:size];
559 _provider=O2DataProviderCreateWithCFData((CFDataRef)data);
560 _pixelBytes=[data mutableBytes];
564 void *O2SurfaceGetPixelBytes(O2Surface *surface) {
565 return surface->_pixelBytes;
568 size_t O2SurfaceGetWidth(O2Surface *surface) {
569 return surface->_width;
572 size_t O2SurfaceGetHeight(O2Surface *surface) {
573 return surface->_height;
576 size_t O2SurfaceGetBytesPerRow(O2Surface *surface) {
577 return surface->_bytesPerRow;
581 O2ImageRef O2SurfaceCreateImage(O2Surface *self) {
582 NSData *data=[[NSData alloc] initWithBytes:self->_pixelBytes length:self->_bytesPerRow*self->_height];
583 O2DataProviderRef provider=O2DataProviderCreateWithCFData((CFDataRef)data);
585 O2Image *result=O2ImageCreate(self->_width,self->_height,self->_bitsPerComponent,self->_bitsPerPixel,self->_bytesPerRow,self->_colorSpace,
586 self->_bitmapInfo,provider,self->_decode,self->_interpolate,self->_renderingIntent);
588 O2DataProviderRelease(provider);
594 void O2SurfaceWriteSpan_argb8u_PRE(O2Surface *self,int x,int y,O2argb8u *span,int length) {
598 self->_writeargb8u(self,x,y,span,length);
601 void O2SurfaceWriteSpan_largb32f_PRE(O2Surface *self,int x,int y,O2argb32f *span,int length) {
605 self->_writeargb32f(self,x,y,span,length);
609 /*-------------------------------------------------------------------*//*!
610 * \brief Applies Gaussian blur filter.
614 *//*-------------------------------------------------------------------*/
616 static O2argb32f gaussianReadPixel(int x, int y, int w, int h,O2argb32f *image)
618 if(x < 0 || x >= w || y < 0 || y >= h) { //apply tiling mode
619 return O2argb32fInit(0,0,0,0);
623 RI_ASSERT(x >= 0 && x < w && y >= 0 && y < h);
628 typedef struct O2GaussianKernel {
641 O2GaussianKernel *O2CreateGaussianKernelWithDeviation(O2Float stdDeviation){
642 O2GaussianKernel *kernel=NSZoneMalloc(NULL,sizeof(O2GaussianKernel));
646 O2Float stdDeviationX=stdDeviation;
647 O2Float stdDeviationY=stdDeviation;
649 RI_ASSERT(stdDeviationX > 0.0f && stdDeviationY > 0.0f);
650 RI_ASSERT(stdDeviationX <= RI_MAX_GAUSSIAN_STD_DEVIATION && stdDeviationY <= RI_MAX_GAUSSIAN_STD_DEVIATION);
652 //find a size for the kernel
653 O2Float totalWeightX = stdDeviationX*(O2Float)sqrt(2.0f*M_PI);
654 O2Float totalWeightY = stdDeviationY*(O2Float)sqrt(2.0f*M_PI);
655 const O2Float tolerance = 0.99f; //use a kernel that covers 99% of the total Gaussian support
657 O2Float expScaleX = -1.0f / (2.0f*stdDeviationX*stdDeviationX);
658 O2Float expScaleY = -1.0f / (2.0f*stdDeviationY*stdDeviationY);
662 O2Float sumX = 1.0f; //the weight of the middle entry counted already
665 e = (O2Float)exp((O2Float)(kernelWidth * kernelWidth) * expScaleX);
666 sumX += e*2.0f; //count left&right lobes
667 }while(sumX < tolerance*totalWeightX);
669 int kernelHeight = 0;
671 O2Float sumY = 1.0f; //the weight of the middle entry counted already
674 e = (O2Float)exp((O2Float)(kernelHeight * kernelHeight) * expScaleY);
675 sumY += e*2.0f; //count left&right lobes
676 }while(sumY < tolerance*totalWeightY);
678 //make a separable kernel
679 kernel->xSize=kernelWidth*2+1;
680 kernel->xValues=NSZoneMalloc(NULL,sizeof(O2Float)*kernel->xSize);
681 kernel->xShift = kernelWidth;
682 kernel->xScale = 0.0f;
684 for(i=0;i<kernel->xSize;i++){
685 int x = i-kernel->xShift;
686 kernel->xValues[i] = (O2Float)exp((O2Float)x*(O2Float)x * expScaleX);
687 kernel->xScale += kernel->xValues[i];
689 kernel->xScale = 1.0f / kernel->xScale; //NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
691 kernel->ySize=kernelHeight*2+1;
692 kernel->yValues=NSZoneMalloc(NULL,sizeof(O2Float)*kernel->ySize);
693 kernel->yShift = kernelHeight;
694 kernel->yScale = 0.0f;
695 for(i=0;i<kernel->ySize;i++)
697 int y = i-kernel->yShift;
698 kernel->yValues[i] = (O2Float)exp((O2Float)y*(O2Float)y * expScaleY);
699 kernel->yScale += kernel->yValues[i];
701 kernel->yScale = 1.0f / kernel->yScale; //NOTE: using the mathematical definition of the scaling term doesn't work since we cut the filter support early for performance
706 O2GaussianKernelRef O2GaussianKernelRetain(O2GaussianKernelRef kernel) {
713 void O2GaussianKernelRelease(O2GaussianKernelRef kernel) {
716 if(kernel->refCount<=0){
717 NSZoneFree(NULL,kernel->xValues);
718 NSZoneFree(NULL,kernel->yValues);
719 NSZoneFree(NULL,kernel);
724 static O2argb32f argbFromColor(O2ColorRef color){
725 size_t count=O2ColorGetNumberOfComponents(color);
726 const float *components=O2ColorGetComponents(color);
729 return O2argb32fInit(components[0],components[0],components[0],components[1]);
731 return O2argb32fInit(components[0],components[1],components[2],components[3]);
733 return O2argb32fInit(1,0,0,1);
736 void O2SurfaceGaussianBlur(O2Surface *self,O2Image * src, O2GaussianKernel *kernel,O2ColorRef color){
737 O2argb32f argbColor=argbFromColor(color);
739 //the area to be written is an intersection of source and destination image areas.
740 //lower-left corners of the images are aligned.
741 int w = RI_INT_MIN(self->_width, src->_width);
742 int h = RI_INT_MIN(self->_height, src->_height);
743 RI_ASSERT(w > 0 && h > 0);
745 O2argb32f *tmp=NSZoneMalloc(NULL,src->_width*src->_height*sizeof(O2argb32f));
747 //copy source region to tmp and do conversion
749 for(j=0;j<src->_height;j++){
750 O2argb32f *tmpRow=tmp+j*src->_width;
751 int i,width=src->_width;
752 O2argb32f *direct=O2Image_read_argb32f(src,0,j,tmpRow,width);
758 for(i=0;i<width;i++){
759 tmpRow[i].a=argbColor.a*tmpRow[i].a;
760 tmpRow[i].r=argbColor.r*tmpRow[i].a;
761 tmpRow[i].g=argbColor.g*tmpRow[i].a;
762 tmpRow[i].b=argbColor.b*tmpRow[i].a;
767 O2argb32f *tmp2=NSZoneMalloc(NULL,w*src->_height*sizeof(O2argb32f));
770 for(j=0;j<src->_height;j++){
772 O2argb32f sum=O2argb32fInit(0,0,0,0);
774 for(ki=0;ki<kernel->xSize;ki++){
775 int x = i+ki-kernel->xShift;
776 sum=O2argb32fAdd(sum, O2argb32fMultiplyByFloat(gaussianReadPixel(x, j, src->_width, src->_height, tmp),kernel->xValues[ki]));
778 tmp2[j*w+i] = O2argb32fMultiplyByFloat(sum, kernel->xScale);
784 O2argb32f sum=O2argb32fInit(0,0,0,0);
786 for(kj=0;kj<kernel->ySize;kj++){
787 int y = j+kj-kernel->yShift;
788 sum=O2argb32fAdd(sum, O2argb32fMultiplyByFloat(gaussianReadPixel(i, y, w, src->_height, tmp2), kernel->yValues[kj]));
790 sum=O2argb32fMultiplyByFloat(sum, kernel->yScale);
791 O2SurfaceWriteSpan_largb32f_PRE(self,i, j, &sum,1);
794 NSZoneFree(NULL,tmp);
795 NSZoneFree(NULL,tmp2);