Zapisywanie zawartości UIView w systemie iOS 4 z rzeczywistym rozmiarem obrazów wewnątrz (np.)

Mam UIView z wieloma UIImageViews jako podview. Aplikacja działa na iOS4 i używam obrazów z rozdzielczością wyświetlacza retina (tzn. obrazy ładują się ze skalą = 2)

Chcę zapisać zawartość UIView ... Ale ... mieć rzeczywisty rozmiar obrazów w środku. Czyli widok ma rozmiar 200x200 i obrazy ze skalą = 2 wewnątrz, chciałbym zapisać wynikowy obraz 400x400 i wszystkie obrazy z ich rzeczywistym rozmiarem.

Teraz to, co przychodzi na myśl, to stworzenie nowego kontekstu obrazu i załadować ponownie Wszystkie obrazy wewnątrz ze skalą = 1 i to powinno wystarczyć, ale zastanawiałem się, czy jest jakiś bardziej elegancki sposób, aby to zrobić? Wygląda na talię pamięci i czasu procesora, aby ponownie załadować wszystko, ponieważ jest już zrobione ...

P. S. jeśli ktoś ma odpowiedź-w tym kod byłby miły

Author: Marin Todorov, 2010-11-18

5 answers

Implementacja do renderowania dowolnego UIView do obrazu (działa również na wyświetlaczu retina).

Pomocnik.plik h:

@interface UIView (Ext) 
- (UIImage*) renderToImage;
@end

I implementacja w helperze.plik m:

#import <QuartzCore/QuartzCore.h>

@implementation UIView (Ext)
- (UIImage*) renderToImage
{
  // IMPORTANT: using weak link on UIKit
  if(UIGraphicsBeginImageContextWithOptions != NULL)
  {
    UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
  } else {
    UIGraphicsBeginImageContext(self.frame.size);
  }

  [self.layer renderInContext:UIGraphicsGetCurrentContext()];
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();  
  return image;
}

0.0 jest współczynnikiem skali. Współczynnik skali zastosowany do bitmapy. Jeśli podasz wartość 0.0, współczynnik skali zostanie ustawiony na współczynnik skali na głównym ekranie urządzenia.

QuartzCore.framework również należy umieścić w projekcie, ponieważ wywołujemy funkcję na obiekt warstwy.

Aby włączyć słabe łącze na frameworku UIKit, kliknij element projektu w lewym nawigatorze, kliknij cel projektu - > fazy budowania - > link binarny i wybierz "opcjonalny" (słaby) typ na frameworku UIKit.

Oto biblioteka z podobnymi rozszerzeniami dla UIColor, UIImage, nsArray, NSDictionary, ...

 25
Author: Prcela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-09 15:04:19

Wykonałem coś takiego, aby zapisać piny z MKMapView jako plik PNG (na wyświetlaczu retina): MKPinAnnotationView: czy są dostępne więcej niż trzy kolory?

Oto wyciąg z kluczowej części, która wykonuje zapisanie UIView (theView) korzystając z definicji siatkówki:


-(void) saveMyView:(UIView*)theView {
    //The image where the view content is going to be saved.
    UIImage* image = nil;
    UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, 2.0);
    [theView.layer renderInContext: UIGraphicsGetCurrentContext()];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData* imgData = UIImagePNGRepresentation(image);
    NSString* targetPath = [NSString stringWithFormat:@"%@/%@", [self writablePath], @"thisismyview.png" ];
    [imgData writeToFile:targetPath atomically:YES]; 
}

-(NSString*) writablePath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; return documentsDirectory; }

 4
Author: yonel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:20:44

Kluczem Jest to, że trzecim parametrem UIGraphicsBeginImageContextWithOptions jest skala , która określa, w jaki sposób obraz zostanie ostatecznie napisany.

Jeśli zawsze chcesz mieć rzeczywiste wymiary w pikselach, użyj skali [[uiscreen mainScreen], aby uzyskać bieżącą skalę ekranu:

UIGraphicsBeginImageContextWithOptions(viewSizeInPoints, YES, [[UIScreen mainScreen] scale]);

Jeśli użyjesz skali=1.0 na iPhone4, otrzymasz obraz z jego wymiarem w punktach , a wynik zostanie pomniejszony o rzeczywistą liczbę pikseli. Jeśli ręcznie Zapisz obraz do wymiaru 640x960 (np.: przechodząc piksele jako pierwszy parametr), to w rzeczywistości będzie to pomniejszony obraz, który jest skalowany z powrotem do góry, który wygląda tak okropnie, jak sobie wyobrażasz, że wyglądałby.

 2
Author: russbishop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-23 17:08:00

Nie możesz po prostu utworzyć nowego kontekstu graficznego w pożądanym rozmiarze, użyć formularza CGAffineTransform, aby skalować go w dół, wyrenderować główną warstwę UIView, przywrócić kontekst do oryginalnego rozmiaru i renderować obraz? Nie próbowałem tego w przypadku treści retina, ale wydaje się, że działa to dobrze w przypadku dużych obrazów, które zostały zmniejszone w UIImageViews...

Coś w stylu:

CGSize originalSize = myOriginalImage.size; //or whatever

//create context
UIGraphicsBeginImageContext(originalSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context); //1 original context

// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, originalSize.height);
CGContextScaleCTM(context, 1.0, -1.0);

//original image
CGContextDrawImage(context, CGRectMake(0,0,originalSize.width,originalSize.height), myOriginalImage.CGImage);

CGContextRestoreGState(context);//1 restore to original for UIView render;

//scaling
CGFloat wratio = originalSize.width/self.view.frame.size.width;
CGFloat hratio = originalSize.height/self.view.frame.size.height;

//scale context to match view size
CGContextSaveGState(context); //1 pre-scaled size
CGContextScaleCTM(context, wratio, hratio);

//render 
[self.view.layer renderInContext:context];

CGContextRestoreGState(context);//1  restore to pre-scaled size;

UIImage *exportImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
 0
Author: Steven Veltema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-24 04:18:52

Importuj QuartzCore (kliknij główny projekt, fazy budowania, import) i tam, gdzie potrzebujesz, dodaj:

#import <QuartzCore/QuartzCore.h>

Moje obrazy są właściwościami, jeśli twoje nie są, zignoruj .self i przekaż imageViews do funkcji jako parametry, a następnie wywołaj renderInContext na dwóch obrazach w Nowym UIGraphicsCurrentContext

- (UIImage *)saveImage
{
    UIGraphicsBeginImageContextWithOptions(self.mainImage.bounds.size, NO, 0.0);

    [self.backgroundImage.layer renderInContext:UIGraphicsGetCurrentContext()];
    [self.mainImage.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *savedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return savedImage;
}
 0
Author: Joshua Dance,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 18:07:55