iOS 大图加载处理

iOS 大图加载处理,第1张

ios需要理解图片原始数据metadata,图片显示内存区别;处理分辨率与图片大小关系,

位图的大小计算公式:

图片width x heigth x 4(ARGB)

对于大图下载需要理解,沙盒作用.

对于大图上传,不能一次性加载压缩等处理,可以使用分片算法再进行上传。

对于大图显示,可以采用gpu的模式性渲染显示。整体思维如下:

        先计算好原图片的每个分片CGRect,然后在根据设备获取到对应的缩放后的分片CGRect,缩放的比例也是根据设备来设定。

        缩放后的分片CGRect和 p1生成缩放后的小分片,并且绘制到屏幕,这样一直循环把原图片全部的每个小分片全部生成对应缩放的小分片,然后绘制。

        以上效果,最终加载出来的图片质量上虽然没有太大变化,但是图片分辨率(即大小width x heigth)变小了。所以如果大图片的显示可以这么处理。


    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
   
    sourceImage = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:kImageFilename ofType:nil]];
    if( sourceImage == nil ) NSLog(@"input image not found!");
    
    sourceResolution.width = CGImageGetWidth(sourceImage.CGImage);
    sourceResolution.height = CGImageGetHeight(sourceImage.CGImage);
  
    sourceTotalPixels = sourceResolution.width * sourceResolution.height;
   
    sourceTotalMB = sourceTotalPixels / pixelsPerMB;
    
    imageScale = destTotalPixels / sourceTotalPixels;
   
    destResolution.width = (int)( sourceResolution.width * imageScale );
    destResolution.height = (int)( sourceResolution.height * imageScale );
  
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int bytesPerRow = bytesPerPixel * destResolution.width;
    
    void* destBitmapData = malloc( bytesPerRow * destResolution.height );
    if( destBitmapData == NULL ) NSLog(@"failed to allocate space for the output image!");
   
    destContext = CGBitmapContextCreate( destBitmapData, destResolution.width, destResolution.height, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast );
  
    if( destContext == NULL ) {
        free( destBitmapData ); 
        NSLog(@"failed to create the output bitmap context!");
    }        
  
    CGColorSpaceRelease( colorSpace );
 
    CGContextTranslateCTM( destContext, 0.0f, destResolution.height );
    CGContextScaleCTM( destContext, 1.0f, -1.0f );
  
    sourceTile.size.width = sourceResolution.width;
    
    sourceTile.size.height = (int)( tileTotalPixels / sourceTile.size.width );     
    NSLog(@"source tile size: %f x %f",sourceTile.size.width, sourceTile.size.height);
    sourceTile.origin.x = 0.0f;
    
    destTile.size.width = destResolution.width;
    destTile.size.height = sourceTile.size.height * imageScale;        
    destTile.origin.x = 0.0f;
    NSLog(@"dest tile size: %f x %f",destTile.size.width, destTile.size.height);
    
    sourceSeemOverlap = (int)( ( destSeemOverlap / destResolution.height ) * sourceResolution.height );
    NSLog(@"dest seem overlap: %f, source seem overlap: %f",destSeemOverlap, sourceSeemOverlap);    
    CGImageRef sourceTileImageRef;
 
    int iterations = (int)( sourceResolution.height / sourceTile.size.height );
   
    int remainder = (int)sourceResolution.height % (int)sourceTile.size.height;
    if( remainder ) iterations++;
    
    float sourceTileHeightMinusOverlap = sourceTile.size.height;
    sourceTile.size.height += sourceSeemOverlap;
    destTile.size.height += destSeemOverlap;    
    NSLog(@"beginning downsize. iterations: %d, tile height: %f, remainder height: %d", iterations, sourceTile.size.height,remainder );
    for( int y = 0; y < iterations; ++y ) {
       
        NSAutoreleasePool* pool2 = [[NSAutoreleasePool alloc] init];
        NSLog(@"iteration %d of %d",y+1,iterations);
        sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap; 
        destTile.origin.y = ( destResolution.height ) - ( ( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + destSeemOverlap ); 
    
        sourceTileImageRef = CGImageCreateWithImageInRect( sourceImage.CGImage, sourceTile );
      
        if( y == iterations - 1 && remainder ) {
            float dify = destTile.size.height;
            destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale;
            dify -= destTile.size.height;
            destTile.origin.y += dify;
        }

        CGContextDrawImage( destContext, destTile, sourceTileImageRef );

        CGImageRelease( sourceTileImageRef ); 


        [sourceImage release];
        // free all objects that were sent -autorelease within the scope of this loop.
        [pool2 drain];     
      
        if( y < iterations - 1 ) {            
            sourceImage = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:kImageFilename ofType:nil]];
            [self performSelectorOnMainThread:@selector(updateScrollView:) withObject:nil waitUntilDone:YES];
        }
    }
    NSLog(@"downsize complete.");
    [self performSelectorOnMainThread:@selector(initializeScrollView:) withObject:nil waitUntilDone:YES];
   
    CGContextRelease( destContext );
    [pool drain];
}

-(void)createImageFromContext {
   
    CGImageRef destImageRef = CGBitmapContextCreateImage( destContext );
    if( destImageRef == NULL ) NSLog(@"destImageRef is null.");
  
    self.destImage = [UIImage imageWithCGImage:destImageRef scale:1.0f orientation:UIImageOrientationDownMirrored];
   
    CGImageRelease( destImageRef );
    if( destImage == nil ) NSLog(@"destImage is nil.");

}

分片读取可以一下思想:

-(void)readDataWithChunk:(NSInteger)chunk file:(CNFile*)file{
  总片数的获取方法:
    int offset =1024*1024;(每一片的大小是1M)
    NSInteger chunks = (file.fileSize%1024==0)?((int)(file.fileSize/1024*1024)):((int)(file.fileSize/(1024*1024) + 1));
    NSLog(@"chunks = %ld",(long)chunks);
    将文件分片,读取每一片的数据:
    NSData* data;
    NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:file.filePath];
    [readHandle seekToFileOffset:offset * chunk];
    data = [readHandle readDataOfLength:offset];
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/993650.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存