前言
初做全景項目,涉及到了360度全景展示(也可以是720度的旋轉),查找了很多資料,很多都是用PanoramaGL這個庫實現的,本人也踩了一下坑,下面我簡單的總結一下。
初識PanoramaGL
此處先提供一個可以在Xcode8運行的 Demo (包含PanoramaGL庫)。你下載下來看一下,運行,沒有太大問題,只是第一張圖加載不出。
從Demo可以看出,使用PanoramaGL進行全景圖展示很簡單:
// 在ViewController.m
// #import "PLView.h"
-(void)viewDidLoad
{
[super viewDidLoad];
// 創建全景展示View,設置代理
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. 創建全景圖 (單張)
NSObject<PLIPanorama> *panorama = nil;
panorama = [PLSphericalPanorama panorama];
[(PLSphericalPanorama *)panorama setTexture:[PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"pano_sphere" ofType:@"jpg"]]]];
/* 2. 創建全景圖(多張圖片拼接)
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;
*/
// 設置一個熱點
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 據說能支持4096x2048 的圖片,試了一下貌似不行。進去看了一下源碼,所謂支持,就是基于2048x1024再縮放,然后進圖片分割排布,效果不行。所以,自己生成預覽圖的時候,需將圖片大小轉為2048x1024。
給自己的項目配置PanoramaGL
看著Demo運行的挺好的,但當你把PanoramaGL拖進你的項目,編譯,一大堆錯誤!原因是Demo把不能運行的坑都踩了,這個PanoramaGL庫2011年開始就不再維護了。庫是在MRC環境寫的,因此,直接在現在Xcode 的ARC環境編譯會出錯。
解決以上問題:
在用MRC 環境寫的文件 添加 -fno-objc-arc,
屬于PanoramaGL基本這個庫的文件基本都要添加,但是,不是全部! 注意,文件后綴.c的文件不用添加 -fno-objc-arc
好不容易將這么多文件添加了-fno-objc-arc ,再編譯一下,蒙蔽了,瞬間幾十個錯誤:
解決上面這個問題,有三個解決方案:
解決方案一:
選擇所有導入的.c文件,將屬性的 identity and type 改為Objective-C Source。
解決方案二:
選擇所有導入的.c文件,將.c修改為.m
解決方案三:
將Compile Sources As 改為 Objective-C++。
方案三由于修改所有文件的編譯類型,所有可能會導致其他包括c、c++代碼的提示錯誤,不過都是些的提示異常,按提示修改即可。
改完了,編譯,終于通過。
項目使用實例
先給大家貼一下使用PanoramaGL實現預覽全景圖的控制器代碼吧:
// 此處是push出來的預覽全景圖控制器
// 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];
// 創建預覽
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;
}
本項目選擇圖片使用QBImagePicker
下面展示上一級控制器.m (即選擇手機相冊圖片的控制器)的部分代碼
#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 里面的對象默認為PHAsset
NSLog(@"%@", assets);
// 此處默認單選
PHAsset *set = assets.firstObject;
// 通過圖片寬高判,這個是我項目的主要判斷
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設置 PHImageManagerMaximumSize 有可能造成卡頓,原來為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];
}
// 點擊預覽
- (void)didPreviewImageView:(CPImagePreview *)imgView
{
// CPLog(@"控制器點擊預覽");
CPPreviewPanoController *previewVc = [[CPPreviewPanoController alloc]init];
previewVc.previewImage = imgView.image;
[self.navigationController pushViewController:previewVc animated:YES];
}
最后
好了,此次分享利用PanoramaGL生成360度全景預覽圖 就到這里,已是凌晨,希望可以幫到你。有問題的小伙伴可以留言,大家一起交流。