在手机软件开发中,有种场景:工程中图片太多,很多png图片,导致程序安装包很大。尤其是出现在移动平台iOS,Android和游戏平台。这是因为png的头占用资源比较大,如果将所有png图片拼接到一起,就省了png的头部信息;那么程序安装包应该会少不小!
想法很好!如果程序中有四五百个png图片,手动合成到大图上恐怕不是小工作量。何况每天的资源图片都有可能更新,更新一张图片就要重新生成拼图。这个工作量肯定不是人能搞定的了。能否让计算机帮助我们来拼图。
拼图完成后,计算机告诉我们每个图片的坐标和长宽,程序运行时候我们根据坐标去截取图片就行了。文章最后下载算法demo
第一步,首先设定一个很大的空白图片,假设是(1000,1000)这样就够装很多图片(称之为目标图片)。考虑到最大限度利用目标图片,事先将所有图片的大小排序。最大在左上角,次大向右一次摊开。
将最大的图片放到空白图片左上角,如下图所示:那么可以将剩余的区域分为两部分:left和right部分,用于放后继图片。重复此逻辑,那么所有的图片都可以放得下了
看懂这个图片,主要通过三个● 和三块区域。迭代操作就是:继续对left进行分割,或者是right进行分割。
NSMutableArray* tmp = [NSMutableArray array]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(120, 100) name:@"1.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(120, 100) name:@"2.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(100, 100) name:@"3.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(80, 21) name:@"4.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(70, 40) name:@"5.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(65, 30) name:@"6.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(50, 21) name:@"7.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(50, 21) name:@"8.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(50, 21) name:@"9.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(50, 21) name:@"10.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(40, 40) name:@"11.png"]]; [tmp addObject:[[picNode alloc]initWithSize:CGSizeMake(35, 30) name:@"12.png"]];
-(bool) insertPicture:(BTreeNode*)node{ //如果图片大小,可以放下这个rect。那么就设置一下这个rect的大小为图片大小,剩余面积分为left和right if (!node.isFull && node.virtualPic.size.width >= _currentPic.size.width && node.virtualPic.size.height >= _currentPic.size.height) { node.isFull = TRUE; /* 拆分剩余rect为left和right两个分支。 ●---------●----------------- | picture | right | | | | ●--------------------------- | | | left | | | | | | | ---------------------------- 例如.picture已经占据了【左上角】区域。剩下的区域分为left和right。点(●)的地方就是CGPoint了。 ● 优化点:如果picture是矩形,那么在生成left和right的时候。可以有两个选择:向下延伸,向右延伸。 通常是向值小的一方延伸,这样保证值大的一方可以放进去更多的图片。 ● 上面的例子是向右延伸。 */ node.left = [[BTreeNode alloc]init]; node.left.point = CGPointMake(node.point.x, node.point.y + _currentPic.size.height); node.left.virtualPic = [[picNode alloc]init]; node.right = [[BTreeNode alloc]init]; node.right.point = CGPointMake(node.point.x+ _currentPic.size.width, node.point.y); node.right.virtualPic = [[picNode alloc]init]; //优化一下 if (_currentPic.size.width >= _currentPic.size.height) { //left的宽度是parent的宽度。高度是parent高度 - 图片的高度 node.left.virtualPic.size = CGSizeMake(node.virtualPic.size.width, node.virtualPic.size.height - _currentPic.size.height); //right的宽度是,parent的宽度-图片的宽度。高度是图片的高度。 node.right.virtualPic.size = CGSizeMake(node.virtualPic.size.width- _currentPic.size.width, _currentPic.size.height); }else{ //left的宽度是图片的宽度。高度是parent高度 - 图片的高度(不变) node.left.virtualPic.size = CGSizeMake(_currentPic.size.width, node.virtualPic.size.height - _currentPic.size.height); //right的宽度是,parent的宽度-图片的宽度。高度parent的高度。 node.right.virtualPic.size = CGSizeMake(node.virtualPic.size.width- _currentPic.size.width, node.virtualPic.size.height); } //将虚拟的pic复制 node.virtualPic = [_currentPic copy]; return YES; } return NO; }
后序遍历的图片利用率最高,这样的结果也符合人类的思维,假如我们手动排版。那么应该也是最大在上角,次大的往后排。后侧排满后再从左侧开始,即蛇型曲线。
demo下载地方点击打开链接