webentwicklung-frage-antwort-db.com.de

Wie beschneide ich den UIImage?

Ich entwickle eine Anwendung, in der ich das Bild mit seinen Pixeln verarbeite. In dieser Bildverarbeitung ist jedoch viel Zeit erforderlich. Daher möchte ich UIImage zuschneiden (nur der mittlere Teil des Bildes, d. H. Das Entfernen/Beschneiden des umrandeten Teils des Bildes).

- (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 nehme ich den mittleren Teil von UIImage (beschneidet außerhalb begrenzt) ?????????

38
Rajendra Bhole

Versuchen Sie etwas so:

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

Hinweis: cropRect ist ein kleineres Rechteck mit dem mittleren Teil des Bildes ...

78
mihir mehta

Ich suchte nach einem Weg, um einen beliebigen rechteckigen Ausschnitt (dh Unterbild) eines UIImage zu erhalten. 

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

Zum Beispiel:

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

Normalerweise haben Sie, wenn Sie Ihre iPhone-Kamera verwenden, andere Ausrichtungen wie UIImageOrientationLeft, und Sie erhalten mit den obigen Angaben keinen korrekten Ausschnitt. 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 aufwärts/abwärts/links/rechts ausgerichteten Bildern 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;
}
39
M-V

Es wäre schlussendlich schneller, mit viel weniger Bilderzeugung aus Sprite-Atlanten, wenn Sie nicht nur das Bild für eine UIImageView festlegen können, sondern auch den oberen linken Versatz, der in diesem UIImage angezeigt wird. Vielleicht ist das möglich. Es würde sicherlich eine Menge Aufwand machen!

In der Zwischenzeit habe ich diese nützlichen Funktionen in einer Dienstprogrammklasse erstellt, die ich in meinen Apps verwende. Es erstellt einen UIImage aus einem Teil eines anderen UIImage mit Optionen zum Drehen, Skalieren und Spiegeln unter Verwendung von UIImageOrientation-Standardwerten. Die Pixel-Skalierung wird vom Originalbild beibehalten.

Meine App erstellt viele UIImages während der Initialisierung, und dies erfordert notwendigerweise Zeit. Einige Bilder werden jedoch erst benötigt, wenn eine bestimmte Registerkarte ausgewählt ist. Um den Eindruck eines schnelleren Ladevorgangs zu vermitteln, könnte ich sie in einem separaten Thread erstellen, der beim Start erzeugt wird, und dann warten Sie, bis der Vorgang abgeschlossen ist, wenn diese Registerkarte ausgewählt ist.

Diesen Code finden Sie auch unter Die effizienteste Art, einen Teil eines Bildes in iOS zu zeichnen

+ (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;
}
2
Scott Lahteine

Da ich es gerade jetzt brauchte, hier der Code von M-V 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!
}
1
dasdom

Verwendung der Funktion 

CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));

Hier ist ein Beispielcode, der zu einem anderen Zweck verwendet wird, die Clips jedoch in Ordnung sind. 

- (UIImage *)aspectFillToSize:(CGSize)size
{
    CGFloat imgAspect = self.size.width / self.size.height;
    CGFloat sizeAspect = size.width/size.height;

    CGSize scaledSize;

        if (sizeAspect > imgAspect) { // increase width, crop height
            scaledSize = CGSizeMake(size.width, size.width / imgAspect);
        } else { // increase height, crop width
            scaledSize = CGSizeMake(size.height * imgAspect, size.height);
        }
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
    [self drawInRect:CGRectMake(0.0f, 0.0f, scaledSize.width, scaledSize.height)];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
0
karim

Wenn Sie möchten, dass ein Porträt in die Mitte eines Fotos geschnitten wird.

Verwenden Sie die @ M-V-Lösung und 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
benjaminhallock

Ich wollte in der Lage sein, aus einem Bereich basierend auf einem Seitenverhältnis zu beschneiden und auf eine Größe zu skalieren, die auf der äußeren Begrenzungsausdehnung basiert. 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 verwirrend finde, die getrennten Sorgen des Zuschnitts und der Größenänderung. Das Zuschneiden erfolgt mit dem Ursprung des Rect, den Sie an drawInRect übergeben, und die Skalierung erfolgt nach dem Größenbereich. In meinem Fall musste ich die Größe des Beschnittrektors an der Quelle mit meinem Ausgangsrekt mit demselben Seitenverhältnis in Beziehung setzen. Der Skalierungsfaktor ist dann Ausgabe/Eingabe, und dieser muss auf den drawRect angewendet werden (wird an drawInRect übergeben).

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

Abschließend sei darauf hingewiesen, dass dieser UIKit-Ansatz auf einem höheren Niveau als die Ansätze von CoreGraphics/Quartz und Core Image liegt und Probleme der Bildorientierung zu behandeln scheint. Es ist auch erwähnenswert, dass es nach ImageIO nach diesem Beitrag hier ziemlich schnell ist: http://nshipster.com/image-resizing/

0
Chris Conover