2014-04-10 8 views
11

छवि डिकंप्रेशन की समस्या स्टैक ओवरफ़्लो में बहुत अधिक चर्चा की गई है लेकिन इस प्रश्न तक kCGImageSourceShouldCacheImmediately के 0 उल्लेख थे, आईओएस 7 में पेश किया गया एक विकल्प, सिद्धांत रूप में, इस समस्या का ख्याल रखता है। शीर्षलेखों से:आईओएस में छवि डिकंप्रेशन 7

निर्दिष्ट करता है कि छवि निर्माण समय पर छवि डिकोडिंग और कैशिंग होना चाहिए या नहीं।

+ (UIImage *)decompressedImageWithData:(NSData *)data 
{ 
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 
    CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: @YES}); 

    UIImage *image = [UIImage imageWithCGImage:cgImage]; 
    CGImageRelease(cgImage); 
    CFRelease(source); 
    return image; 
} 

पुस्तकालय AFNetworking और SDWebImage की तरह अभी भी CGContextDrawImage विधि के साथ छवि विसंपीड़न कार्य करें:

Objc.io #7 में पीटर स्टीनबर्गर इस दृष्टिकोण का सुझाव दिया। SDWebImage से:

+ (UIImage *)decodedImageWithImage:(UIImage *)image { 
    if (image.images) { 
     // Do not decode animated images 
     return image; 
    } 

    CGImageRef imageRef = image.CGImage; 
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 
    CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize}; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); 

    int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask); 
    BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone || 
      infoMask == kCGImageAlphaNoneSkipFirst || 
      infoMask == kCGImageAlphaNoneSkipLast); 

    // CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB. 
    // https://developer.apple.com/library/mac/#qa/qa1037/_index.html 
    if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1) { 
     // Unset the old alpha info. 
     bitmapInfo &= ~kCGBitmapAlphaInfoMask; 

     // Set noneSkipFirst. 
     bitmapInfo |= kCGImageAlphaNoneSkipFirst; 
    } 
      // Some PNGs tell us they have alpha but only 3 components. Odd. 
    else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { 
     // Unset the old alpha info. 
     bitmapInfo &= ~kCGBitmapAlphaInfoMask; 
     bitmapInfo |= kCGImageAlphaPremultipliedFirst; 
    } 

    // It calculates the bytes-per-row based on the bitsPerComponent and width arguments. 
    CGContextRef context = CGBitmapContextCreate(NULL, 
      imageSize.width, 
      imageSize.height, 
      CGImageGetBitsPerComponent(imageRef), 
      0, 
      colorSpace, 
      bitmapInfo); 
    CGColorSpaceRelease(colorSpace); 

    // If failed, return undecompressed image 
    if (!context) return image; 

    CGContextDrawImage(context, imageRect, imageRef); 
    CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); 

    CGContextRelease(context); 

    UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation]; 
    CGImageRelease(decompressedImageRef); 
    return decompressedImage; 
} 

मेरा प्रश्न है हम iOS 7 में kCGImageSourceShouldCacheImmediately दृष्टिकोण पर जाना चाहिए?

+1

अस्वीकरण: मैं एसडीवेब इमेज के विकल्प हनेके के लेखक हूं और मैं यह पूछने के लिए कह रहा हूं कि मैं अपनी लाइब्रेरी में छवियों को कैसे डीकोड करता हूं। – hpique

+0

क्या स्पष्ट नहीं है कि इस समस्या को उत्पन्न करने वाली समस्या क्या है? आप इससे चिंतित क्यों हैं? – SpaceDog

उत्तर

-2

आप नीचे दिए गए इस कोड की कोशिश कर सकते:

+(NSData *)imageData:(UIImage *)image 
{ 
    //1.0 == 100% 
    return UIImageJPEGRepresentation(image, 0.7); 
} 

चीयर्स!

0

कि जिस तरह से किया जा सकता है:

+ (UIImage *)imageFromURL:(NSURL *)url { 
    UIImage *result = nil; 
    if ([url isFileURL]) { 
     CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)url, NULL); 
     if (source) { 
      NSDictionary * attributes = @{ (id)kCGImageSourceShouldCache : @YES }; 
      CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)attributes); 
      if (cgImage) { 
       result = [UIImage imageWithCGImage:cgImage]; 
       CGImageRelease(cgImage); 
      } 
      CFRelease(source); 
     } 
    } 
    return result; 
} 
3

कार्यान्वयन जहाँ तक मैं बता सकता हूँ के साथ कुछ समस्याएं हैं।

  1. इस "नई विधि" को मुख्य धागे पर किसी प्रकार की प्रतिपादन की आवश्यकता होती है। आप छवि लोड कर सकते हैं और तुरंत कैश कैश करना चाहिए, लेकिन यह प्रक्रिया के लिए मुख्य थ्रेड में कुछ ऑपरेशन सेट करेगा। जब आप स्क्रॉल दृश्य और संग्रह दृश्य लोड करते हैं तो इससे स्टटरिंग हो जाएगी। यह पृष्ठभूमि में प्रेषण कतारों के साथ पुराने तरीके से करने के लिए मेरे लिए अधिक stutters।

  2. यदि आप फ़ाइलों के बजाय अपने स्वयं के मेमोरी बफर का उपयोग कर रहे हैं, तो आपको डेटा प्रदाताओं को डेटा कॉपी करने की आवश्यकता होगी, क्योंकि ऐसा लगता है कि डेटा प्रदाता स्मृति मेमरी को चारों ओर लटकने की अपेक्षा करते हैं। यही कारण है कि स्पष्ट लगता है, लेकिन इस समारोह नेतृत्व में झंडे क्या आप ऐसा कर सकते हैं विश्वास करने के लिए:

    • एक डेटा प्रदाता बनाने के कुछ स्रोत
    • से संकुचित जेपीईजी डेटा के साथ अपने स्वयं बफर को भरने और इसे करने के लिए जेपीईजी डेटा देते हैं
    • कैश के साथ डेटा प्रदाता से छवि स्रोत तुरंत सेट
    • छवि स्रोत का उपयोग एक तटरक्षक छवि
    • फेंक सभी मध्यवर्ती वस्तुओं दूर बना सकते हैं और हाथ अपने अच्छी तरह से decompressed CGImage एक UIImage अप करने के लिए वस्तु के लिए तैयार वस्तु बनाने स्क्रॉलिंग

यह है कि हालांकि ऐसा नहीं करता है, क्योंकि यह मुख्य थ्रेड जहां विसंपीड़न को होगा इंतजार करेगा। ऐसा लगता है कि सब ठीक है क्योंकि यह आपके द्वारा जारी की गई सभी मध्यस्थ वस्तुओं के संदर्भ में है। आपने इन सभी ऑब्जेक्ट्स को यह सोचकर जारी किया कि यह तुरंत डिकंप्रेस्ड है क्योंकि झंडे ने कहा था कि यह होगा। यदि आपने उस मेमोरी बफर को भी फेंक दिया है, और उस मेमोरी बफर को नो-कॉपी अर्थ में पारित किया गया था, तो आप कचरे के साथ खत्म होने जा रहे हैं।या, अगर मेरे मामले में मेमोरी बफर का पुन: उपयोग किया गया था, तो दूसरी छवि लोड करने के लिए, आपको कचरा भी मिल जाएगा।

आपके पास वास्तव में यह जानने का कोई तरीका नहीं है कि यह छवि डिकंप्रेस्ड होने और उपयोग के लिए तैयार होने जा रही है।

टी एल; डॉ = "पर विचार करें मतलब kCGImageSourceShouldCacheImmediately जब ओएस के लिए सुविधाजनक"

जब आप इसे "पुराना तरीका" करते हैं, आप 100% पता है कि उपलब्ध है और जब होने के लिए जा रहा है। क्योंकि यह परिभाषित नहीं कर रहा है कि आप कुछ प्रतिलिपि से बच सकते हैं। मुझे नहीं लगता कि यह एपीआई वैसे भी जादुई कर रहा है, मुझे लगता है कि यह सिर्फ मेमोरी बफर धारण कर रहा है और फिर चीजों को हुड के नीचे "पुराना तरीका" कर रहा है।

तो यहां मूल रूप से कोई निःशुल्क भोजन नहीं है। जब मैं सोचता था कि यह सब साइन आउट किया गया था, तो मुझे यह पता चला कि यह चीज़ दुर्घटनाग्रस्त हो गई है, जहां से यह सबकुछ दुर्घटनाग्रस्त हो गया था, मुझे लगता है कि यह सीए :: लेनदेन, सीए :: परत, सीए :: रेंडर, और से ImageProviderCopy में ... जेपीईजीपीआरएसजेपीईजीईएफओ (जहां यह मेरे बफर तक पहुंचने में दुर्घटनाग्रस्त हो गया) तक सभी तरह से नीचे।

यह है कि kCGImageSourceShouldCacheImmediately एक झंडा जितनी जल्दी हो सके मुख्य थ्रेड में संपीड़ित छवि बताने के लिए के रूप में आपको लगता है (पढ़ने पर) तुरंत इसका मतलब बनाने के बाद उसे और वास्तव में तुरंत नहीं किया है को छोड़कर कुछ भी नहीं करता है मतलब है। यदि आपने छवि को स्क्रॉल व्यू पर प्रदर्शित करने के लिए छवि को सौंप दिया था और यह छवि खींची गई तो यह वही काम करता। यदि आप भाग्यशाली हैं तो स्क्रॉलिंग के बीच कुछ अतिरिक्त चक्र थे और इससे चीजों में सुधार होगा, लेकिन मूल रूप से मुझे लगता है कि यह बहुत अधिक उम्मीद है कि यह वास्तव में उससे अधिक कर रहा है।