RSS

(root)/iphone/common : 64 : source/ImageWell.m

To get this branch, use:
bzr branch /browse/iphone/common

« back to all changes in this revision

Viewing changes to source/ImageWell.m

Dömötör Gulyás
2010-06-23 15:02:43
Revision ID: dognotdog@gmail.com-20100623130243-dxezs4230sqdltpa
adds ImageWell to common, from Jigs; minor bugfix in messenger

Show diffs side-by-side

added added

removed removed

 
1
//
 
2
//  ImageWell.m
 
3
//  Jigs
 
4
//
 
5
//  Created by döme on 11.08.2009.
 
6
//  Copyright 2009 __MyCompanyName__. All rights reserved.
 
7
//
 
8
 
 
9
#import "ImageWell.h"
 
10
#import "ElAnimation.h"
 
11
 
 
12
#import <QuartzCore/QuartzCore.h>
 
13
 
 
14
@class UIPopoverController;
 
15
 
 
16
void createPathInRoundedRect(CGContextRef c, CGRect rect, float radius)
 
17
{
 
18
        CGContextBeginPath(c);
 
19
        CGContextMoveToPoint(c, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) );
 
20
        CGContextAddLineToPoint(c, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect));
 
21
        CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect) + radius, radius);
 
22
        CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect) - radius);
 
23
        CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect), radius);
 
24
        CGContextAddLineToPoint(c, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect));
 
25
        CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect) - radius, radius);
 
26
        CGContextAddLineToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect) + radius );
 
27
        CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMinX(rect) + radius, CGRectGetMinY(rect), radius);
 
28
        CGContextClosePath(c);
 
29
        
 
30
 
 
31
}
 
32
 
 
33
@implementation UIImage (ElImageView)
 
34
 
 
35
CGImageRef CreateScaledCGImageFromCGImage(CGImageRef image, CGSize size, UIImageOrientation orientation)
 
36
{
 
37
        int srcWidth = size.width;
 
38
        int srcHeight = size.height;
 
39
        int dstWidth = size.width;
 
40
        int dstHeight = size.height;
 
41
        
 
42
        switch (orientation)
 
43
        {
 
44
                case UIImageOrientationLeft:
 
45
                case UIImageOrientationLeftMirrored:
 
46
                case UIImageOrientationRight:
 
47
                case UIImageOrientationRightMirrored:
 
48
                {
 
49
                        srcWidth = dstHeight;
 
50
                        srcHeight = dstWidth;
 
51
                        break;
 
52
                }
 
53
        }
 
54
        
 
55
 
 
56
        //UIGraphicsPushContext(UIGraphicsGetCurrentContext());
 
57
         
 
58
        // Declare the number of bytes per row. Each pixel in the bitmap in this
 
59
        // example is represented by 4 bytes; 8 bits each of red, green, blue, and
 
60
        // alpha.
 
61
        size_t bitmapBytesPerRow   = (dstWidth * 4);
 
62
        size_t bitmapByteCount     = (bitmapBytesPerRow * dstHeight);
 
63
         
 
64
        // Allocate memory for image data. This is the destination in memory
 
65
        // where any drawing to the bitmap context will be rendered.
 
66
        void* bitmapData = malloc( bitmapByteCount );
 
67
        if (bitmapData == NULL)
 
68
        {
 
69
                return nil;
 
70
        }
 
71
         
 
72
        // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
 
73
        // per component. Regardless of what the source image format is
 
74
        // (CMYK, Grayscale, and so on) it will be converted over to the format
 
75
        // specified here by CGBitmapContextCreate.
 
76
        CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
 
77
        CGContextRef context = CGBitmapContextCreate(bitmapData,dstWidth,dstHeight,8,bitmapBytesPerRow,
 
78
        colorspace,kCGImageAlphaPremultipliedFirst);
 
79
        CGColorSpaceRelease(colorspace);
 
80
         
 
81
        if (context == NULL)
 
82
        // error creating context
 
83
        {
 
84
                free(bitmapData);
 
85
                return nil;
 
86
        }
 
87
        
 
88
        CGFloat angle = 0.0;
 
89
        switch (orientation)
 
90
        {
 
91
                case UIImageOrientationLeft:
 
92
                case UIImageOrientationLeftMirrored:
 
93
                        angle = M_PI_2;
 
94
                        break;
 
95
                case UIImageOrientationRight:
 
96
                case UIImageOrientationRightMirrored:
 
97
                        angle = -M_PI_2;
 
98
                        break;
 
99
                case UIImageOrientationDown:
 
100
                case UIImageOrientationDownMirrored:
 
101
                        angle = M_PI;
 
102
                        break;
 
103
        }
 
104
        
 
105
        CGContextTranslateCTM(context, 0.5f*(float)dstWidth, 0.5*(float)dstHeight);
 
106
        CGContextRotateCTM(context, angle);
 
107
        CGContextTranslateCTM(context, -0.5f*(float)srcWidth, -0.5*(float)srcHeight);
 
108
        // Draw the image to the bitmap context. Once we draw, the memory
 
109
        // allocated for the context for rendering will then contain the
 
110
        // raw image data in the specified color space.
 
111
        
 
112
        
 
113
        
 
114
        CGContextDrawImage(context, CGRectMake(0,0,srcWidth, srcHeight), image);
 
115
         
 
116
        CGImageRef imgRef = CGBitmapContextCreateImage(context);
 
117
        CGContextRelease(context);
 
118
        free(bitmapData);
 
119
        
 
120
        //UIGraphicsPopContext();
 
121
         
 
122
        return imgRef;
 
123
}
 
124
 
 
125
 
 
126
- (UIImage*) scaledToSize: (CGSize) size
 
127
{
 
128
        CGImageRef imgref = CreateScaledCGImageFromCGImage([self CGImage], size, [self imageOrientation]);
 
129
        if (!imgref)
 
130
                return nil;
 
131
                
 
132
        UIImage* img = [UIImage imageWithCGImage: imgref];
 
133
        
 
134
        CGImageRelease(imgref);
 
135
                
 
136
        return img;
 
137
}
 
138
 
 
139
@end
 
140
 
 
141
@implementation ElImageView
 
142
 
 
143
- (id) initWithFrame: (CGRect) frame
 
144
{
 
145
    if (!(self = [super initWithFrame: frame]))
 
146
                return nil;
 
147
 
 
148
        borderColor = [[UIColor grayColor] retain];
 
149
        cornerRadius = 5.0f;
 
150
        borderWidth = 1.0f;
 
151
        imageAlpha = 1.0f;
 
152
 
 
153
        [self setBackgroundColor: [UIColor redColor]];
 
154
 
 
155
        return self;
 
156
}
 
157
 
 
158
 
 
159
- (id) initWithCoder: (NSCoder*) coder
 
160
{
 
161
    if (!(self = [super initWithCoder: coder]))
 
162
                return nil;
 
163
        
 
164
        borderColor = [[UIColor grayColor] retain];
 
165
        cornerRadius = 5.0f;
 
166
        borderWidth = 1.0f;
 
167
        imageAlpha = 1.0f;
 
168
        
 
169
        fillView = NO;
 
170
        
 
171
        [self setBackgroundColor: [UIColor clearColor]];
 
172
 
 
173
        return self;
 
174
}
 
175
 
 
176
- (void) dealloc
 
177
{
 
178
        [image release];
 
179
//      [_cachedImageForDrawing release];
 
180
        [borderColor release];
 
181
    [super dealloc];
 
182
}
 
183
 
 
184
/*
 
185
- (void) setFrame: (CGRect) frame
 
186
{
 
187
        [super setFrame: frame];
 
188
        if (!CGRectEqualToRect(frame, [self frame]))
 
189
        {
 
190
                [_cachedImageForDrawing release];
 
191
                _cachedImageForDrawing = nil;
 
192
        }
 
193
}
 
194
*/
 
195
- (void) drawRect: (CGRect) rect
 
196
{
 
197
        CGContextRef c = UIGraphicsGetCurrentContext();
 
198
        //[[UIColor blueColor] set];
 
199
        //CGContextFillRect(c, rect);
 
200
 
 
201
        CGContextSaveGState(c);
 
202
 
 
203
        UIImage* img = nil;
 
204
        
 
205
        @synchronized(self)
 
206
        {
 
207
                img = image;
 
208
        }
 
209
        if (!img)
 
210
                img = [UIImage imageNamed: @"image-not-found-icon.png"];
 
211
        
 
212
        CGRect bounds = CGRectInset([self bounds], 0.5*borderWidth,0.5*borderWidth);
 
213
        CGSize imgSize = [img size];
 
214
        
 
215
        
 
216
        
 
217
        float drawHeight = imgSize.height;
 
218
        float drawWidth = imgSize.width;
 
219
        
 
220
        float heightR = imgSize.height/bounds.size.height;
 
221
        float widthR = imgSize.width/bounds.size.width;
 
222
        
 
223
        if (heightR > 1.0f)
 
224
        {
 
225
                drawHeight = bounds.size.height;
 
226
                drawWidth *= 1.0f/heightR;
 
227
                widthR = drawWidth/bounds.size.width;
 
228
        }
 
229
 
 
230
        if (widthR > 1.0f)
 
231
        {
 
232
                drawWidth = bounds.size.width;
 
233
                drawHeight *= 1.0f/widthR;
 
234
        }
 
235
        
 
236
        CGRect drawRect = CGRectMake(bounds.origin.x + 0.5f*(bounds.size.width - drawWidth), bounds.origin.y + 0.5f*(bounds.size.height - drawHeight), drawWidth, drawHeight);
 
237
 
 
238
        if (fillView)
 
239
                drawRect = bounds;
 
240
        
 
241
/*
 
242
        if (!_cachedImageForDrawing)
 
243
        {
 
244
        //bounds.size.width = ceilf(bounds.origin.x + bounds.size.width) - bounds.origin.x;
 
245
        //bounds.origin.x = ceilf(bounds.origin.x);
 
246
        //bounds.origin.y = ceilf(bounds.origin.y);
 
247
        
 
248
                _cachedImageForDrawing = [img scaledToSize: drawRect.size];
 
249
        }
 
250
*/
 
251
        createPathInRoundedRect(c, drawRect, cornerRadius);
 
252
 
 
253
        CGContextClip(c);
 
254
 
 
255
        [img drawInRect: drawRect blendMode: kCGBlendModeNormal alpha: imageAlpha];
 
256
 
 
257
        CGContextRestoreGState(c);
 
258
        if (borderWidth)
 
259
        {
 
260
                [[borderColor colorWithAlphaComponent: imageAlpha] set];
 
261
                createPathInRoundedRect(c, drawRect, cornerRadius);
 
262
                CGContextSetLineWidth(c, borderWidth);
 
263
                CGContextStrokePath(c);
 
264
        }
 
265
}
 
266
 
 
267
- (void) setImageAlpha: (float) a
 
268
{
 
269
        imageAlpha = a;
 
270
        [self setNeedsDisplay];
 
271
}
 
272
 
 
273
- (void) setImage: (UIImage*) img
 
274
{
 
275
        @synchronized(self)
 
276
        {
 
277
                [img retain];
 
278
                [image release];
 
279
                image = img;
 
280
                //[_cachedImageForDrawing release];
 
281
                //_cachedImageForDrawing = nil;
 
282
        }
 
283
        [self performSelectorOnMainThread: @selector(setNeedsDisplay) withObject: nil waitUntilDone: NO];
 
284
        //[self setNeedsDisplay];
 
285
}
 
286
 
 
287
@synthesize image, cornerRadius, borderColor, borderWidth, fillView, imageAlpha;
 
288
 
 
289
@end
 
290
 
 
291
 
 
292
 
 
293
@implementation ImageWell
 
294
 
 
295
 
 
296
- (id) initWithFrame: (CGRect) frame
 
297
{
 
298
    if (!(self = [super initWithFrame: frame]))
 
299
                return nil;
 
300
 
 
301
        return self;
 
302
}
 
303
 
 
304
- (id) initWithCoder: (NSCoder*) coder
 
305
{
 
306
    if (!(self = [super initWithCoder: coder]))
 
307
                return nil;
 
308
        
 
309
        instructionsView = [[UITextView alloc] initWithFrame: CGRectInset([self bounds], 0.0f, 0.0f)];
 
310
        [instructionsView setText: NSLocalizedString(@"ImageWell instruction text", @"\n\n\nTap and hold to paste image,\n\nor\n\nDouble-tap to select image from gallery.")];
 
311
        //[instructionsView setBackgroundColor: [UIColor yellowColor]];
 
312
        [instructionsView setTextColor: [UIColor whiteColor]];
 
313
        [instructionsView setBackgroundColor: [UIColor clearColor]];
 
314
        [instructionsView setFont: [UIFont systemFontOfSize: [UIFont labelFontSize]]];
 
315
        [instructionsView setEditable: NO];
 
316
        [instructionsView setUserInteractionEnabled: NO];
 
317
        [instructionsView setTextAlignment: UITextAlignmentCenter];
 
318
        [self addSubview: instructionsView];
 
319
 
 
320
        [instructionsView layer].opacity = 0.0f;
 
321
 
 
322
 
 
323
        return self;
 
324
}
 
325
 
 
326
- (void) setFrame: (CGRect) frame
 
327
{
 
328
        [super setFrame: frame];
 
329
        [instructionsView setFrame: CGRectInset([self bounds], 0.0f, 0.0f)];
 
330
}
 
331
 
 
332
 
 
333
 
 
334
- (void) dealloc
 
335
{
 
336
        [imagePicker release];
 
337
        [popoverController release];
 
338
    [super dealloc];
 
339
}
 
340
 
 
341
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 
342
{
 
343
        [alertView dismissWithClickedButtonIndex: buttonIndex animated: YES];
 
344
}
 
345
 
 
346
 
 
347
- (void) pbAlert
 
348
{
 
349
        id alert = [[UIAlertView alloc] initWithTitle: @"No Image to Paste!" message: @"Sorry, there is no usable image or image URL on the pasteboard" delegate: self cancelButtonTitle: nil otherButtonTitles: @"OK", nil];
 
350
        [alert show];
 
351
        [alert autorelease];
 
352
}
 
353
 
 
354
- (void) pasteAction: (id) info
 
355
{
 
356
        NSArray* images = [[UIPasteboard generalPasteboard] images];
 
357
        if ([images count])
 
358
        {
 
359
                UIImage* img = [images objectAtIndex: 0];
 
360
                
 
361
                [self setImage: img];
 
362
                [delegate imageWasSelectedInWell: self];
 
363
        }
 
364
        else
 
365
        {
 
366
                id url = [[UIPasteboard generalPasteboard] URL];
 
367
                if (url)
 
368
                {
 
369
                        NSData *data = [NSData dataWithContentsOfURL:url];
 
370
                        UIImage *img = [UIImage imageWithData:data];
 
371
                        if (img)
 
372
                        {
 
373
                                [self setImage: img];
 
374
                                [delegate imageWasSelectedInWell: self];
 
375
                        }
 
376
                        else
 
377
                                [self pbAlert];
 
378
                }
 
379
                else
 
380
                        [self pbAlert];
 
381
        }
 
382
        pasteTimer = nil;
 
383
}
 
384
 
 
385
- (void) showInstructions: (float) time
 
386
{
 
387
                time = MAX(1.0f, time);
 
388
                
 
389
                ElFloatAnimation* anim = nil;
 
390
 
 
391
                anim = [[[ElFloatAnimation alloc] init] autorelease];
 
392
                
 
393
                [anim setStartValue: [[instructionsView layer] opacity]];
 
394
                [anim setEndValue: 0.667f];
 
395
                [anim setDuration: 0.5f];
 
396
                [anim setTarget: [instructionsView layer]];
 
397
                [anim setProperty: @"opacity"];
 
398
                [anim queueForKey: @"text-opacity" atBeginning: YES cancelPending: YES];
 
399
                
 
400
                
 
401
                anim = [[[ElFloatAnimation alloc] init] autorelease];
 
402
                
 
403
                [anim setStartValue: imageAlpha];
 
404
                [anim setEndValue: 0.333f];
 
405
                [anim setDuration: 0.5f];
 
406
                [anim setTarget: self];
 
407
                [anim setProperty: @"imageAlpha"];
 
408
                [anim queueForKey: @"image-opacity" atBeginning: YES cancelPending: YES];
 
409
                
 
410
                [[ElAnimation delayedAnimationWithDelay: time - 0.5f] queueForKey: @"text-opacity" atBeginning: NO cancelPending: NO];
 
411
                [[ElAnimation delayedAnimationWithDelay: time - 0.5f] queueForKey: @"image-opacity" atBeginning: NO cancelPending: NO];
 
412
 
 
413
                anim = [[[ElFloatAnimation alloc] init] autorelease];
 
414
                
 
415
                [anim setStartValue: 0.667f];
 
416
                [anim setEndValue: 0.0f];
 
417
                [anim setDuration: 0.5f];
 
418
                [anim setTarget: [instructionsView layer]];
 
419
                [anim setProperty: @"opacity"];
 
420
                [anim queueForKey: @"text-opacity" atBeginning: NO cancelPending: NO];
 
421
 
 
422
 
 
423
                anim = [[[ElFloatAnimation alloc] init] autorelease];
 
424
                
 
425
                [anim setStartValue: 0.333f];
 
426
                [anim setEndValue: 1.0f];
 
427
                [anim setDuration: 0.5f];
 
428
                [anim setTarget: self];
 
429
                [anim setProperty: @"imageAlpha"];
 
430
                [anim queueForKey: @"image-opacity" atBeginning: NO cancelPending: NO];
 
431
}
 
432
 
 
433
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
 
434
{
 
435
        UITouch* touch = [touches anyObject];
 
436
        
 
437
        if (([touch tapCount] == 1) && [self isItAPhone])
 
438
        {
 
439
                [self showInstructions: 3.0f];
 
440
        }
 
441
 
 
442
        
 
443
        touchBeganTime = [event timestamp];
 
444
        
 
445
        pasteTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector:@selector(pasteAction:) userInfo: nil repeats: NO];
 
446
        
 
447
        if ([touch tapCount] == 2)
 
448
        {
 
449
                [pasteTimer invalidate];
 
450
                pasteTimer = nil;
 
451
 
 
452
                if (!imagePicker)
 
453
                {
 
454
                        imagePicker = [[UIImagePickerController alloc] init];
 
455
 
 
456
                        //[imagePicker setSourceType: UIImagePickerControllerSourceTypeCamera];
 
457
                        [imagePicker setDelegate: self];
 
458
                        //[imagePicker setAllowsImageEditing: YES];
 
459
                        //[imagePicker setShowsCameraControls: NO];
 
460
                }
 
461
                
 
462
                assert(delegate);
 
463
                #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
 
464
                if ([self isItAPad])
 
465
                {
 
466
                        if (!popoverController)
 
467
                        {
 
468
                                Class popoverClass = NSClassFromString(@"UIPopoverController");
 
469
                                popoverController = [[popoverClass alloc] initWithContentViewController: imagePicker];
 
470
                        }
 
471
                        [popoverController presentPopoverFromRect: [self bounds] inView: self permittedArrowDirections: UIPopoverArrowDirectionAny animated: YES];
 
472
                }
 
473
                else
 
474
                #endif
 
475
                        [delegate presentModalViewController: imagePicker animated: YES];
 
476
        }
 
477
}
 
478
 
 
479
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
 
480
{
 
481
//      UITouch* touch = [touches anyObject];
 
482
        
 
483
        [pasteTimer invalidate];
 
484
        pasteTimer = nil;
 
485
        
 
486
}
 
487
 
 
488
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
 
489
{
 
490
//      UITouch* touch = [touches anyObject];
 
491
        
 
492
        [pasteTimer invalidate];
 
493
        pasteTimer = nil;
 
494
        
 
495
}
 
496
 
 
497
- (void)imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
 
498
{
 
499
        
 
500
        UIImage* img = [info objectForKey: UIImagePickerControllerEditedImage];
 
501
        
 
502
        if (!img)
 
503
                img = [info objectForKey: UIImagePickerControllerOriginalImage];
 
504
 
 
505
        if (img)
 
506
        {
 
507
                [self setImage: img];
 
508
                [delegate imageWasSelectedInWell: self];
 
509
        }
 
510
 
 
511
        [delegate dismissModalViewControllerAnimated: YES];
 
512
 
 
513
}
 
514
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
 
515
{
 
516
        [delegate dismissModalViewControllerAnimated: YES];
 
517
}
 
518
 
 
519
 
 
520
@synthesize delegate;
 
521
 
 
522
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches