How to define a struct correctly - iphone

I have a struct where I define the size (width, height) of a square, and I don't know why the code doesn't work well. Here's the code that I'm using:
.h
struct size{
int width;
int height;
};
.m
struct size a;
a.width = 508;
a.height = 686;
// I use it here.
Any ideas?

If you want to use Apple provided types, you have:
CGSize for sizes (with width and height)
CGPoint for locations (with x and y)
and CGRect, which combines the two.
Example usage:
CGPoint p;
CGSize s;
CGRect r;
p.x = 1;
p.y = 2;
// or:
p = CGPointMake(1, 2);
s.width = 3;
s.height = 4;
// or:
s = CGSizeMake(3, 4);
r.origin.x = 1;
r.origin.y = 2;
r.size.width = 3;
r.size.height = 4;
// or:
r.origin = p;
r.size = s;
// or:
r = CGRectMake(1, 2, 3, 4);

Related

Drawing a ruler in objective c iPhone

I am trying to create a dynamic ruler using code from this post of Brad Larson
NSInteger majorTickInterval = 5;
NSInteger totalTravelRangeInMicrons = 1000;
NSInteger minorTickSpacingInMicrons = 50;
CGFloat currentHeight = 100;
int leftEdgeForTicks = 10;
int majorTickLength = 15;
int minorTickLength = 10;
NSInteger minorTickCounter = majorTickInterval;
NSInteger totalNumberOfTicks = totalTravelRangeInMicrons / minorTickSpacingInMicrons;
CGFloat minorTickSpacingInPixels = currentHeight / (CGFloat)totalNumberOfTicks;
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
for (NSInteger currentTickNumber = 0; currentTickNumber < totalNumberOfTicks; currentTickNumber++)
{
CGContextMoveToPoint(context, leftEdgeForTicks + 0.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
minorTickCounter++;
if (minorTickCounter >= majorTickInterval)
{
CGContextAddLineToPoint(context, round(leftEdgeForTicks + majorTickLength) + 7**.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
minorTickCounter = 0;
}
else
{
CGContextAddLineToPoint(context, round(leftEdgeForTicks + minorTickLength) + 0.5, round(currentTickNumber * minorTickSpacingInPixels) + 0.5);
}
}
CGContextStrokePath(context);
But the issue is that it is creating ticks vertically not horizontally as in below screenshot:
While I want to draw a ruler like this:
Also it is not giving me more than 25 ticks, I have played with the code but still unsuccessful.
Any guidance how can I resolve this issue.
Here is an implementation, from the top of my head... I think it is important to keep it readable.
CGFloat leftMargin= 10;
CGFloat topMargin = 10;
CGFloat height = 30;
CGFloat width = 200;
CGFloat minorTickSpace = 10;
int multiple = 5; // number of minor ticks per major tick
CGFloat majorTickLength = 20; // must be smaller or equal height,
CGFloat minorTickLength = 10; // must be smaller than majorTickLength
CGFloat baseY = topMargin + height;
CGFloat minorY = baseY - minorTickLength;
CGFloat majorY = baseY - majorTickLength;
CGFloat majorTickSpace = minorTickSpace * multiple;
int step = 0;
for (CGFloat x = leftMargin; x <= leftMargin + width, x += minorTickLength) {
CGContextMoveToPoint(context, x, baseY);
CGFloat endY = (step*multiple*minorTickLength == x) ? majorY : minorY;
CGContextAddLineToPoint(context, x, endY);
step++; // step contains the minorTickCount in case you want to draw labels
}
CGContextStrokePath(context);

iPhone paint bucket

I am working on implementing a flood-fill paint-bucket tool in an iPhone app and am having some trouble with it. The user is able to draw and I would like the paint bucket to allow them to tap a spot and fill everything of that color that is connected.
Here's my idea:
1) Start at the point the user selects
2) Save points checked to a NSMutableArray so they don't get re-checked
3) If the pixel color at the current point is the same as the original clicked point, save to an array to be changed later
4) If the pixel color at the current point is different than the original, return. (boundary)
5) Once finished scanning, go through the array of pixels to change and set them to the new color.
But this is not working out so far. Any help or knowledge of how to do this would be greatly appreciated! Here is my code.
-(void)flood:(int)x:(int)y
{
//NSLog(#"Flood %i %i", x, y);
CGPoint point = CGPointMake(x, y);
NSValue *value = [NSValue valueWithCGPoint:point];
//Don't repeat checked pixels
if([self.checkedFloodPixels containsObject:value])
{
return;
}
else
{
//If not checked, mark as checked
[self.checkedFloodPixels addObject:value];
//Make sure in bounds
if([self isOutOfBounds:x:y] || [self reachedStopColor:x:y])
{
return;
}
//Go to adjacent points
[self flood:x+1:y];
[self flood:x-1:y];
[self flood:x:y+1];
[self flood:x:y-1];
}
}
- (BOOL)isOutOfBounds:(int)x:(int)y
{
BOOL outOfBounds;
if(y > self.drawImage.frame.origin.y && y < (self.drawImage.frame.origin.y + self.drawImage.frame.size.height))
{
if(x > self.drawImage.frame.origin.x && x < (self.drawImage.frame.origin.x + self.drawImage.frame.size.width))
{
outOfBounds = NO;
}
else
{
outOfBounds = YES;
}
}
else
{
outOfBounds = YES;
}
if(outOfBounds)
NSLog(#"Out of bounds");
return outOfBounds;
}
- (BOOL)reachedStopColor:(int)x:(int)y
{
CFDataRef theData = CGDataProviderCopyData(CGImageGetDataProvider(self.drawImage.image.CGImage));
const UInt8 *pixelData = CFDataGetBytePtr(theData);
int red = 0;
int green = 1;
int blue = 2;
//RGB for point being checked
float newPointR;
float newPointG;
float newPointB;
//RGB for point initially clicked
float oldPointR;
float oldPointG;
float oldPointB;
int index;
BOOL reachedStopColor = NO;
//Format oldPoint RBG - pixels are every 4 bytes so round to 4
index = lastPoint.x * lastPoint.y;
if(index % 4 != 0)
{
index -= 2;
index /= 4;
index *= 4;
}
//Get into 0.0 - 1.0 value
oldPointR = pixelData[index + red];
oldPointG = pixelData[index + green];
oldPointB = pixelData[index + blue];
oldPointR /= 255.0;
oldPointG /= 255.0;
oldPointB /= 255.0;
oldPointR *= 1000;
oldPointG *= 1000;
oldPointB *= 1000;
int oldR = oldPointR;
int oldG = oldPointG;
int oldB = oldPointB;
oldPointR = oldR / 1000.0;
oldPointG = oldG / 1000.0;
oldPointB = oldB / 1000.0;
//Format newPoint RBG
index = x*y;
if(index % 4 != 0)
{
index -= 2;
index /= 4;
index *= 4;
}
newPointR = pixelData[index + red];
newPointG = pixelData[index + green];
newPointB = pixelData[index + blue];
newPointR /= 255.0;
newPointG /= 255.0;
newPointB /= 255.0;
newPointR *= 1000;
newPointG *= 1000;
newPointB *= 1000;
int newR = newPointR;
int newG = newPointG;
int newB = newPointB;
newPointR = newR / 1000.0;
newPointG = newG / 1000.0;
newPointB = newB / 1000.0;
//Check if different color
if(newPointR < (oldPointR - 0.02f) || newPointR > (oldPointR + 0.02f))
{
if(newPointG < (oldPointG - 0.02f) || newPointG > (oldPointG + 0.02f))
{
if(newPointB < (oldPointB - 0.02f) || newPointB > (oldPointB + 0.02f))
{
reachedStopColor = YES;
NSLog(#"Different Color");
}
else
{
NSLog(#"Same Color3");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
}
else
{
NSLog(#"Same Color2");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
}
else
{
NSLog(#"Same Color1");
NSNumber *num = [NSNumber numberWithInt:index];
[self.pixelsToChange addObject:num];
}
CFRelease(theData);
if(reachedStopColor)
NSLog(#"Reached stop color");
return reachedStopColor;
}
-(void)fillAll
{
CGContextRef ctx;
CGImageRef imageRef = self.drawImage.image.CGImage;
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width * 4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
int red = 0;
int green = 1;
int blue = 2;
int index;
NSNumber *num;
for(int i = 0; i < [self.pixelsToChange count]; i++)
{
num = [self.pixelsToChange objectAtIndex:i];
index = [num intValue];
rawData[index + red] = (char)[[GameManager sharedManager] RValue];
rawData[index + green] = (char)[[GameManager sharedManager] GValue];
rawData[index + blue] = (char)[[GameManager sharedManager] BValue];
}
ctx = CGBitmapContextCreate(rawData,
CGImageGetWidth( imageRef ),
CGImageGetHeight( imageRef ),
8,
CGImageGetBytesPerRow( imageRef ),
CGImageGetColorSpace( imageRef ),
kCGImageAlphaPremultipliedLast );
imageRef = CGBitmapContextCreateImage (ctx);
UIImage* rawImage = [UIImage imageWithCGImage:imageRef];
CGContextRelease(ctx);
self.drawImage.image = rawImage;
free(rawData);
}
so i found this (i know the question might be irrelevant now but for people who are still looking for something like this it's not ) :
to get color at pixel from context (modified code from here) :
- (UIColor*) getPixelColorAtLocation:(CGPoint)point {
UIColor* color;
CGContextRef cgctx = UIGraphicsGetCurrentContext();
unsigned char* data = CGBitmapContextGetData (cgctx);
if (data != NULL) {
int offset = 4*((ContextWidth*round(point.y))+round(point.x)); //i dont know how to get ContextWidth from current context so i have it as a instance variable in my code
int alpha = data[offset];
int red = data[offset+1];
int green = data[offset+2];
int blue = data[offset+3];
color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
}
if (data) { free(data); }
return color;
}
and the fill algorithm: is here
This is what i'm using but the fill itself is quite slow compared to CGPath drawing styles. Tho if you're rendering offscreen and/or you fill it dynamically like this it looks kinda cool :

Blur an UIImage on change of slider

I have tried gaussian blur and checked out all the questions on stackoverflow but no one of them solved my crash issue.Please help is there is any other way to blur image other than gaussian blur algorithm. My image size is 768x1024 and the loops iterates for 2*1024*768 times and this is not feasible.
CGContextRef NYXImageCreateARGBBitmapContext(const size_t width, const size_t height, const size_t bytesPerRow)
{
/// Use the generic RGB color space
/// We avoid the NULL check because CGColorSpaceRelease() NULL check the value anyway, and worst case scenario = fail to create context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
/// Create the bitmap context, we want pre-multiplied ARGB, 8-bits per component
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8/*Bits per component*/, bytesPerRow, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
return bmContext;
}
-(UIImage*)blurredImageUsingGaussFactor:(NSUInteger)gaussFactor andPixelRadius:(NSUInteger)pixelRadius
{
CGImageRef cgImage = self.CGImage;
const size_t originalWidth = CGImageGetWidth(cgImage);
const size_t originalHeight = CGImageGetHeight(cgImage);
const size_t bytesPerRow = originalWidth * 4;
CGContextRef context = NYXImageCreateARGBBitmapContext(originalWidth, originalHeight, bytesPerRow);
if (!context)
return nil;
unsigned char *srcData, *destData, *finalData;
size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);
size_t bpp = CGBitmapContextGetBitsPerPixel(context) / 8;
CGRect rect = {{0.0f, 0.0f}, {width, height}};
CGContextDrawImage(context, rect, cgImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
srcData = (unsigned char*)CGBitmapContextGetData(context);
if (srcData != NULL)
{
size_t dataSize = bpr * height;
finalData = malloc(dataSize);
destData = malloc(dataSize);
memcpy(finalData, srcData, dataSize);
memcpy(destData, srcData, dataSize);
int sums[gaussFactor];
size_t i, /*x, y,*/ k;
int gauss_sum = 0;
size_t radius = pixelRadius * 2 + 1;
int *gauss_fact = malloc(radius * sizeof(int));
for (i = 0; i < pixelRadius; i++)
{
gauss_fact[i] = 1 + (gaussFactor * i);
gauss_fact[radius - (i + 1)] = 1 + (gaussFactor * i);
gauss_sum += (gauss_fact[i] + gauss_fact[radius - (i + 1)]);
}
gauss_fact[(radius - 1) / 2] = 1 + (gaussFactor*pixelRadius);
gauss_sum += gauss_fact[(radius - 1) / 2];
unsigned char *p1, *p2, *p3;
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
p1 = srcData + bpp * (y * width + x);
p2 = destData + bpp * (y * width + x);
for (i = 0; i < gaussFactor; i++)
sums[i] = 0;
for (k = 0; k < radius ; k++)
{
if ((y - ((radius - 1) >> 1) + k) < height)
p1 = srcData + bpp * ((y - ((radius - 1) >> 1) + k) * width + x);
else
p1 = srcData + bpp * (y * width + x);
for (i = 0; i < bpp; i++)
sums[i] += p1[i] * gauss_fact[k];
}
for (i = 0; i < bpp; i++)
p2[i] = sums[i] / gauss_sum;
}
}
for (size_t y = 0; y < height; y++)
{
for (size_t x = 0; x < width; x++)
{
p2 = destData + bpp * (y * width + x);
p3 = finalData + bpp * (y * width + x);
for (i = 0; i < gaussFactor; i++)
sums[i] = 0;
for(k = 0; k < radius ; k++)
{
if ((x - ((radius - 1) >> 1) + k) < width)
p1 = srcData + bpp * ( y * width + (x - ((radius - 1) >> 1) + k));
else
p1 = srcData + bpp * (y * width + x);
for (i = 0; i < bpp; i++)
sums[i] += p2[i] * gauss_fact[k];
}
for (i = 0; i < bpp; i++)
{
p3[i] = sums[i] / gauss_sum;
}
}
}
}
size_t bitmapByteCount = bpr * height;
///////Here was the problem.. you had given srcData instead of destData.. Rest all
//were perfect...
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, destData, bitmapByteCount, NULL);
CGImageRef blurredImageRef = CGImageCreate(width, height, CGBitmapContextGetBitsPerComponent(context), CGBitmapContextGetBitsPerPixel(context), CGBitmapContextGetBytesPerRow(context), CGBitmapContextGetColorSpace(context), CGBitmapContextGetBitmapInfo(context), dataProvider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
if (destData)
free(destData);
if (finalData)
free(finalData);
UIImage* retUIImage = [UIImage imageWithCGImage:blurredImageRef];
CGImageRelease(blurredImageRef);
return retUIImage;
}
I've made a small StackBlur extension to UIImage. StackBlur is close to GaussianBlur but much faster.
Check it at: https://github.com/tomsoft1/StackBluriOS
tiny note... there's a typo just on that ReadMe, "normalized" for "normalize"
Not sure about how to blur an image.
This may help is you want to blur an UIImageView or any view.
UIView *myView = self.theImageView;
CALayer *layer = [myView layer];
[layer setRasterizationScale:0.25];
[layer setShouldRasterize:YES];
You can undo it by setting the rasterization scale back to 1.
[layer setRasterizationScale:1.0];
UPDATE:
The below Apple sample code includes a blur/sharp effect. (using Open GL)
See if it helps, http://developer.apple.com/library/ios/#samplecode/GLImageProcessing/Introduction/Intro.html
What you probably want is a Box Blur algorithm. It is about 10 times faster than Gaussian blur and produces nice results. I have the code running on Android, I just haven't ported it to iOS yet. Here is the source.
Should only take about 10 minutes to port to iOS. The functions will work as is, you just need to access the image bytes (as you are doing in the source code above) and feed them to functions.

polaroid filter from UIImage

I am trying to implement some image filters, like polaroid, in iphone. I searched on how to filter an existing UIImage to convert it into a polaroid style and come across this stackoverflow link. Taking the answer there as a starting point, I looped through each pixel of the image, taking RGB values, and converted them to HSV, up to this point I have been successful. So this is what I have done (anyone is free to point any mistakes..)
double minRGB(double r, double g, double b){
if (r < g){
if (r < b){
return r;
}else {
return b;
}
}else {
if (g < b){
return g;
}else{
return b;
}
}
}
double maxRGB(double r, double g, double b){
if (r > g){
if (r > b){
return r;
}else {
return b;
}
}else {
if (g > b){
return g;
}else {
return b;
}
}
}
void rgbToHsv(double redIn,double greenIn,double blueIn,double *hue,double *saturation,double* value){
double min,max,delta;
min = minRGB(redIn,greenIn,blueIn);
max = maxRGB(redIn,greenIn,blueIn);
*value = max;
delta = max - min;
if (max != 0) {
*saturation = delta/max;
}else {
*saturation = 0;
*hue = -1.0;
return ;
}
if (redIn == max) {
*hue = (greenIn - blueIn)/delta;
}else if (greenIn == max) {
*hue = 2 + (blueIn - redIn)/delta;
}else {
*hue = 4 + (redIn - greenIn)/delta;
}
*hue *= 60.0;
if (*hue < 0) {
*hue += 360.0;
}
}
void hsvToRgb(double h,double s, double v, double *r,double *g, double *b){
int i;
float f, p, q, t;
if( s == 0 ) {
// achromatic (grey)
*r = *g = *b = v;
return;
}
h /= 60; // sector 0 to 5
i = floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i ) {
case 0:
*r = v;
*g = t;
*b = p;
break;
case 1:
*r = q;
*g = v;
*b = p;
break;
case 2:
*r = p;
*g = v;
*b = t;
break;
case 3:
*r = p;
*g = q;
*b = v;
break;
case 4:
*r = t;
*g = p;
*b = v;
break;
default: // case 5:
*r = v;
*g = p;
*b = q;
break;
}
}
-(void)makeImagePolaroid:(UIImage*)myImage{
CGImageRef originalImage = [myImage CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL,CGImageGetWidth(originalImage),CGImageGetHeight(originalImage),8,CGImageGetWidth(originalImage)*4,colorSpace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGBitmapContextGetWidth(bitmapContext), CGBitmapContextGetHeight(bitmapContext)), originalImage);
UInt8 *data = CGBitmapContextGetData(bitmapContext);
int numComponents = 4;
int bytesInContext = CGBitmapContextGetHeight(bitmapContext) * CGBitmapContextGetBytesPerRow(bitmapContext);
double redIn, greenIn, blueIn,alphaIn;
double hue,saturation,value;
for (int i = 0; i < bytesInContext; i += numComponents) {
redIn = (double)data[i]/255.0;
greenIn = (double)data[i+1]/255.0;
blueIn = (double)data[i+2]/255.0;
alphaIn = (double)data[i+3]/255.0;
rgbToHsv(redIn,greenIn,blueIn,&hue,&saturation,&value);
hue = hue * 0.7;
if (hue > 360) {
hue = 360;
}
saturation = saturation *1.3;
if (saturation > 1.0) {
saturation = 1.0;
}
value = value * 0.8;
if (value > 1.0) {
value = 1.0;
}
hsvToRgb(hue,saturation,value,&redIn,&greenIn,&blueIn);
data[i] = redIn * 255.0;
data[i+1] = greenIn * 255.0;
data[i+2] = blueIn * 255.0;
}
CGImageRef outImage = CGBitmapContextCreateImage(bitmapContext);
myImage = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return myImage;
}
Now my idea about image processing is very childish (not even amateurish). I read this and tried to adjust the saturation and hue to see if I can get a polaroid effect..I think I am missing something, for I got every effect on earth other than a polaroid (saying that I havent got anything)..
Is there any document on net (or
books) which tells about image
filtering on a programmers point of
view? (and not on a designers point
of view and without a photoshop
screenshot)
What is the hue, saturation, value
difference I have to make on a pixel
so that I can make it polaroid?
And third, Am I on the right track?
Thanks in advance..
This might be helpful, from Camera+ taking filters from photoshop and reproducing them for iOS.
http://taptaptap.com/blog/creating-a-camera-plus-fx/
int step=10;// variable value that changes the level of saturation
int red = pixelRedVal;
int green = pixelGreenVal;
int blue = pixelBlueVal;
int avg = (red + green + blue) / 3;
pixelBuf[r] = SAFECOLOR((avg + step * (red - avg)));
pixelBuf[g] = SAFECOLOR((avg + step * (green - avg)));
pixelBuf[b] = SAFECOLOR((avg + step * (blue - avg)));
where SAFECOLOR is a macro
define SAFECOLOR(color) MIN(255,MAX(0,color))
and for Brightness int step=10;// variable value that changes the level of saturation
int red = pixelRedVal;
int green = pixelGreenVal;
int blue = pixelBlueVal;
pixelBuf[r] = SAFECOLOR(red * step);
pixelBuf[g] = SAFECOLOR(green * step);
pixelBuf[b] = SAFECOLOR(blue * step);
You can simply use this: with different parameters
// Note: the hue input ranges from 0.0 to 1.0, both red. Values outside this range will be clamped to 0.0 or 1.0.
//Polaroid with HSB parameter
- (UIImage*) polaroidishEffectWithHue:(CGFloat)hue saturation:(CGFloat)sat brightness:(CGFloat)bright alpha:(CGFloat)alpha
{
// Find the image dimensions.
CGSize imageSize = [self size];
CGRect imageExtent = CGRectMake(0,0,imageSize.width,imageSize.height);
// Create a context containing the image.
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawAtPoint:CGPointMake(0,0)];
// Draw the hue on top of the image.
CGContextSetBlendMode(context, kCGBlendModeHue);
[[UIColor colorWithHue:hue saturation:sat brightness:bright alpha:alpha] set];
UIBezierPath *imagePath = [UIBezierPath bezierPathWithRect:imageExtent];
[imagePath fill];
// Retrieve the new image.
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}

Box Blur CGImageRef

I'm attempting to implement a simple Box Blur, but am having issues. Namely, instead of blurring the images it seems to be converting each pixel to either: Red, Green, Blue or Black. Not sure exactly what is going on. Any help would be appreciated.
Please note, this code is simply a first pass to get it working, I'm not worried about speed... yet.
- (CGImageRef)blur:(CGImageRef)base radius:(int)radius {
CGContextRef ctx;
CGImageRef imageRef = base;
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = malloc(height * width *4);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
char red = 0;
char green = 0;
char blue = 0;
for (int widthIndex = radius; widthIndex < width - radius; widthIndex++) {
for (int heightIndex = radius; heightIndex < height - radius; heightIndex++) {
red = 0;
green = 0;
blue = 0;
for (int radiusY = -radius; radiusY <= radius; ++radiusY) {
for (int radiusX = -radius; radiusX <= radius; ++radiusX) {
int xIndex = widthIndex + radiusX;
int yIndex = heightIndex + radiusY;
int index = ((yIndex * width) + xIndex) * 4;
red += rawData[index];
green += rawData[index + 1];
blue += rawData[index + 2];
}
}
int currentIndex = ((heightIndex * width) + widthIndex) * 4;
int divisor = (radius * 2) + 1;
divisor *= divisor;
int finalRed = red / divisor;
int finalGreen = green / divisor;
int finalBlue = blue / divisor;
rawData[currentIndex] = (char)finalRed;
rawData[currentIndex + 1] = (char)finalGreen;
rawData[currentIndex + 2] = (char)finalBlue;
}
}
ctx = CGBitmapContextCreate(rawData,
CGImageGetWidth( imageRef ),
CGImageGetHeight( imageRef ),
8,
CGImageGetBytesPerRow( imageRef ),
CGImageGetColorSpace( imageRef ),
kCGImageAlphaPremultipliedLast );
imageRef = CGBitmapContextCreateImage (ctx);
CGContextRelease(ctx);
free(rawData);
[(id)imageRef autorelease];
return imageRef;
}
The char colors should be declared as int.
int red = 0;
int green = 0;
int blue = 0;
I just have a comment. I used this script and it really works well and fast. the only thing is that it leaves the frame with width of radius which is not blurred. So I have modified it a bit so that it blurs whole area using mirroring technique near the edges.
For this one needs to put the following lines:
// Mirroring the part between edge and blur raduis
if (xIndex<0) xIndex=-xIndex-1; else if (xIndex>width-1) xIndex=2*width-xIndex-1;
if (yIndex<0) yIndex=-yIndex-1; else if (yIndex>height-1) yIndex=2*height-yIndex-1;
after these lines:
int xIndex = widthIndex + radiusX;
int yIndex = heightIndex + radiusY;
And then replace the headers of for loops:
for (int widthIndex = radius; widthIndex < width - radius; widthIndex++) {
for (int heightIndex = radius; heightIndex < height - radius; heightIndex++) {
with these headers:
for (int widthIndex = 0; widthIndex < width; widthIndex++) {
for (int heightIndex = 0; heightIndex < height; heightIndex++) {