前言
初做全景項(xiàng)目,涉及到了360度全景展示(也可以是720度的旋轉(zhuǎn)),查找了很多資料,很多都是用PanoramaGL這個(gè)庫(kù)實(shí)現(xiàn)的,本人也踩了一下坑,下面我簡(jiǎn)單的總結(jié)一下。
初識(shí)PanoramaGL
此處先提供一個(gè)可以在Xcode8運(yùn)行的 Demo (包含PanoramaGL庫(kù))。你下載下來(lái)看一下,運(yùn)行,沒有太大問題,只是第一張圖加載不出。
從Demo可以看出,使用PanoramaGL進(jìn)行全景圖展示很簡(jiǎn)單:
// 在ViewController.m
// #import "PLView.h"
-(void)viewDidLoad
{
[super viewDidLoad];
// 創(chuàng)建全景展示View,設(shè)置代理
self.plView.delegate = self;
//JSON loader example (see json.data, json_s2.data and json_cubic.data)
//[plView load:[PLJSONLoader loaderWithPath:[[NSBundle mainBundle] pathForResource:@"json_cubic" ofType:@"data"]]];
// 1. 創(chuàng)建全景圖 (單張)
NSObject<PLIPanorama> *panorama = nil;
panorama = [PLSphericalPanorama panorama];
[(PLSphericalPanorama *)panorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_sphere" ofType:@"jpg"]]]];
/* 2. 創(chuàng)建全景圖(多張圖片拼接)
PLCubicPanorama *cubicPanorama = [PLCubicPanorama panorama];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_f" ofType:@"jpg"]]] face:PLCubeFaceOrientationFront];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_b" ofType:@"jpg"]]] face:PLCubeFaceOrientationBack];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_l" ofType:@"jpg"]]] face:PLCubeFaceOrientationLeft];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_r" ofType:@"jpg"]]] face:PLCubeFaceOrientationRight];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_u" ofType:@"jpg"]]] face:PLCubeFaceOrientationUp];
[cubicPanorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_d" ofType:@"jpg"]]] face:PLCubeFaceOrientationDown];
panorama = cubicPanorama;
*/
// 設(shè)置一個(gè)熱點(diǎn)
PLTexture *hotspotTexture = [PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"hotspot" ofType:@"png"]]];
PLHotspot *hotspot = [PLHotspot hotspotWithId:(kIdMin + random() % ((kIdMax + 1) - kIdMin)) texture:hotspotTexture atv:0.0f ath:0.0f width:0.08f height:0.08f];
[panorama addHotspot:hotspot];
// 將全景圖展示
[self.plView setPanorama:panorama];
}
此處給大家說一下,這里單張的全景圖片的<寬高比限定為2:1>
而PanoramaGL僅支持單張分辨率2048x1024的全景圖,里面的
PLSpherical2Panorama 據(jù)說能支持4096x2048 的圖片,試了一下貌似不行。進(jìn)去看了一下源碼,所謂支持,就是基于2048x1024再縮放,然后進(jìn)圖片分割排布,效果不行。所以,自己生成預(yù)覽圖的時(shí)候,需將圖片大小轉(zhuǎn)為2048x1024。
給自己的項(xiàng)目配置PanoramaGL
看著Demo運(yùn)行的挺好的,但當(dāng)你把PanoramaGL拖進(jìn)你的項(xiàng)目,編譯,一大堆錯(cuò)誤!原因是Demo把不能運(yùn)行的坑都踩了,這個(gè)PanoramaGL庫(kù)2011年開始就不再維護(hù)了。庫(kù)是在MRC環(huán)境寫的,因此,直接在現(xiàn)在Xcode 的ARC環(huán)境編譯會(huì)出錯(cuò)。

解決以上問題:
在用MRC 環(huán)境寫的文件 添加 -fno-objc-arc,
屬于PanoramaGL基本這個(gè)庫(kù)的文件基本都要添加,但是,不是全部! 注意,文件后綴.c的文件不用添加 -fno-objc-arc

好不容易將這么多文件添加了-fno-objc-arc ,再編譯一下,蒙蔽了,瞬間幾十個(gè)錯(cuò)誤:

解決上面這個(gè)問題,有三個(gè)解決方案:
解決方案一:
選擇所有導(dǎo)入的.c文件,將屬性的 identity and type 改為Objective-C Source。

解決方案二:
選擇所有導(dǎo)入的.c文件,將.c修改為.m

解決方案三:
將Compile Sources As 改為 Objective-C++。
方案三由于修改所有文件的編譯類型,所有可能會(huì)導(dǎo)致其他包括c、c++代碼的提示錯(cuò)誤,不過都是些的提示異常,按提示修改即可。
改完了,編譯,終于通過。
項(xiàng)目使用實(shí)例
先給大家貼一下使用PanoramaGL實(shí)現(xiàn)預(yù)覽全景圖的控制器代碼吧:
// 此處是push出來(lái)的預(yù)覽全景圖控制器
// CPPreviewPanoController.h
@interface CPPreviewPanoController : UIViewController
@property (strong, nonatomic) UIImage *previewImage;
@end
// Created by JasonSu on 2017/5/17.
// Copyright ? 2017年 JasonSu. All rights reserved.
//
// CPPreviewPanoController.m
#import "CPPreviewPanoController.h"
#import "PLView.h"
#define kPreviewSize CGSizeMake(2048, 1024)
@interface CPPreviewPanoController ()<PLViewDelegate>
@property (strong , nonatomic) PLView *plView;
@end
@implementation CPPreviewPanoController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
// 創(chuàng)建預(yù)覽
self.plView = [[PLView alloc]initWithFrame:CGRectMake(0, 64, CPSCREEN_WIDTH, CPSCREEN_HEIGHT-64)];
self.plView.delegate = self;
[self.view addSubview:self.plView];
if (!self.previewImage) {
return;
}
UIImage *previewImg = [self reSizeImage:self.previewImage toSize:kPreviewSize];
NSLog(@"改變尺寸后的image==%@", previewImg);
CGImageRef cgRef = previewImg.CGImage;
NSObject<PLIPanorama> *panorama = nil;
// (supports up 2048x1024 texture)
panorama = [PLSphericalPanorama panorama];
[(PLSphericalPanorama *)panorama setTexture:[PLTexture textureWithImage:[PLImage imageWithCGImage:cgRef]]];
[self.plView setPanorama:panorama];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:YES];
[self.plView removeFromSuperview];
self.plView.delegate = nil;
self.plView = nil;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
/// 修改圖片尺寸
- (UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize
{
UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
[image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return reSizeImage;
}
本項(xiàng)目選擇圖片使用QBImagePicker
下面展示上一級(jí)控制器.m (即選擇手機(jī)相冊(cè)圖片的控制器)的部分代碼
#import "QBImagePickerController.h"
// 遵守QBImagePickerControllerDelegate
/// 選擇圖片
- (void)addPhoto:(CPImageUpButton *)btn
{
// CPLog(@"添加圖片");
QBImagePickerController *imagePickerController = [QBImagePickerController new];
imagePickerController.delegate = self;
imagePickerController.allowsMultipleSelection = NO; // 單選
// 只獲取圖片資源
imagePickerController.mediaType = QBImagePickerMediaTypeImage;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
#pragma mark - QBImagePickerController delegate 圖片選擇代理
- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets {
// iOS8 以后,assets 里面的對(duì)象默認(rèn)為PHAsset
NSLog(@"%@", assets);
// 此處默認(rèn)單選
PHAsset *set = assets.firstObject;
// 通過圖片寬高判,這個(gè)是我項(xiàng)目的主要判斷
if ( set.pixelWidth/set.pixelHeight !=2) {
[MBProgressHUD showError:@"您選的不是全景圖片"];
return;
}
// 類型判斷
if (!(set.mediaType == 1 && set.mediaSubtypes == 0)) {
[MBProgressHUD showError:@"您選的不是全景圖片"];
return;
}
// 獲取圖片(獲得UIImage)
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
// 注意:targetSize設(shè)置 PHImageManagerMaximumSize 有可能造成卡頓,原來(lái)為Screen.size
[[PHImageManager defaultManager] requestImageForAsset:set targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
NSLog(@"result==%@ info==%@", result,info);
UIImage *photo = result;
[self.photosArray addObject:photo];
}];
[self dismissViewControllerAnimated:YES completion:nil];
}
// 用戶取消選擇圖片
- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController {
//do something
[self dismissViewControllerAnimated:YES completion:nil];
}
// 點(diǎn)擊預(yù)覽
- (void)didPreviewImageView:(CPImagePreview *)imgView
{
// CPLog(@"控制器點(diǎn)擊預(yù)覽");
CPPreviewPanoController *previewVc = [[CPPreviewPanoController alloc]init];
previewVc.previewImage = imgView.image;
[self.navigationController pushViewController:previewVc animated:YES];
}
最后
好了,此次分享利用PanoramaGL生成360度全景預(yù)覽圖 就到這里,已是凌晨,希望可以幫到你。有問題的小伙伴可以留言,大家一起交流。