2010-04-14 20 views
38

Ich entwickle eine Anwendung, in der ich das Bild unter Verwendung seiner Pixel verarbeite, aber in dieser Bildverarbeitung dauert es eine Menge Zeit. Deshalb möchte ich (dh das Entfernen/croping grenzte Teil des Bildes nur mittleren Teil des Bildes) UIImage zuzuschneiden .Ich der Code sind entwickeln haben,Wie schneidet man das UIImage?

- (NSInteger) processImage1: (UIImage*) image 
{ 

CGFloat width = image.size.width; 
CGFloat height = image.size.height; 
struct pixel* pixels = (struct pixel*) calloc(1, image.size.width * image.size.height * sizeof(struct pixel)); 
if (pixels != nil) 
{ 
    // Create a new bitmap 
    CGContextRef context = CGBitmapContextCreate(
       (void*) pixels, 
       image.size.width, 
       image.size.height, 
       8, 
       image.size.width * 4, 
       CGImageGetColorSpace(image.CGImage), 
       kCGImageAlphaPremultipliedLast 
      ); 
    if (context != NULL) 
    { 
    // Draw the image in the bitmap 
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage); 
    NSUInteger numberOfPixels = image.size.width * image.size.height; 

    NSMutableArray *numberOfPixelsArray = [[[NSMutableArray alloc] initWithCapacity:numberOfPixelsArray] autorelease]; 
} 

Wie ich nehme (croping außerhalb grenzt) der mittlere Teil von UIImage? ????????

Antwort

78

versuchen, etwas wie folgen aus:

CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect); 
image = [UIImage imageWithCGImage:imageRef]; 
CGImageRelease(imageRef); 

Hinweis: cropRect kleines Rechteck mit mittlerem Teil des Bildes ...

+0

mihirpmehta , Jetzt versuche ich so etwas zu tun, - (UIImage *) cropedImage: (UIImage *) Bild { \t CGFloat width = image.size.width; \t CGFloat height = image.size.height; \t UIImage * cropedImage = [[UIImage alloc] init]; \t CGFloat widthCrop = (image.size.width)/2; \t CGFloat heightCrop = (image.size.height)/2; \t } Danach kann ich nicht visualisieren, was zu tun ist? –

+0

erhalten Sie neues X und neues Y als OldX + OldX/4 und OldY + OldY/4 und machen REctangle mit neuer Breitenhöhe NewX und NewY und verwenden es als cropRect –

+0

@mihirpmehta, Ihre obige Methode zeichnet nur das Spiegelbild des Originals Bild im cropRect-Rechteck. Es konnte das UIImage nicht verarbeitet werden. –

38

Ich war auf der Suche nach einer Möglichkeit, eine beliebige rechteckige Ernte (dh zu bekommen. , Teilbild) eines UIImage.

Die meisten Lösungen, die ich ausprobiert habe, funktionieren nicht, wenn die Ausrichtung des Bildes anders als UIImageOrientationUp ist.

Zum Beispiel:

http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/

Normalerweise, wenn Sie Ihre iPhone-Kamera verwenden, werden Sie andere Orientierungen wie UIImageOrientationLeft haben, und Sie werden nicht eine richtige Ernte mit dem oben bekommen. Dies liegt an der Verwendung von CGImageRef/CGContextDrawImage, die sich im Koordinatensystem in Bezug auf UIImage unterscheiden.

Der folgende Code verwendet UI * Methoden (kein CGImageRef), und ich habe dies mit hoch/runter/links/rechts orientierte Bilder getestet, und es scheint gut zu funktionieren.


// get sub image 
- (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect { 

    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // translated rectangle for drawing sub image 
    CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height); 

    // clip to the bounds of the image context 
    // not strictly necessary as it will get clipped anyway? 
    CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height)); 

    // draw image 
    [img drawInRect:drawRect]; 

    // grab image 
    UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return subImage; 
} 
 
+2

Beachten Sie, dass Sie den obigen Code nur für den Hauptthread ausführen können. Der Vorteil, 'UIGraphicsBeginImageContext' usw. zu vermeiden, besteht darin, diese Einschränkung zu umgehen. –

+1

@William Denniss bist du sicher? http://stackoverflow.com/questions/11528803/is-uigraphicsbeginimagecontext-thread-safe/11530675#11530675 – Klaas

+0

@Klass, du hast Recht, seit iOS 4 können Sie es auf jedem Thread aufrufen. Der Code ** ist jedoch immer noch nicht threadsicher **, Sie können 'UIGraphicsBeginImageContext' nur für einen Thread gleichzeitig verwenden. Die Dokumentation besagt: "Erstellt einen Bitmap-basierten Grafikkontext und macht ihn zum aktuellen Kontext." Ich glaube, dass dieser "aktuelle Kontext" global ist und daher nicht sicher ist. Meine App verarbeitet mehrere Bilder auf einmal, und ich hatte Abstürze, wenn ich 'UIGraphicsBeginImageContext' in mehreren Threads verwendete, also wechselte ich zu 'CGContextRef's, die Thread-sicher sind. –

2

Es wäre letztlich schneller sein, mit viel weniger Image-Erstellung von Sprite Atlanten, wenn Sie nicht nur das Bild für eine UIImageView, sondern auch die linke obere innerhalb dieser UIImage anzuzeigen Offset einstellen könnte. Vielleicht ist das möglich. Es würde sicherlich eine Menge Aufwand beseitigen!

Mittlerweile habe ich diese nützlichen Funktionen in einer Dienstprogrammklasse erstellt, die ich in meinen Apps verwende. Es erstellt ein UIImage aus einem Teil eines anderen UIImage mit Optionen zum Drehen, Skalieren und Spiegeln mit Standard-UIImageOrientation-Werten zum Angeben. Die Pixelskalierung wird vom Originalbild beibehalten.

Meine App erstellt eine Menge von UIImagages während der Initialisierung, und dies benötigt notwendigerweise Zeit. Aber einige Bilder werden nicht benötigt, bis eine bestimmte Registerkarte ausgewählt ist. Um eine schnellere Ladezeit zu erhalten, könnte ich sie in einem separaten Thread erzeugen, der beim Start erzeugt wurde, und dann einfach warten, bis es fertig ist, wenn diese Registerkarte ausgewählt ist.

Dieser Code wird auch bei Most efficient way to draw part of an image in iOS

geschrieben
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture { 
    return [ChordCalcController imageByCropping:imageToCrop toRect:aperture withOrientation:UIImageOrientationUp]; 
} 

// Draw a full image into a crop-sized area and offset to produce a cropped, rotated image 
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture withOrientation:(UIImageOrientation)orientation { 

      // convert y coordinate to origin bottom-left 
    CGFloat orgY = aperture.origin.y + aperture.size.height - imageToCrop.size.height, 
      orgX = -aperture.origin.x, 
      scaleX = 1.0, 
      scaleY = 1.0, 
      rot = 0.0; 
    CGSize size; 

    switch (orientation) { 
     case UIImageOrientationRight: 
     case UIImageOrientationRightMirrored: 
     case UIImageOrientationLeft: 
     case UIImageOrientationLeftMirrored: 
      size = CGSizeMake(aperture.size.height, aperture.size.width); 
      break; 
     case UIImageOrientationDown: 
     case UIImageOrientationDownMirrored: 
     case UIImageOrientationUp: 
     case UIImageOrientationUpMirrored: 
      size = aperture.size; 
      break; 
     default: 
      assert(NO); 
      return nil; 
    } 


    switch (orientation) { 
     case UIImageOrientationRight: 
      rot = 1.0 * M_PI/2.0; 
      orgY -= aperture.size.height; 
      break; 
     case UIImageOrientationRightMirrored: 
      rot = 1.0 * M_PI/2.0; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationDown: 
      scaleX = scaleY = -1.0; 
      orgX -= aperture.size.width; 
      orgY -= aperture.size.height; 
      break; 
     case UIImageOrientationDownMirrored: 
      orgY -= aperture.size.height; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationLeft: 
      rot = 3.0 * M_PI/2.0; 
      orgX -= aperture.size.height; 
      break; 
     case UIImageOrientationLeftMirrored: 
      rot = 3.0 * M_PI/2.0; 
      orgY -= aperture.size.height; 
      orgX -= aperture.size.width; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationUp: 
      break; 
     case UIImageOrientationUpMirrored: 
      orgX -= aperture.size.width; 
      scaleX = -1.0; 
      break; 
    } 

    // set the draw rect to pan the image to the right spot 
    CGRect drawRect = CGRectMake(orgX, orgY, imageToCrop.size.width, imageToCrop.size.height); 

    // create a context for the new image 
    UIGraphicsBeginImageContextWithOptions(size, NO, imageToCrop.scale); 
    CGContextRef gc = UIGraphicsGetCurrentContext(); 

    // apply rotation and scaling 
    CGContextRotateCTM(gc, rot); 
    CGContextScaleCTM(gc, scaleX, scaleY); 

    // draw the image to our clipped context using the offset rect 
    CGContextDrawImage(gc, drawRect, imageToCrop.CGImage); 

    // pull the image from our cropped context 
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext(); 

    // pop the context to get back to the default 
    UIGraphicsEndImageContext(); 

    // Note: this is autoreleased 
    return cropped; 
} 
+0

Danke. Was sollte die Ausrichtung sein, die ich für das Bild sende, wenn ich es von der AVFoundation Kamera nehme, die die Bilder dreht? – Dejell

0

Wenn Sie das Zentrum jedes Foto ein Porträt Ernte nach unten wollen.

Verwenden Sie @ M-V-Lösung, & ersetzen Sie cropRect.

CGFloat height = imageTaken.size.height; 
CGFloat width = imageTaken.size.width; 

CGFloat newWidth = height * 9/16; 
CGFloat newX = abs((width - newWidth))/2; 

CGRect cropRect = CGRectMake(newX,0, newWidth ,height); 
0

Ich wollte von einem Bereich auf einem Seitenverhältnis und Skalierung zu einer Größe basierend auf einem äußeren Begrenzungs Ausmaß basierend zuzuschneiden können.Hier ist meine Variation:

import AVFoundation 
import ImageIO 

class Image { 

    class func crop(image:UIImage, source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage { 

     let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source) 
     let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent)) 

     let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device's main screen 
     UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale) 

     let scale = max(
      targetRect.size.width/sourceRect.size.width, 
      targetRect.size.height/sourceRect.size.height) 

     let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale) 
     image.drawInRect(drawRect) 

     let scaledImage = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 

     return scaledImage 
    } 
} 

Es gibt ein paar Dinge, die ich gefunden verwirrend, die einzelnen Anliegen Zuschneiden und Größenanpassung. Das Zuschneiden wird mit dem Ursprung des Rechtecks ​​behandelt, das Sie an drawInRect übergeben, und die Skalierung wird vom Größenbereich übernommen. In meinem Fall musste ich die Größe des Beschneidungs-Rect auf der Quelle mit meiner Ausgabe des gleichen Seitenverhältnisses in Beziehung setzen. Der Skalierungsfaktor wird dann ausgegeben/eingegeben, und dies muss auf drawRect angewendet werden (übergeben an drawInRect).

Eine Einschränkung ist, dass dieser Ansatz effektiv davon ausgeht, dass das Bild, das Sie zeichnen, größer als der Bildkontext ist. Ich habe das nicht getestet, aber ich denke, Sie können diesen Code verwenden, um das Zuschneiden/Zoomen zu behandeln, aber den Skalierungsparameter explizit als den zuvor genannten Skalierungsparameter zu definieren. Standardmäßig wendet UIKit einen Multiplikator an, der auf der Bildschirmauflösung basiert.

Schließlich sollte beachtet werden, dass dieser UIKit-Ansatz eine höhere Ebene als CoreGraphics/Quartz und Core Image-Ansätze aufweist und Probleme mit der Bildausrichtung zu lösen scheint. Es ist auch erwähnenswert, dass es ziemlich schnell ist, an zweiter Stelle zu ImageIO, nach diesem Beitrag hier: http://nshipster.com/image-resizing/

1

Weil ich es gerade jetzt benötigen, ist hier MV ‚s Code in Swift 4:

func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage { 

    UIGraphicsBeginImageContext(rect.size) 
    let context = UIGraphicsGetCurrentContext() 

    let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y, 
          width: image.size.width, height: image.size.height) 

    context?.clip(to: CGRect(x: 0, y: 0, 
          width: rect.size.width, height: rect.size.height)) 

    image.draw(in: drawRect) 

    let subImage = UIGraphicsGetImageFromCurrentImageContext() 

    UIGraphicsEndImageContext() 
    return subImage! 
} 
Verwandte Themen