UIImage: Resize, dan Crop

stemmen
184

Ik heb bashing mijn gezicht in deze voor letterlijk dagen nu en hoewel ik voel me voortdurend dat ik direct aan de rand van de openbaring, ik kan gewoon niet mijn doel te bereiken.

Ik dacht van tevoren in de conceptuele fase van mijn ontwerp, dat het een triviale zaak om een beeld van de camera of de bibliotheek van de iPhone te pakken zou zijn, schaal het neer op een bepaalde hoogte, met behulp van een functie gelijk is aan de Aspect Fill optie UIImageView (volledig in code), en vervolgens bijsnijden off iets dat niet binnen een doorgeschoten CGRect pasten.

Het krijgen van het originele beeld van de camera of de bibliotheek, was triviaal. Ik ben geschokt over hoe moeilijk de andere twee stappen hebben bewezen te zijn.

De bijgevoegde afbeelding laat zien wat ik probeer te bereiken. Zou iemand aub zo vriendelijk om mijn hand vast te houden? Elke code voorbeeld dat ik heb gevonden tot nu toe lijkt het beeld te breken, zijn ondersteboven, zien eruit als crap, trekken uit grenzen, of anders gewoon niet goed werken.

De vraag is gesteld op 02/03/2009 om 21:42
bron van user
In andere talen...                            


16 antwoorden

stemmen
244

Ik moest het zelfde ding - in mijn geval, aan de dimensie die ooit past geschaald te halen, en vervolgens bijsnijden elk uiteinde om de rest te passen aan de breedte. (. Ik werk in het landschap, dus misschien niet eventuele onvolkomenheden in portret-modus hebben gemerkt) Hier is mijn code - het is een deel van een categeory op UIImage. Target grootte in mijn code is altijd ingesteld op de volledige schermgrootte van het apparaat.

@implementation UIImage (Extras)

#pragma mark -
#pragma mark Scale and crop image

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
    UIImage *sourceImage = self;
    UIImage *newImage = nil;    
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) 
    {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor > heightFactor) 
        {
            scaleFactor = widthFactor; // scale to fit height
        }
        else
        {
            scaleFactor = heightFactor; // scale to fit width
        }

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image
        if (widthFactor > heightFactor)
        {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
        }
        else
        {
            if (widthFactor < heightFactor)
            {
                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
            }
        }
    }   

    UIGraphicsBeginImageContext(targetSize); // this will crop

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage == nil)
    {
        NSLog(@"could not scale image");
    }

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

    return newImage;
}
antwoordde op 03/03/2009 om 07:55
bron van user

stemmen
77

Een ouder bericht bevat code voor een methode om uw UIImage wijzigen. Het relevante gedeelte is als volgt:

+ (UIImage*)imageWithImage:(UIImage*)image 
               scaledToSize:(CGSize)newSize;
{
   UIGraphicsBeginImageContext( newSize );
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
}

Voor zover bijsnijden gaat, ik denk dat als je de methode om een ​​ander formaat te gebruiken voor de schaal dan voor de context te veranderen, moet uw resulterende beeld worden bevestigd aan de grenzen van de context.

antwoordde op 02/03/2009 om 23:32
bron van user

stemmen
18
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {
    //If scaleFactor is not touched, no scaling will occur      
    CGFloat scaleFactor = 1.0;

    //Deciding which factor to use to scale the image (factor = targetSize / imageSize)
    if (image.size.width > targetSize.width || image.size.height > targetSize.height)
        if (!((scaleFactor = (targetSize.width / image.size.width)) > (targetSize.height / image.size.height))) //scale to fit width, or
            scaleFactor = targetSize.height / image.size.height; // scale to fit heigth.

    UIGraphicsBeginImageContext(targetSize); 

    //Creating the rect where the scaled image is drawn in
    CGRect rect = CGRectMake((targetSize.width - image.size.width * scaleFactor) / 2,
                             (targetSize.height -  image.size.height * scaleFactor) / 2,
                             image.size.width * scaleFactor, image.size.height * scaleFactor);

    //Draw the image into the rect
    [image drawInRect:rect];

    //Saving the image, ending image context
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return scaledImage;
}

Ik stel voor deze. Is ze niet prachtig? ;)

antwoordde op 23/11/2010 om 00:09
bron van user

stemmen
15

Er is een groot stuk van de code met betrekking tot het aanpassen van afbeeldingen + diverse andere operaties. Ik kwam rond deze ene wanneer het proberen om ou achterhalen hoe u afbeeldingen verkleinen ... http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/

antwoordde op 18/01/2010 om 15:58
bron van user

stemmen
7

Alsjeblieft. Deze is perfect ;-)

EDIT: zie hieronder commentaar - "Werkt niet met bepaalde beelden, mislukt met: CGContextSetInterpolationQuality: ongeldige context 0x0 error"

// Resizes the image according to the given content mode, taking into account the image's orientation
- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode imageToScale:(UIImage*)imageToScale bounds:(CGSize)bounds interpolationQuality:(CGInterpolationQuality)quality {
    //Get the size we want to scale it to
    CGFloat horizontalRatio = bounds.width / imageToScale.size.width;
    CGFloat verticalRatio = bounds.height / imageToScale.size.height;
    CGFloat ratio;

    switch (contentMode) {
        case UIViewContentModeScaleAspectFill:
            ratio = MAX(horizontalRatio, verticalRatio);
            break;

        case UIViewContentModeScaleAspectFit:
            ratio = MIN(horizontalRatio, verticalRatio);
            break;

        default:
            [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", contentMode];
    }

    //...and here it is
    CGSize newSize = CGSizeMake(imageToScale.size.width * ratio, imageToScale.size.height * ratio);


    //start scaling it
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = imageToScale.CGImage;
    CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                                newRect.size.width,
                                                newRect.size.height,
                                                CGImageGetBitsPerComponent(imageRef),
                                                0,
                                                CGImageGetColorSpace(imageRef),
                                                CGImageGetBitmapInfo(imageRef));

    CGContextSetInterpolationQuality(bitmap, quality);

    // Draw into the context; this scales the image
    CGContextDrawImage(bitmap, newRect, imageRef);

    // Get the resized image from the context and a UIImage
    CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    // Clean up
    CGContextRelease(bitmap);
    CGImageRelease(newImageRef);

    return newImage;
}
antwoordde op 28/06/2011 om 19:40
bron van user

stemmen
6

Dit is een versie van het antwoord van Jane Sales' in Swift. Proost!

public func resizeImage(image: UIImage, size: CGSize) -> UIImage? {
    var returnImage: UIImage?

    var scaleFactor: CGFloat = 1.0
    var scaledWidth = size.width
    var scaledHeight = size.height
    var thumbnailPoint = CGPointMake(0, 0)

    if !CGSizeEqualToSize(image.size, size) {
        let widthFactor = size.width / image.size.width
        let heightFactor = size.height / image.size.height

        if widthFactor > heightFactor {
            scaleFactor = widthFactor
        } else {
            scaleFactor = heightFactor
        }

        scaledWidth = image.size.width * scaleFactor
        scaledHeight = image.size.height * scaleFactor

        if widthFactor > heightFactor {
            thumbnailPoint.y = (size.height - scaledHeight) * 0.5
        } else if widthFactor < heightFactor {
            thumbnailPoint.x = (size.width - scaledWidth) * 0.5
        }
    }

    UIGraphicsBeginImageContextWithOptions(size, true, 0)

    var thumbnailRect = CGRectZero
    thumbnailRect.origin = thumbnailPoint
    thumbnailRect.size.width = scaledWidth
    thumbnailRect.size.height = scaledHeight

    image.drawInRect(thumbnailRect)
    returnImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return returnImage
}
antwoordde op 24/12/2015 om 13:15
bron van user

stemmen
2

Ik zette gids Sam Wirch om snel en het werkte goed voor mij, hoewel er een aantal zeer lichte "squishing" in het uiteindelijke beeld dat ik niet kon oplossen.

func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage {
    var ratio: CGFloat = 0
    var delta: CGFloat = 0
    var offset = CGPointZero
    if image.size.width > image.size.height {
        ratio = newSize.width / image.size.width
        delta = (ratio * image.size.width) - (ratio * image.size.height)
        offset = CGPointMake(delta / 2, 0)
    } else {
        ratio = newSize.width / image.size.height
        delta = (ratio * image.size.height) - (ratio * image.size.width)
        offset = CGPointMake(0, delta / 2)
    }
    let clipRect = CGRectMake(-offset.x, -offset.y, (ratio * image.size.width) + delta, (ratio * image.size.height) + delta)
    UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
    UIRectClip(clipRect)
    image.drawInRect(clipRect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

Als iemand wil dat de doelstelling c-versie, het is op zijn website.

antwoordde op 16/08/2015 om 22:00
bron van user

stemmen
2

Xamarin.iOS versie voor geaccepteerde antwoord op hoe om het formaat en vervolgens wilt bijsnijden UIImage (Aspect Fill) is hieronder

    public static UIImage ScaleAndCropImage(UIImage sourceImage, SizeF targetSize)
    {
        var imageSize = sourceImage.Size;
        UIImage newImage = null;
        var width = imageSize.Width;
        var height = imageSize.Height;
        var targetWidth = targetSize.Width;
        var targetHeight = targetSize.Height;
        var scaleFactor = 0.0f;
        var scaledWidth = targetWidth;
        var scaledHeight = targetHeight;
        var thumbnailPoint = PointF.Empty;
        if (imageSize != targetSize)
        {
            var widthFactor = targetWidth / width;
            var heightFactor = targetHeight / height;
            if (widthFactor > heightFactor)
            {
                scaleFactor = widthFactor;// scale to fit height
            }
            else
            {
                scaleFactor = heightFactor;// scale to fit width
            }
            scaledWidth = width * scaleFactor;
            scaledHeight = height * scaleFactor;
            // center the image
            if (widthFactor > heightFactor)
            {
                thumbnailPoint.Y = (targetHeight - scaledHeight) * 0.5f;
            }
            else
            {
                if (widthFactor < heightFactor)
                {
                    thumbnailPoint.X = (targetWidth - scaledWidth) * 0.5f;
                }
            }
        }
        UIGraphics.BeginImageContextWithOptions(targetSize, false, 0.0f);
        var thumbnailRect = new RectangleF(thumbnailPoint, new SizeF(scaledWidth, scaledHeight));
        sourceImage.Draw(thumbnailRect);
        newImage = UIGraphics.GetImageFromCurrentImageContext();
        if (newImage == null)
        {
            Console.WriteLine("could not scale image");
        }
        //pop the context to get back to the default
        UIGraphics.EndImageContext();

        return newImage;
    }
antwoordde op 09/09/2014 om 08:29
bron van user

stemmen
2

Ik wijzigde Brad Larson Code. Het zal aspect vult de afbeelding in bepaalde rect.

-(UIImage*) scaleAndCropToSize:(CGSize)newSize;
{
    float ratio = self.size.width / self.size.height;

    UIGraphicsBeginImageContext(newSize);

    if (ratio > 1) {
        CGFloat newWidth = ratio * newSize.width;
        CGFloat newHeight = newSize.height;
        CGFloat leftMargin = (newWidth - newHeight) / 2;
        [self drawInRect:CGRectMake(-leftMargin, 0, newWidth, newHeight)];
    }
    else {
        CGFloat newWidth = newSize.width;
        CGFloat newHeight = newSize.height / ratio;
        CGFloat topMargin = (newHeight - newWidth) / 2;
        [self drawInRect:CGRectMake(0, -topMargin, newSize.width, newSize.height/ratio)];
    }

    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}
antwoordde op 09/01/2012 om 21:02
bron van user

stemmen
1

Ik vond dat de Swift 3 gepost door Evgenii Kanvets niet uniform de schaal van de afbeelding.

Hier is mijn Swift 4 versie van de functie die het beeld niet squish:

static func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage? {

    // This function returns a newImage, based on image
    // - image is scaled uniformaly to fit into a rect of size newSize
    // - if the newSize rect is of a different aspect ratio from the source image
    //     the new image is cropped to be in the center of the source image
    //     (the excess source image is removed)

    var ratio: CGFloat = 0
    var delta: CGFloat = 0
    var drawRect = CGRect()

    if newSize.width > newSize.height {

        ratio = newSize.width / image.size.width
        delta = (ratio * image.size.height) - newSize.height
        drawRect = CGRect(x: 0, y: -delta / 2, width: newSize.width, height: newSize.height + delta)

    } else {

        ratio = newSize.height / image.size.height
        delta = (ratio * image.size.width) - newSize.width
        drawRect = CGRect(x: -delta / 2, y: 0, width: newSize.width + delta, height: newSize.height)

    }

    UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
    image.draw(in: drawRect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
} 
antwoordde op 19/06/2018 om 00:58
bron van user

stemmen
1
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0,0.0,ScreenWidth,ScreenHeigth)];
    [scrollView setBackgroundColor:[UIColor blackColor]];
    [scrollView setDelegate:self];
    [scrollView setShowsHorizontalScrollIndicator:NO];
    [scrollView setShowsVerticalScrollIndicator:NO];
    [scrollView setMaximumZoomScale:2.0];
    image=[image scaleToSize:CGSizeMake(ScreenWidth, ScreenHeigth)];
    imageView = [[UIImageView alloc] initWithImage:image];
    UIImageView* imageViewBk = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]];
    [self.view addSubview:imageViewBk];
    CGRect rect;
    rect.origin.x=0;
    rect.origin.y=0;
    rect.size.width = image.size.width;
    rect.size.height = image.size.height;

    [imageView setFrame:rect];

    [scrollView setContentSize:[imageView frame].size];
    [scrollView setMinimumZoomScale:[scrollView frame].size.width / [imageView frame].size.width];
    [scrollView setZoomScale:[scrollView minimumZoomScale]];
    [scrollView addSubview:imageView];

    [[self view] addSubview:scrollView];

dan kun je screenshots nemen om uw afbeelding door deze

float zoomScale = 1.0 / [scrollView zoomScale];
CGRect rect;
rect.origin.x = [scrollView contentOffset].x * zoomScale;
rect.origin.y = [scrollView contentOffset].y * zoomScale;
rect.size.width = [scrollView bounds].size.width * zoomScale;
rect.size.height = [scrollView bounds].size.height * zoomScale;

CGImageRef cr = CGImageCreateWithImageInRect([[imageView image] CGImage], rect);

UIImage *cropped = [UIImage imageWithCGImage:cr];

CGImageRelease(cr);
antwoordde op 23/11/2012 om 10:31
bron van user

stemmen
1

De volgende eenvoudige code werkte voor mij.

[imageView setContentMode:UIViewContentModeScaleAspectFill];
[imageView setClipsToBounds:YES];
antwoordde op 27/06/2012 om 09:07
bron van user

stemmen
0

Hier is een Swift 3-versie van de gids Sam Wirch om snel gepost door William T.

extension UIImage {

    static func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage? {
        var ratio: CGFloat = 0
        var delta: CGFloat = 0
        var offset = CGPoint.zero

        if image.size.width > image.size.height {
            ratio = newSize.width / image.size.width
            delta = (ratio * image.size.width) - (ratio * image.size.height)
            offset = CGPoint(x: delta / 2, y: 0)
        } else {
            ratio = newSize.width / image.size.height
            delta = (ratio * image.size.height) - (ratio * image.size.width)
            offset = CGPoint(x: 0, y: delta / 2)
        }

        let clipRect = CGRect(x: -offset.x, y: -offset.y, width: (ratio * image.size.width) + delta, height: (ratio * image.size.height) + delta)
        UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
        UIRectClip(clipRect)
        image.draw(in: clipRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }

}
antwoordde op 04/09/2017 om 12:38
bron van user

stemmen
0

Deze vraag lijkt te zijn om te rusten te zetten, maar in mijn zoektocht naar een oplossing die ik kon gemakkelijker te begrijpen (en geschreven in Swift), kwam ik op dit (ook geplaatst op: ? Hoe de UIImage bijsnijden )


Ik wil kunnen snijden uit een gebied op basis van een aspectverhouding en schaal een afmeting gebaseerd op een buitenzijde begrenzende mate. Hier is mijn variatie:

import AVFoundation
import ImageIO

class Image {

    class func crop(image:UIImage, crop 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
    }
}

Er zijn een paar dingen die ik vond verwarrend, de afzonderlijke belangen van bijsnijden en vergroten of verkleinen. Bijsnijden wordt behandeld met de oorsprong van de rect die u doorgeeft aan drawInRect, en de schaalvergroting wordt afgehandeld door de portiegrootte. In mijn geval, ik nodig had om de grootte van de uitsnede rect op de bron relateren, mijn uitgang rect van hetzelfde aspect ratio. De schaalfactor wordt dan uitgang / ingang, en dit moet worden toegepast op de drawRect (doorgegeven aan drawInRect).

Een nadeel is dat deze aanpak effectief gaat ervan uit dat de afbeelding die u aan het tekenen is groter dan het beeld context. Ik heb dit niet getest, maar ik denk dat je kunt deze code gebruiken om te behandelen bijsnijden / zoomen, maar expliciet definiëren van de parameter schaal om de hiervoor genoemde schaal parameter. Standaard UIKit geldt een multiplier op basis van de schermresolutie.

Tot slot dient te worden opgemerkt dat deze UIKit aanpak is hoger niveau dan CoreGraphics / Quartz en Core Image benaderingen, en lijkt beeldoriëntatie kwesties te behandelen. Het is ook het vermelden waard dat het vrij snel, tweede tot en ImageIO, volgens deze post hier: http://nshipster.com/image-resizing/

antwoordde op 28/05/2015 om 04:58
bron van user

stemmen
0

Swift versie:

    static func imageWithImage(image:UIImage, newSize:CGSize) ->UIImage {
    UIGraphicsBeginImageContextWithOptions(newSize, true, UIScreen.mainScreen().scale);
    image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))

    let newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    return newImage
}
antwoordde op 24/02/2015 om 07:32
bron van user

stemmen
0
- (UIImage*)imageScale:(CGFloat)scaleFactor cropForSize:(CGSize)targetSize
{
    targetSize = !targetSize.width?self.size:targetSize;
    UIGraphicsBeginImageContext(targetSize); // this will crop

    CGRect thumbnailRect = CGRectZero;

    thumbnailRect.size.width  = targetSize.width*scaleFactor;
    thumbnailRect.size.height = targetSize.height*scaleFactor;
    CGFloat xOffset = (targetSize.width- thumbnailRect.size.width)/2;
    CGFloat yOffset = (targetSize.height- thumbnailRect.size.height)/2;
    thumbnailRect.origin = CGPointMake(xOffset,yOffset);

    [self drawInRect:thumbnailRect];

    UIImage *newImage  = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage == nil)
    {
        NSLog(@"could not scale image");
    }

    UIGraphicsEndImageContext();

    return newImage;
}

Onder het voorbeeld van het werk: Left afbeelding - (image oorsprong); Rechter afbeelding met schaal x2

voer image beschrijving hier

Als u wilt dat het op schaal, maar behoudt zijn frame (verhoudingen), methode noemen deze manier:

[yourImage imageScale:2.0f cropForSize:CGSizeZero];
antwoordde op 12/02/2015 om 15:30
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more