RSS

(root)/iphone/tappity : 61 : source/TappityServer.m

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

« back to all changes in this revision

Viewing changes to source/TappityServer.m

Dömötör Gulyás
2010-01-28 15:50:50
Revision ID: dognotdog@gmail.com-20100128145050-mogyehpg1eif15uq
fixes bug in server side data reception; feedback images are no reduced to a fixed size to improve network load;variably sized GL framebuffers now supported; adds 'placed screenshot' in addition to raw screenshot message, for non full screen GL; no longer sends suspend/quit events to the server when client is quit, which caused the server to quit, too, even though that was most likely not intended

Show diffs side-by-side

added added

removed removed

41
41
#import <CoreLocation/CoreLocation.h>
42
42
#import <objc/runtime.h>
43
43
 
44
 
 
 
44
#define TAPPITY_MAX_FEEDBACK_SIZE 240
45
45
CGImageRef UIGetScreenImage(void);
46
46
 
47
47
@interface UIImage (ScreenImage)
48
48
+ (UIImage *)imageWithScreenContents;
49
 
@end
50
 
 
51
 
@implementation UIImage (ScreenImage)
52
 
+ (UIImage *)imageWithScreenContents
53
 
{
54
 
    CGImageRef cgScreen = UIGetScreenImage();
55
 
    if (cgScreen) {
56
 
        UIImage *result = [UIImage imageWithCGImage:cgScreen];
57
 
        CGImageRelease(cgScreen);
58
 
        return result;
59
 
    }
60
 
    return nil;
61
 
}
 
49
- (UIImage*) scaledToSize: (CGSize) size;
62
50
@end
63
51
 
64
52
@interface CLLocationManager (TappityServer)
373
361
        NSData* tapData = [dataDict objectForKey: SocketMessageDataKey];
374
362
        
375
363
//      NSDictionary* tapDict = [NSPropertyListSerialization propertyListFromData: tapData mutabilityOption:NSPropertyListImmutable format: NULL errorDescription: NULL];
376
 
        assert(tapData);
377
364
        switch(messageId)
378
365
        {
379
366
/*
522
509
                [self convertAndSendImage: img];
523
510
}
524
511
 
 
512
 
525
513
- (void) imageConversionThread: (id) info
526
514
{
527
515
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
545
533
                [capturedImagesQueue removeObjectAtIndex: 0];
546
534
                
547
535
                [capturedImagesCondition unlock];
 
536
                
 
537
                CGRect imgRect = {CGPointZero, [img size]};
 
538
                
 
539
                float aspect = imgRect.size.width/imgRect.size.height;
 
540
                CGSize newSize = CGSizeMake(
 
541
                        MIN(TAPPITY_MAX_FEEDBACK_SIZE, TAPPITY_MAX_FEEDBACK_SIZE*aspect),
 
542
                        MIN(TAPPITY_MAX_FEEDBACK_SIZE, TAPPITY_MAX_FEEDBACK_SIZE/aspect));
 
543
                
 
544
                img = [img scaledToSize: newSize];
548
545
 
549
546
                NSData* imgData = UIImagePNGRepresentation(img);
550
547
        
551
548
                if (imgData)
552
 
                        [messenger sendData: imgData withIdentifier: kTapRawScreenshot];
553
 
 
 
549
                {
 
550
                        NSString* rstr = NSStringFromCGRect(imgRect);
 
551
                        NSDictionary* imgDict = [NSDictionary dictionaryWithObjectsAndKeys: imgData, TapImageDataKey, rstr, TapImageRectKey, rstr, TapReferenceRectKey, nil];
 
552
                        NSData* data = [NSPropertyListSerialization dataFromPropertyList: imgDict format:NSPropertyListBinaryFormat_v1_0 errorDescription: nil];
 
553
                        [messenger sendData: data withIdentifier: kTapPlacedScreenshot];
 
554
                }
554
555
                
555
556
                [pool drain];
556
557
 
633
634
}
634
635
*/
635
636
 
636
 
static UIImage* imageFromGLData(NSData* data)
 
637
static UIImage* imageFromGLData(NSData* data, GLint* viewport)
637
638
{
638
639
    // make data provider with data.
639
640
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [data bytes], [data length], NULL);
641
642
    // prep the ingredients
642
643
    int bitsPerComponent = 8;
643
644
    int bitsPerPixel = 32;
644
 
    int bytesPerRow = 4 * 320;
 
645
    int bytesPerRow = 4 * viewport[2];
645
646
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
646
647
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
647
648
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
648
649
   
649
650
    // make the cgimage
650
 
    CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
 
651
    CGImageRef imageRef = CGImageCreate(viewport[2], viewport[3], bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
651
652
   
652
653
    // then make the uiimage from that
653
654
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
654
655
    return myImage;
655
656
}
656
657
 
657
 
static NSData* dataFromGL(void)
 
658
static NSData* dataFromGL(GLint* viewport)
658
659
{
659
 
    NSInteger myDataLength = 320 * 480 * 4;
 
660
    NSInteger myDataLength = viewport[2] * viewport[3] * 4;
660
661
        
661
662
        NSMutableData* data = [NSMutableData dataWithLength: myDataLength];
662
663
   
663
664
    // allocate array and read pixels into it.
664
665
    void* buffer = [data mutableBytes];
665
 
    glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
 
666
    glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGBA, GL_UNSIGNED_BYTE, buffer);
666
667
        
667
 
        size_t bpr = 4*320;
 
668
        size_t bpr = 4*viewport[2];
668
669
        void* rowbuf = calloc(1, bpr);
669
670
        
670
671
        // swap image in Y
671
 
        for (size_t i = 0; i < 480/2; ++i)
 
672
        for (size_t i = 0; i < viewport[3]/2; ++i)
672
673
        {
673
674
                memcpy(rowbuf, buffer + i*bpr, bpr);
674
 
                memcpy(buffer + i*bpr, buffer + (480-i-1)*bpr, bpr);
675
 
                memcpy(buffer + (480-i-1)*bpr, rowbuf, bpr);
 
675
                memcpy(buffer + i*bpr, buffer + (viewport[3]-i-1)*bpr, bpr);
 
676
                memcpy(buffer + (viewport[3]-i-1)*bpr, rowbuf, bpr);
676
677
        }
677
678
        
678
679
        free(rowbuf);
688
689
        NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
689
690
        if (lastGlUpdate + desiredFrameInterval < now)
690
691
        {
691
 
                NSData* rawData = dataFromGL();
692
 
                UIImage* image = imageFromGLData(rawData);
693
 
                
694
 
                NSData* data = UIImagePNGRepresentation(image);
695
 
                
696
 
                [messenger sendData: data withIdentifier: kTapRawScreenshot];
 
692
                
 
693
                GLint viewport[4];
 
694
                glGetIntegerv(GL_VIEWPORT, viewport);
 
695
 
 
696
                NSData* rawData = dataFromGL(viewport);
 
697
                
 
698
                float aspect = (float)viewport[2]/(float)viewport[3];
 
699
                CGSize newSize = CGSizeMake(
 
700
                        MIN(TAPPITY_MAX_FEEDBACK_SIZE, TAPPITY_MAX_FEEDBACK_SIZE*aspect),
 
701
                        MIN(TAPPITY_MAX_FEEDBACK_SIZE, TAPPITY_MAX_FEEDBACK_SIZE/aspect));
 
702
 
 
703
                UIImage* image = [imageFromGLData(rawData, viewport) scaledToSize: newSize];
 
704
                
 
705
                NSData* imgData = UIImagePNGRepresentation(image);
 
706
                if (imgData)
 
707
                {
 
708
                        CGRect imgRect = CGRectMake(viewport[0], viewport[1], viewport[2], viewport[3]);
 
709
                        NSString* rstr = NSStringFromCGRect(imgRect);
 
710
                        NSDictionary* imgDict = [NSDictionary dictionaryWithObjectsAndKeys: imgData, TapImageDataKey, rstr, TapImageRectKey, NSStringFromCGRect(CGRectZero), TapReferenceRectKey, nil];
 
711
                        NSData* data = [NSPropertyListSerialization dataFromPropertyList: imgDict format:NSPropertyListBinaryFormat_v1_0 errorDescription: nil];
 
712
                        [messenger sendData: data withIdentifier: kTapPlacedScreenshot];
 
713
                }
697
714
                
698
715
                lastGlUpdate = now;
699
716
        }
731
748
@synthesize locationDelegate, headingDelegate;
732
749
 
733
750
@end
 
751
 
 
752
@implementation UIImage (ScreenImage)
 
753
 
 
754
+ (UIImage *)imageWithScreenContents
 
755
{
 
756
    CGImageRef cgScreen = UIGetScreenImage();
 
757
    if (cgScreen) {
 
758
        UIImage *result = [UIImage imageWithCGImage:cgScreen];
 
759
        CGImageRelease(cgScreen);
 
760
        return result;
 
761
    }
 
762
    return nil;
 
763
}
 
764
 
 
765
CGImageRef CreateScaledCGImageFromCGImage(CGImageRef image, CGSize size)
 
766
{
 
767
        int width = size.width;
 
768
        int height = size.height;
 
769
         
 
770
        // Declare the number of bytes per row. Each pixel in the bitmap in this
 
771
        // example is represented by 4 bytes; 8 bits each of red, green, blue, and
 
772
        // alpha.
 
773
        size_t bitmapBytesPerRow   = (width * 4);
 
774
        size_t bitmapByteCount     = (bitmapBytesPerRow * height);
 
775
         
 
776
        // Allocate memory for image data. This is the destination in memory
 
777
        // where any drawing to the bitmap context will be rendered.
 
778
        void* bitmapData = malloc( bitmapByteCount );
 
779
        if (bitmapData == NULL)
 
780
        {
 
781
                return nil;
 
782
        }
 
783
         
 
784
        // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
 
785
        // per component. Regardless of what the source image format is
 
786
        // (CMYK, Grayscale, and so on) it will be converted over to the format
 
787
        // specified here by CGBitmapContextCreate.
 
788
        CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
 
789
        CGContextRef context = CGBitmapContextCreate (bitmapData,width,height,8,bitmapBytesPerRow,
 
790
        colorspace,kCGImageAlphaPremultipliedFirst);
 
791
        CGColorSpaceRelease(colorspace);
 
792
         
 
793
        if (context == NULL)
 
794
        // error creating context
 
795
        {
 
796
                free(bitmapData);
 
797
                return nil;
 
798
        }
 
799
         
 
800
        // Draw the image to the bitmap context. Once we draw, the memory
 
801
        // allocated for the context for rendering will then contain the
 
802
        // raw image data in the specified color space.
 
803
        CGContextDrawImage(context, CGRectMake(0,0,width, height), image);
 
804
         
 
805
        CGImageRef imgRef = CGBitmapContextCreateImage(context);
 
806
        CGContextRelease(context);
 
807
        free(bitmapData);
 
808
         
 
809
        return imgRef;
 
810
}
 
811
 
 
812
 
 
813
- (UIImage*) scaledToSize: (CGSize) size
 
814
{
 
815
        CGImageRef imgref = CreateScaledCGImageFromCGImage([self CGImage], size);
 
816
        if (!imgref)
 
817
                return nil;
 
818
                
 
819
        UIImage* img = [UIImage imageWithCGImage: imgref];
 
820
        
 
821
        CGImageRelease(imgref);
 
822
                
 
823
        return img;
 
824
}
 
825
 
 
826
@end
 
827
 
 
828
 

Loggerhead 1.17 is a web-based interface for Bazaar branches