/src/GraphicsUtilities.m
Objective C | 340 lines | 242 code | 49 blank | 49 comment | 26 complexity | 558bd734e2d476549b37e6571314dac8 MD5 | raw file
Possible License(s): GPL-3.0
- /*
-
- GraphicsUtilities.m ... Convenient functions for manipulating bitmaps
-
- Copyright (c) 2009, KennyTM~
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the KennyTM~ nor the names of its contributors may be
- used to endorse or promote products derived from this software without
- specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- */
- #include <math.h>
- #include <GraphicsUtilities.h>
- #import <UIKit/UIImage.h>
- CGImageRef GUImageCreateByConcatSubimages (CGImageRef img,
- CGRect subrect1,
- CGRect subrect2,
- bool tileVertically) {
- CGRect imgRect = CGRectZero;
- if (tileVertically)
- imgRect.size = CGSizeMake(subrect1.size.width, subrect1.size.height + subrect2.size.height);
- else
- imgRect.size = CGSizeMake(subrect1.size.width + subrect2.size.width, subrect1.size.height);
-
- CGImageRef subimg1 = CGImageCreateWithImageInRect(img, subrect1);
- CGImageRef subimg2 = CGImageCreateWithImageInRect(img, subrect2);
-
- GUCreateContext(c, imgRect.size.width, imgRect.size.height);
- if (tileVertically) {
- CGContextDrawImage(c, CGRectMake(0, 0, subrect2.size.width, subrect2.size.height), subimg2);
- CGContextDrawImage(c, CGRectMake(0, subrect2.size.height, subrect1.size.width, subrect1.size.height), subimg1);
- } else {
- CGContextDrawImage(c, CGRectMake(0, 0, subrect1.size.width, subrect1.size.height), subimg1);
- CGContextDrawImage(c, CGRectMake(subrect1.size.width, 0, subrect2.size.width, subrect2.size.height), subimg2);
- }
-
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
-
- CGImageRelease(subimg1);
- CGImageRelease(subimg2);
-
- CGContextRelease(c);
-
- return finalImg;
- }
- CGImageRef GUImageCreateByComposition (CGImageRef foreground,
- CGImageRef background,
- CGRect fgRect,
- CGRect bgSubRect) {
- GUCreateContext(c, bgSubRect.size.width, bgSubRect.size.height);
- CGImageRef subimage = NULL;
- if (background != NULL) {
- if (bgSubRect.size.width == CGImageGetWidth(background) && bgSubRect.size.height == CGImageGetHeight(background))
- subimage = CGImageRetain(background);
- else
- subimage = CGImageCreateWithImageInRect(background, bgSubRect);
- CGContextDrawImage(c, CGRectMake(0, 0, bgSubRect.size.width, bgSubRect.size.height), subimage);
- }
- CGContextDrawImage(c, fgRect, foreground);
-
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
-
- CGImageRelease(subimage);
- CGContextRelease(c);
-
- return finalImg;
- }
- CGImageRef GUImageCreateWithPatching(CGImageRef img, CGRect src, CGRect target) {
- CGRect imgRect = CGRectMake(0, 0, CGImageGetWidth(img), CGImageGetHeight(img));
- GUCreateContext(c, imgRect.size.width, imgRect.size.height);
-
- CGContextDrawImage(c, imgRect, img);
- CGImageRef subImg = CGImageCreateWithImageInRect(img, src);
- CGContextSetBlendMode(c, kCGBlendModeCopy);
- CGContextDrawImage(c, target, subImg);
-
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
-
- CGImageRelease(subImg);
- CGContextRelease(c);
- return finalImg;
- }
- CGImageRef GUImageCreateWithMask(CGImageRef src, CGImageRef mask) {
- GUCreateContextWithImageAuto(src);
- CGContextClipToMask(c, imgRect, mask);
- CGContextDrawImage(c, imgRect, src);
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
- CGContextRelease(c);
- return finalImg;
- }
- CGImageRef GUImageCreateWithCappedMask(CGImageRef src, CGImageRef mask, GUCaps caps) {
- GUCreateContextWithImageAuto(src);
- GUDrawImageWithCaps(c, imgRect, mask, caps);
- CGContextSetBlendMode(c, kCGBlendModeSourceIn);
- CGContextDrawImage(c, imgRect, src);
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
- CGContextRelease(c);
- return finalImg;
- }
-
- CGImageRef GUImageCreateWithCaps(CGImageRef img, CGRect rect, GUCaps caps) {
- GUCreateContext(c, rect.size.width, rect.size.height);
- GUDrawImageWithCaps(c, rect, img, caps);
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
- CGContextRelease(c);
- return finalImg;
- }
- void GUDrawImageWithCaps(CGContextRef c, CGRect rect, CGImageRef img, GUCaps caps) {
- // assert: img.width > caps.left+caps.right && img.height > caps.top+caps.bottom.
- size_t imgWidth = CGImageGetWidth(img), imgHeight = CGImageGetHeight(img);
- bool matchX = (rect.size.width == imgWidth), matchY = (rect.size.height == imgHeight);
-
- if (matchX && matchY) {
- // the caps are bigger than the image: just draw the image.
- CGContextDrawImage(c, rect, img);
- } else if (matchX) {
- // create a 3-part image vertically.
- CGImageRef top = CGImageCreateWithImageInRect(img,
- CGRectMake(0, 0,
- imgWidth, caps.top));
- CGImageRef middle = CGImageCreateWithImageInRect(img,
- CGRectMake(0, caps.top,
- imgWidth, imgHeight-caps.top-caps.bottom));
- CGImageRef bottom = CGImageCreateWithImageInRect(img,
- CGRectMake(0, imgHeight-caps.bottom,
- imgWidth, caps.bottom));
-
- CGContextDrawImage(c, CGRectMake(rect.origin.x, rect.origin.y+rect.size.height-caps.top,
- rect.size.width, caps.top), top);
- CGContextDrawImage(c, CGRectMake(rect.origin.x, rect.origin.y+caps.bottom,
- rect.size.width, rect.size.height-caps.top-caps.bottom), middle);
- CGContextDrawImage(c, CGRectMake(rect.origin.x, rect.origin.y,
- rect.size.width, caps.bottom), bottom);
-
- CGImageRelease(top);
- CGImageRelease(middle);
- CGImageRelease(bottom);
- } else if (matchY) {
- // create a 3-part image horizontally.
- CGImageRef left = CGImageCreateWithImageInRect(img, CGRectMake(0, 0,
- caps.left, imgHeight));
- CGImageRef middle = CGImageCreateWithImageInRect(img, CGRectMake(caps.left, 0,
- imgWidth-caps.left-caps.right, imgHeight));
- CGImageRef right = CGImageCreateWithImageInRect(img, CGRectMake(imgWidth-caps.right, 0,
- caps.right, imgHeight));
-
- CGContextDrawImage(c, CGRectMake(rect.origin.x, rect.origin.y,
- caps.left, rect.size.height), left);
- CGContextDrawImage(c, CGRectMake(rect.origin.x+caps.left, rect.origin.y,
- rect.size.width-caps.left-caps.right, rect.size.height), middle);
- CGContextDrawImage(c, CGRectMake(rect.origin.x+rect.size.width-caps.right, rect.origin.y,
- caps.right, rect.size.height), right);
-
- CGImageRelease(left);
- CGImageRelease(middle);
- CGImageRelease(right);
- } else {
- // create a 9-part image.
- /*
-
- +---+---+---+ ^
- | Q | W | E | | w3
- +---+---+---+ x
- | A | S | D | | w2
- +---+---+---+ x
- | Z | X | C | | w1
- +---+---+---+ v
- <-> <-> <->
- w1 w2 w3
-
- */
-
- CGFloat w1 = caps.left, w2 = imgWidth-caps.left-caps.right, w3 = caps.right;
- CGFloat h1 = caps.top, h2 = imgHeight-caps.top-caps.bottom, h3 = caps.bottom;
-
- CGFloat x1 = 0, x2 = w1, x3 = w1+w2;
- CGFloat y1 = 0, y2 = h1, y3 = h1+h2;
-
- CGImageRef Q = CGImageCreateWithImageInRect(img, CGRectMake(x1, y1, w1, h1));
- CGImageRef W = CGImageCreateWithImageInRect(img, CGRectMake(x2, y1, w2, h1));
- CGImageRef E = CGImageCreateWithImageInRect(img, CGRectMake(x3, y1, w3, h1));
- CGImageRef A = CGImageCreateWithImageInRect(img, CGRectMake(x1, y2, w1, h2));
- CGImageRef S = CGImageCreateWithImageInRect(img, CGRectMake(x2, y2, w2, h2));
- CGImageRef D = CGImageCreateWithImageInRect(img, CGRectMake(x3, y2, w3, h2));
- CGImageRef Z = CGImageCreateWithImageInRect(img, CGRectMake(x1, y3, w1, h3));
- CGImageRef X = CGImageCreateWithImageInRect(img, CGRectMake(x2, y3, w2, h3));
- CGImageRef C = CGImageCreateWithImageInRect(img, CGRectMake(x3, y3, w3, h3));
-
- w2 = rect.size.width-w1-w3;
- h2 = rect.size.height-h1-h3;
-
- x1 = rect.origin.x;
- x2 = rect.origin.x+w1;
- x3 = x2+w2;
- y3 = rect.origin.y;
- y2 = rect.origin.y+h3;
- y1 = y2+h2;
-
- CGContextDrawImage(c, CGRectMake(x1, y1, w1, h1), Q);
- CGContextDrawImage(c, CGRectMake(x2, y1, w2, h1), W);
- CGContextDrawImage(c, CGRectMake(x3, y1, w3, h1), E);
- CGContextDrawImage(c, CGRectMake(x1, y2, w1, h2), A);
- CGContextDrawImage(c, CGRectMake(x2, y2, w2, h2), S);
- CGContextDrawImage(c, CGRectMake(x3, y2, w3, h2), D);
- CGContextDrawImage(c, CGRectMake(x1, y3, w1, h3), Z);
- CGContextDrawImage(c, CGRectMake(x2, y3, w2, h3), X);
- CGContextDrawImage(c, CGRectMake(x3, y3, w3, h3), C);
-
- CGImageRelease(Q);
- CGImageRelease(W);
- CGImageRelease(E);
- CGImageRelease(A);
- CGImageRelease(S);
- CGImageRelease(D);
- CGImageRelease(Z);
- CGImageRelease(X);
- CGImageRelease(C);
- }
- }
- float GUAverageLuminance (CGImageRef img) {
- float retval = NAN;
- if (img == NULL)
- return retval;
-
- size_t height = CGImageGetHeight(img);
- size_t width = CGImageGetWidth(img);
- size_t area = width*height;
-
- struct{unsigned char r,g,b,a;}* data = calloc(area, 4);
- CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
- CGContextRef c = CGBitmapContextCreate(data, width, height, 8, 4*width, rgbSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
- CGColorSpaceRelease(rgbSpace);
-
- CGContextDrawImage(c, CGRectMake(0, 0, width, height), img);
-
- UInt32 A = 0, R = 0, G = 0, B = 0;
- for (int i = 0; i < area; ++ i) {
- R += data[i].r;
- G += data[i].g;
- B += data[i].b;
- A += data[i].a;
- }
-
- if (A != 0) {
- retval = GULuminance(R,G,B)/A;
- }
-
- CGContextRelease(c);
- free(data);
-
- return retval;
- }
- CGImageRef GUImageCreateWithPNG(const char* filename) {
- CGDataProviderRef data = CGDataProviderCreateWithFilename(filename);
- if (data == NULL)
- return NULL;
- else {
- CGImageRef retimg = CGImageCreateWithPNGDataProvider(data, NULL, false, kCGRenderingIntentDefault);
- CGDataProviderRelease(data);
- return retimg;
- }
- }
- UIImage* GUCreateUIImageAndRelease(CGImageRef img) {
- UIImage* retval = [UIImage imageWithCGImage:img];
- CGImageRelease(img);
- return retval;
- }
- CGImageRef GUImageCreateByReducingBrightness(CGImageRef img, CGFloat reductionRatio) {
- GUCreateContextWithImageAuto(img);
- CGContextDrawImage(c, imgRect, img);
- CGContextSetBlendMode(c, kCGBlendModeDestinationIn);
- CGContextSetAlpha(c, reductionRatio);
- CGContextFillRect(c, imgRect);
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
- CGContextRelease(c);
- return finalImg;
- }
- CGPathRef GUPathCreateRoundRect(CGRect rect, CGFloat radius) {
- CGFloat right = rect.origin.x + rect.size.width, top = rect.origin.y + rect.size.height;
- CGPoint centers[4];
- centers[0] = CGPointMake(rect.origin.x + radius, top - radius);
- centers[1] = CGPointMake(right - radius, top - radius);
- centers[2] = CGPointMake(right - radius, rect.origin.y + radius);
- centers[3] = CGPointMake(rect.origin.x + radius, rect.origin.y + radius);
-
- CGMutablePathRef path = CGPathCreateMutable();
- CGPathAddArc(path, NULL, centers[0].x, centers[0].y, radius, M_PI, M_PI/2, true);
- CGPathAddArc(path, NULL, centers[1].x, centers[1].y, radius, M_PI/2, 0, true);
- CGPathAddArc(path, NULL, centers[2].x, centers[2].y, radius, 0, -M_PI/2, true);
- CGPathAddArc(path, NULL, centers[3].x, centers[3].y, radius, -M_PI/2, -M_PI, true);
- CGPathCloseSubpath(path);
-
- return path;
- }
- CGImageRef GUImageCreateByClippingToRoundRect(CGImageRef img, CGRect rect, CGFloat radius) {
- GUCreateContextWithImageAuto(img);
- CGPathRef roundRect = GUPathCreateRoundRect(rect, radius);
- CGContextAddPath(c, roundRect);
- CGContextClip(c);
- CGContextDrawImage(c, imgRect, img);
- CGImageRef finalImg = CGBitmapContextCreateImage(c);
- CGContextRelease(c);
- CGPathRelease(roundRect);
- return finalImg;
- }