如何动态处理图像平铺
我正在编写一个应用程序,它将平铺图像 256 * 256 并将这些平铺文件写回到目录中。如果有任何更新,我每次都会更新我的 URL,并将这些图像平铺回来并存储在 iphone 文件夹中。我主要担心两件事: 1)内存消耗——5张大小为200KB的图像的内存消耗会很多吗? 2) 如果我必须同时使用图像平铺 5 个不同的 URL,我可以多快处理我的应用程序?
我已经编写了一段代码来平铺并保存在一个 URL 的目录中,并且希望对 5 个 URL 执行相同的操作。是否建议采用这种方法,或者是否有人有不同的方法?
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *URLString = @"http://www.abc.com/abc.html?event=123";
NSURL *url = [[NSURL alloc] initWithString:URLString];
NSData * dataImage = [NSData dataWithContentsOfURL:url];
NSString *directoryPath = [[NSBundle mainBundle] bundlePath];
UIImage *big = [UIImage imageWithData:dataImage];
[self saveTilesOfSize:(CGSize){256,256} forImage:big toDirectory:directoryPath usingPrefix:@"image_124_"];
TileView *tv = [[TileView alloc] initWithFrame:(CGRect){{0,0}, (CGSize){5000,5000}}];
[tv setTileTag:@"image_110_"];
[tv setTileDirectory:directoryPath];
[scrollView addSubview:tv];
[scrollView setContentSize:(CGSize){5000,5000}];
}
- (void)saveTilesOfSize:(CGSize)size
forImage:(UIImage*)image
toDirectory:(NSString*)directoryPath
usingPrefix:(NSString*)prefix
{
CGFloat cols = [image size].width / size.width;
CGFloat rows = [image size].height / size.height;
int fullColumns = floorf(cols);
int fullRows = floorf(rows);
CGFloat remainderWidth = [image size].width -
(fullColumns * size.width);
CGFloat remainderHeight = [image size].height -
(fullRows * size.height);
if (cols > fullColumns) fullColumns++;
if (rows > fullRows) fullRows++;
CGImageRef fullImage = [image CGImage];
for (int y = 0; y < fullRows; ++y) {
for (int x = 0; x < fullColumns; ++x) {
CGSize tileSize = size;
if (x + 1 == fullColumns && remainderWidth > 0) {
// Last column
tileSize.width = remainderWidth;
}
if (y + 1 == fullRows && remainderHeight > 0) {
// Last row
tileSize.height = remainderHeight;
}
CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage,
(CGRect){{x*size.width, y*size.height},
tileSize});
NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:tileImage]);
NSString *path = [NSString stringWithFormat:@"%@/%d.png",
directoryPath, prefix];
[imageData writeToFile:path atomically:NO];
}
}
}
I am writing an app which would tile the images 256 * 256 and write those tile files back in the directory. I am updating my URL each time if there are any updates and tile those images back and store in the iphone folder. I am worried about two main things :
1) Memory consumption -- will the memory consumption for 5 images of size 200 KB a lot ?
2) How fast I can process my app if I have to tile 5 different URL with images at the same time ?
I have written a code to tile and save in the directory for one URL and would like to do the same for 5 URLs. Is it recommended to go with this approach or if anyone has a different approach?
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *URLString = @"http://www.abc.com/abc.html?event=123";
NSURL *url = [[NSURL alloc] initWithString:URLString];
NSData * dataImage = [NSData dataWithContentsOfURL:url];
NSString *directoryPath = [[NSBundle mainBundle] bundlePath];
UIImage *big = [UIImage imageWithData:dataImage];
[self saveTilesOfSize:(CGSize){256,256} forImage:big toDirectory:directoryPath usingPrefix:@"image_124_"];
TileView *tv = [[TileView alloc] initWithFrame:(CGRect){{0,0}, (CGSize){5000,5000}}];
[tv setTileTag:@"image_110_"];
[tv setTileDirectory:directoryPath];
[scrollView addSubview:tv];
[scrollView setContentSize:(CGSize){5000,5000}];
}
- (void)saveTilesOfSize:(CGSize)size
forImage:(UIImage*)image
toDirectory:(NSString*)directoryPath
usingPrefix:(NSString*)prefix
{
CGFloat cols = [image size].width / size.width;
CGFloat rows = [image size].height / size.height;
int fullColumns = floorf(cols);
int fullRows = floorf(rows);
CGFloat remainderWidth = [image size].width -
(fullColumns * size.width);
CGFloat remainderHeight = [image size].height -
(fullRows * size.height);
if (cols > fullColumns) fullColumns++;
if (rows > fullRows) fullRows++;
CGImageRef fullImage = [image CGImage];
for (int y = 0; y < fullRows; ++y) {
for (int x = 0; x < fullColumns; ++x) {
CGSize tileSize = size;
if (x + 1 == fullColumns && remainderWidth > 0) {
// Last column
tileSize.width = remainderWidth;
}
if (y + 1 == fullRows && remainderHeight > 0) {
// Last row
tileSize.height = remainderHeight;
}
CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage,
(CGRect){{x*size.width, y*size.height},
tileSize});
NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:tileImage]);
NSString *path = [NSString stringWithFormat:@"%@/%d.png",
directoryPath, prefix];
[imageData writeToFile:path atomically:NO];
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我已经用不同的方法实现了类似问题的解决方案(不同的是,我没有将它们保存在目录中,这些仅用于显示目的。)。
在我的问题中,
我有 84 个尺寸为 250x250 的图像,每个图像大小为 8KB
(我将它们添加到scrollView
上,并在滚动时加载它们,有点类似于谷歌地图,但是更顺畅)。起初我使用与你相同的方法,但性能有问题。所以,我使用了异步加载的概念。我编写了一个带有连接委托的 UIImageView 子类,因此 UIImageView 子类负责加载其图像。由于加载是异步的,因此性能要好得多。正如您所问的
1)内存消耗 - 5 个大小为 200 KB 的图像的内存消耗会很多吗?
Ans
:5x200KB = 1MB ~ 1.2MB 左右(所以你需要那么多内存来显示,如果你有那么多内存,那么你不用担心。)..在我的例子中,84x8KB = 672 ~ 900KB(因为我正在使用一些额外的东西,比如每个图像视图的活动指示器)。2)如果我必须同时使用图像平铺 5 个不同的 URL,我可以多快处理我的应用程序?
Ans
:当您在 viewDidLoad 中加载它时...或者在主线程中,那么性能将成为一个问题(可能会发生阻塞,因为我不完全确定您是否正在使用线程)。快速建议:
代码:
TileImageView.h
< code>TileImageView.m
所以,如果您使用上面的代码,那么您只需添加 TileImageView 对象并调用方法
-(void) startImageDownloading :(NSString *)pRequestURL
。更新:
//像这样,我在 2D 形状(12 x 7)网格中添加 84 个图像...添加图像后,我根据完整的网格大小设置滚动视图的 contentSize。
..稍后在代码中,当用户滚动和其他图像视图可见时。我使用以下代码...
TileImageView *loadableImageView = (TileImageView *)[myImageScrollView viewWithTag:];
[loadableImageView开始图像下载:];
我不需要在
drawRect
: 中执行任何操作,因为我不需要进行自定义绘图。对于图像名称,您可以使用
imageView
中的标签属性,但如果您需要一些更像字符串的不同名称,那么您可以在imageView
中为图像名称放置另一个属性并设置它同时添加图像视图。为了保存数据,您可以在TileImageView
的didFinishLoading
方法中下载图像后调用您的方法,您可以在其中使用该名称。第二次更新
添加
TileImageView
我如何在
ScrollView
和ScrollViewDelegate
方法中。这就是
createAndSendScrollRequest
的实现方式。谢谢,
I have implemented solution for the similar problem(the difference is, I was not saving them in directory, those were for display purpose only.), with different approach.
In my problem,
I have 84 images of 250x250 dimension with size 8KB each
( I added them onscrollView
and on scrolling I load them, a bit similar to google maps, but more smooth). At first I was using the same approach as yours, but performance was problem. So, I used asynchornous loading concept. I wrote an UIImageView subclass with connectiond delegates, so the UIImageView subclass was responsible for loading it's image. And as loading is asynchronous so performance is far better.As you asked
1) Memory consumption -- will the memory consumption for 5 images of size 200 KB a lot?
Ans
: 5x200KB = 1MB ~ 1.2MB or so(so you will need that much memory for displaying, if you have that much amount of memory then you should not worry.).. in my case 84x8KB = 672 ~ 900KB(as I was using some additional things like activity indicator for each imageview).2) How fast I can process my app if I have to tile 5 different URL with images at the same time ?
Ans
: As you are loading it in viewDidLoad ... or in main thread then performance will be an issue(blocking may happen, as I am not completely sure whether you are using threads or not).Quick suggestion:
CODE :
TileImageView.h
TileImageView.m
So, If you use above code then only thing you have to do is to add the object of TileImageView and just call method
-(void) startImageDownloading:(NSString *)pRequestURL
.Update :
//like this I add 84 images in a 2D shape( 12 x 7) grid ... and once Images are added I set scrollView's contentSize as per complete grid size.
..later in code when user scroll's and other imageviews come in visibility.I use following code...
TileImageView *loadableImageView = (TileImageView *)[myImageScrollView viewWithTag:];
[loadableImageView startImageDownloading:];
I do not need to do anything in
drawRect
: , as I have no need to do custome drawing.For Image names you can use tag property from
imageView
, but if you need some different name that are more like string then you can put another property inimageView
for image name and set it while adding the image view. for saving data you can call your method once the image is downloaded indidFinishLoading
method ofTileImageView
, where you can use that name.SECODN UPDATE
How I add
TileImageView
onScrollView
And in
ScrollViewDelegate
method.And this is how
createAndSendScrollRequest
is implemented.Thanks,