Frage an scale, ios, uiimage – UIImage wurde unscharf, als es skaliert wurde. Warum? (IOS 5.0)

12

UIImage wird immer undeutlich, wenn es skaliert wurde. Was kann ich tun, wenn es klar bleibt?

<code>- (UIImage *)rescaleImageToSize:(CGSize)size {
    CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
    UIGraphicsBeginImageContext(rect.size);
    [self drawInRect:rect];  // scales image to rect
    UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resImage;
}
</code>

Deine Antwort

4   die antwort
5

Ich habe die @ Dondragmer-Antwort mit VImage versucht, aber die Qualität des Ergebnisses war nicht gut genug (ich verkleinere das Bild mit einem Verhältnis von 1/10).

Diese Lösung funktionierte jedoch für mich:UIImage's drawInrect: Glättet das Bild

Grundsätzlich heißt es nur, dass Sie auf der Retina-Anzeige den grafischen Kontext mit dem Retina-Parameter erstellen müssen:

<code>UIGraphicsBeginImageContextWithOptions(size, NO, 2.0f);
</code>
Keines der oben oder unten hat für mich funktioniert, aber dieses, ich war für 2 Tage fest, upvote und upvote für Original, Prost !!! AamirR
0

In dem speziellen Fall, dass ein Bild vergrößert wird,und Um scharfe Ecken zu erhalten, müssen Sie die Bildinterpolation deaktivieren. Wenn es sich bei Ihrem Bild um Pixelkunst handelt, ist dies genau das, was Sie möchten. In den meisten anderen Fällen ist dies nicht der Fall.

<code>UIGraphicsBeginImageContext(rect.size);

// Turn off interpolation to keep the scaled image from being blurred.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

[self drawInRect:rect];  // scales image to rect
UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
</code>

Wenn Sie verkleinern, ist es auch nicht die beste Option, einfach mit kCGInterpolationHigh zu zeichnen.Es ist gut, aberCILanczosScaleTransform ist etwas schärfer.

Bearbeiten: CILanczosScaleTransform ist ab iOS 5.1 nicht mehr verfügbar. In meiner anderen Antwort finden Sie eine hochwertige Skalierungsroutine, die Sie verwenden können.

wow, mein gott, verdiene dir mehr als 10 ruf, um bilder zu posten. shuiyouren
Ich denke, CILanczosScaleTransform kann es lösen. Ich suche nach Anweisungen zur Verwendung von CILanczosScaleTransform. shuiyouren
@shuiyouren: Tut mir leid, dass ich das Unmögliche gefragt habe. Wie auch immer, ich habe die Umstände beschrieben, unter denen Sie CILanczosScaleTransform benötigen. Können Sie bestätigen, dass diese für Ihr Problem zutreffen? Dondragmer
Haben Sie mir ein Beispiel für diese Frage zu CILanczosScaleTransform gegeben? shuiyouren
@shuiyouren: Ich habe kein Beispiel für CILanczosScaleTransform angegeben, da ich nicht weiß, ob Sie es benötigen. Bitte hängen Sie zwei Bilder an Ihren Originalbeitrag an: das Bild vor dem Skalieren und das Bild nach dem Skalieren. Dann kann Ihnen möglicherweise jemand sagen, welchen Algorithmus Sie benötigen. Dondragmer
2

Versuchen Sie es mit:

<code>CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
</code>

vor dem Zeichnen, um eine qualitativ hochwertige Interpolation zu erhalten.

Versucht, aber es ist nicht bewirkt. shuiyouren
@shuiyouren Das ist so gut wie du nur kannst. AFAIK, Quartz2D verwendet Bilinear, weil es in Echtzeit schneller ist. Die Qualität ist schlechter als bikubisch. Wenn Sie eine noch höhere Qualität wünschen, müssen Sie möglicherweise Ihre eigenen Interpolationsalgorithmen verwenden. He Shiming
46
Runden

Stellen Sie zunächst sicher, dass Sie Ihre Größe runden, bevor Sie skalieren.drawInRect: kann in diesem Fall ein ansonsten verwendbares Bild unscharf machen. So runden Sie auf den nächsten ganzzahligen Wert:

<code>size.width = truncf(size.width);
size.height = truncf(size.height);
</code>

Für bestimmte Aufgaben möchten Sie möglicherweise stattdessen abrunden (floorf) oder aufrunden (ceilingf).

CILanczosScaleTransform nicht verfügbar

Ignorieren Sie dann meine vorherige Empfehlung von CILanczosScaleTransform. Teile von Core Image sind in iOS 5.0 verfügbar, die Lanczos-Skalierung jedoch nicht. Wenn es jemals verfügbar wird, nutzen Sie es. Wenn Sie mit Mac OS arbeiten, können Sie es verwenden.

vBildskalierung

In ist jedoch ein hochwertiger Skalierungsalgorithmus verfügbarvBild. Die folgenden Bilder zeigen, wie eine Methode, die sie verwendet (vImageScaledImage), mit den verschiedenen Kontextinterpolationsoptionen verglichen wird. Beachten Sie auch, wie sich diese Optionen bei verschiedenen Zoomstufen unterschiedlich verhalten.

DaraufDiagrammbewahrte es die meisten Liniendetails:

Darauffotografieren, vergleiche die Blätter unten links:

Darauffotografieren, vergleiche die Texturen unten rechts:

Verwenden Sie es nicht aufPixel Kunst; es entstehen seltsame Skalierungsartefakte:

Obwohl es weiter gehteinige bilder es hat interessante rundungseffekte:

Performance

Es überrascht nicht, dass kCGImageInterpolationHigh die langsamste Standard-Bildinterpolationsoption ist. vImageScaledImage, wie hier implementiert, ist noch langsamer. Für das Verkleinern des fraktalen Bildes auf die Hälfte seiner Originalgröße wurden 110% der Zeit von UIImageInterpolationHigh benötigt. Das Schrumpfen auf ein Viertel dauerte 340% der Zeit.

Sie könnten anders denken, wenn Sie es im Simulator ausführen. dort kann es viel schneller sein als kCGImageInterpolationHigh. Vermutlich bieten die Mehrkernoptimierungen von vImage einen relativen Vorteil für den Desktop.

Code
<code>// Method: vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize
// Returns even better scaling than drawing to a context with kCGInterpolationHigh.
// This employs the vImage routines in Accelerate.framework.
// For more information about vImage, see https://developer.apple.com/library/mac/#documentation/performance/Conceptual/vImage/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001001-CH201-TPXREF101
// Large quantities of memory are manually allocated and (hopefully) freed here.  Test your application for leaks before and after using this method.
- (UIImage*) vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize;
{
    UIImage *destImage = nil;

    if (sourceImage)
    {
        // First, convert the UIImage to an array of bytes, in the format expected by vImage.
        // Thanks: http://stackoverflow.com/a/1262893/1318452
        CGImageRef sourceRef = [sourceImage CGImage];
        NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
        NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        unsigned char *sourceData = (unsigned char*) calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
        NSUInteger bytesPerPixel = 4;
        NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
        NSUInteger bitsPerComponent = 8;
        CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight,
                                                     bitsPerComponent, sourceBytesPerRow, colorSpace,
                                                     kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef);
        CGContextRelease(context);

        // We now have the source data.  Construct a pixel array
        NSUInteger destWidth = (NSUInteger) destSize.width;
        NSUInteger destHeight = (NSUInteger) destSize.height;
        NSUInteger destBytesPerRow = bytesPerPixel * destWidth;
        unsigned char *destData = (unsigned char*) calloc(destHeight * destWidth * 4, sizeof(unsigned char));

        // Now create vImage structures for the two pixel arrays.
        // Thanks: https://github.com/dhoerl/PhotoScrollerNetwork
        vImage_Buffer src = {
            .data = sourceData,
            .height = sourceHeight,
            .width = sourceWidth,
            .rowBytes = sourceBytesPerRow
        };

        vImage_Buffer dest = {
            .data = destData,
            .height = destHeight,
            .width = destWidth,
            .rowBytes = destBytesPerRow
        };

        // Carry out the scaling.
        vImage_Error err = vImageScale_ARGB8888 (
                                                 &src,
                                                 &dest,
                                                 NULL,
                                                 kvImageHighQualityResampling 
                                                 );

        // The source bytes are no longer needed.
        free(sourceData);

        // Convert the destination bytes to a UIImage.
        CGContextRef destContext = CGBitmapContextCreate(destData, destWidth, destHeight,
                                                         bitsPerComponent, destBytesPerRow, colorSpace,
                                                         kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGImageRef destRef = CGBitmapContextCreateImage(destContext);

        // Store the result.
        destImage = [UIImage imageWithCGImage:destRef];

        // Free up the remaining memory.
        CGImageRelease(destRef);

        CGColorSpaceRelease(colorSpace);
        CGContextRelease(destContext);

        // The destination bytes are no longer needed.
        free(destData);

        if (err != kvImageNoError)
        {
            NSString *errorReason = [NSString stringWithFormat:@"vImageScale returned error code %d", err];
            NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                       sourceImage, @"sourceImage", 
                                       [NSValue valueWithCGSize:destSize], @"destSize",
                                       nil];

            NSException *exception = [NSException exceptionWithName:@"HighQualityImageScalingFailureException" reason:errorReason userInfo:errorInfo];

            @throw exception;
        }
    }
    return destImage;
}
</code>
Der Autor von {PhotoScrollerNetwork bedankt sich für die Zuordnung im Code: // Danke:github.com/dhoerl/PhotoScrollerNetwork :-) David H

Verwandte Fragen