CTPanoramaView is a library that displays spherical or cylindrical panoramas with touch or motion based controls.

Overview

CTPanoramaView

CI Status Cocoapods Compatible Carthage compatible Issues

CTPanoramaView is a high-performance library that uses SceneKit to display complete spherical or cylindrical panoramas with touch or motion based controls.

panorama_demo

Requirements

  • iOS 8.0+
  • v1.0 requires Xcode 8.0 and Swift 3.0
  • v1.1 requires XCode 9.0 and Swift 4.0
  • v1.2 requires XCode 10.0 and Swift 4.2
  • v1.3 requires XCode 10.0 and Swift 5.0
  • v1.4 requires XCode 12.0 and Swift 5.0

CTPanoramaView can be used both from Objective-C and Swift code.

Installation

Using Carthage

To install CTPanoramaView using Carthage, add the folowing line into your Cartfile:

1.3 ">
github "scihant/CTPanoramaView" ~> 1.3

Then run the carthage update command to build the framework and drag the built CTPanoramaView.framework into your XCode project.

Using CocoaPods

To install CTPanoramaView using CocoaPods, add the following line into your Podfile:

1.3" ">
pod "CTPanoramaView", "~> 1.3"

Then run the pod install command and use the created workspace to open your project from now on.

Manual Install

Just add the file CTPanoramaView.swift (and CTPieSliceView.swift if you want to use it as the compass view) to your project.

Running the Example project

The example project is located in the Example directory. The framework target is already added as a dependency to it therefore you can run it directly.

Usage

Create an instance of CTPanoramaView either in code or using a Storyboard/Nib.

Then load a panoramic image and set it as the image of the CTPanoramaView instance:

// Create an instance of CTPanoramaView called "panoramaView" somewhere
// ...
let image = UIImage(named: "panoramicImage.png")
panaromaView.image = image

panorama_screenshot

Configuration

Panorama Types

CTPanoramaView supports two types of panoramic images:

  • Spherical panoramas (also called 360 photos)
  • Cylindrical panoramas

All panoramas should be full. Partial panoramas (panoramas with a field of view of less than 360º) are not supported. For a spherical panorama, the image should use equirectangular projection. Cubic format is not supported.

CTPanoramaView will automatically determine whether the given image is a spherical or cylindircal panorama by looking at the aspect ratio of the image. If it is 2:1, then it will assume a spherical panorama. If you want to override this default value, change the value of the panoramaType property after the image is set.

panaromaView.panoramaType = .spherical  // or .cylindrical

Control Methods

CTPanoramaView allows the user to navigate the panorama two different ways. To change the control method, use the controlMethod property.

panaromaView.controlMethod = .touch  // Touch based control
panaromaView.controlMethod = .motion // Accelerometer & gyroscope based control

The default control method is touch based control. You can change the control method on the fly, while the panorama is being displayed on the screen. The visible section will get automatically reset during a control method change.

When using touch based control, you can set the starting angle of the viewer in radians using the startAngle property of CTPanoramaView. This property is ignored in motion based control mode.

Orientation Support

All orientations are supported. Orientation changes are automatically handled. Therefore you don't have to worry about things getting messed up after an orientation change.

Compass

If you want to display a compass that shows the users current field of view, use the compass property. When you set this property to a custom UIView subclass conforming to the CTPanoramaCompass protocol, the view will automatically supplied with rotation and field of view angles whenever one of them changes.

// compassView is a custom view that conforms to the `CTPanoramaCompass` protocol.
panaromaView.compass =  compassView 

The protocol contains only a single method, which is updateUI(rotationAngle:fieldOfViewAngle:). Here, rotationAngle is the amount of rotation around the vertical axis, and fieldOfViewAngle is the horizontal FoV angle of the camera. Both values are in radians.

You can see an example implementation of a compass in the supplied CTPieSliceView class. Add it into your view hierarchy somewhere above your CTPanoramaView instance, and then set it as its compass. You'll see that it shows the current FoV accurately. Here's how CTPieSliceView looks in its default configuration:

compassview

CTPieSliceView has several customizable properties such as sliceColor, outerRingColor and bgColor, all of which can also be modified from the interface builder thanks to its live-rendering support.

Overlay Views

There is also a convenience property named overlayView that can be used to add a custom view that covers the entire panorama view on top. When using touch based controls, it's up to you to make sure that the overlay view does not "consume" the touches it receives so that the CTPanoramaView instance can receive the touch events properly.

How to Contribute

Create a feature branch off the dev branch and then send me a pull request. I don't merge PR's directly to master so please don't make your changes there.

Comments
  • Allow both motion and finger rotation?

    Allow both motion and finger rotation?

    Is it possible to have both rotation methods?

    Or perhaps, an "auto" mode that changes from finger to motion if certain movement is detected?

    opened by cristianoccazinsp 9
  • Replaced main operation queue with user initiated queue

    Replaced main operation queue with user initiated queue

    Hi @scihant , Performing motionManager.startDeviceMotionUpdates on main queue caused very strong lagging on iPhone X. I updated it so it uses a user initiated queue which I think is suitable for this case. From Apple's documentation: "Used for performing work that has been explicitly requested by the user, and for which results must be immediately presented in order to allow for further user interaction."

    opened by fajdof 5
  • Control both

    Control both

    This PR is related to https://github.com/scihant/CTPanoramaView/issues/46

    After hours of testing, I wasn't able to combine both finger and motion rotation values. However, I think this approach can be useful for some (e.g., https://github.com/lightbasenl/react-native-panorama-view). Basically, this new both option starts with motion rotation, but switches to finger rotation if it is used.

    opened by cristianoccazinsp 3
  • Specify a Swift version for Cocoapods

    Specify a Swift version for Cocoapods

    With cocoapods version 1.6.1 I get the following error:

    [!] Unable to determine Swift version for the following pods:

    • CTPanoramaView does not specify a Swift version and none of the targets (targetlist) integrating it have the SWIFT_VERSION attribute set. Please contact the author or set the SWIFT_VERSION attribute in at least one of the targets that integrate this pod.

    Could you please add the "swift version" in the pod declaration?

    opened by lchamp 2
  • Start angle for motion-based panoramas

    Start angle for motion-based panoramas

    This PR provides ability to specify start angle for motion based panoramas as well as touch based. I also would like to apply start angle to sphere panoramas too, but couldn't figure out where should I apply it.

    opened by Sega-Zero 2
  • Added zooming

    Added zooming

    • Added a starting scale var to keep track of the scale when the zooming starts
    • Added a new pinch gesture recognizer for the zoom
    • Added the method handlePinch for the zoom logic
    opened by Ludicrous2k 2
  • Public property for start angle?

    Public property for start angle?

    Is it possible change start angle from 0,0,0 to the center of my spherical picture? I found random picture in google to illustrate it: For example http://paulbourke.net/fun/dragongardens/2.jpg the gates is the most important part of panorama and I want to start viewing from the center of image.

    opened by MirstrKot 2
  • compass rotation angle bug

    compass rotation angle bug

    to rotate compass we use eulerAngles: -cameraNode.eulerAngles.y But it works not in a proper way. The compass always jumps in different directions during rotation.

    opened by IhorKram 1
  • Binding sceneView.backgroundColor with self.backgroundColor

    Binding sceneView.backgroundColor with self.backgroundColor

    Background color is set at initialization. If you initialize the view through xib, then it works fine. But if you create a view programmatically, then it is impossible to set the color during initialization, only after. But if set after, then sceneView will not update its background color

    opened by ravilich86 1
  • Option to use both finger and sensor rotation

    Option to use both finger and sensor rotation

    Follow up of the previously rejected PR.

    I have merged all changes from master, and also dropped the min XCode requirement back to 10 (you don't really need 12) so this library is compatible with react-native.

    I've been using these changes for a while now and the ".both" option is great. Please consider including this in the library.

    opened by cristianoccazinsp 1
  • Allow the image to be rotated independent of the camera

    Allow the image to be rotated independent of the camera

    This would provide a method for rotating the image rather than the camera.

    The benefit of doing this rather than the existing startAngle property is that it works the same regardless of camera control method or panorama type.

    The main difference is that it doesn't change the orientation of the direction indicator. In my projects case, that's a benefit since we are applying a rotation correct for the fact that images start facing backwards using this library

    opened by kingjd2 1
  • Image Remain blank

    Image Remain blank

    Hello ! Before thank you for this work !

    I got a problem , I take my image from url , I create UIImage with Data object , but sometimes , Image remains blank Did this happened to someone ? I mean i maybe failed with the lifecycle or something....

    Thanks a lot !

    opened by clemPerrousset 0
  • Xcode 13/iOS 15 Crash when using CTPanoramaView

    Xcode 13/iOS 15 Crash when using CTPanoramaView

    [MTLTextureDescriptorInternal validateWithDevice:]:1325: failed assertion `Texture Descriptor Validation

    MTLTextureDescriptor has width (8704) greater than the maximum allowed size of 8192.

    This was using an image taken from an Android phone.

    opened by brian-telintelo-kr 0
  • Isn't VR360 just two VR180s (at least for stills)?

    Isn't VR360 just two VR180s (at least for stills)?

    VR180 3D Image Support

    Not so much an issue as it is a question. You say you only support 360 deg FoV angles, but all VR360 cameras that I know of are basically two VR180 cameras pointed away from each other, then rendered side-by-side. That's actually how the Vuze and Insta360 Vue switch between 360 mono and 180 stereo/3D views. You fold the 3D 180 cameras around so they're back-to-back and you get 360 footage.

    As such, couldn't it be as simple as taking the 180 footage then adding a black rectangle for the 'second' 180 to properly show it with your library? i.e. your library would think it's still working with 360, just with a dead camera so half of the 'sphere' would be black.

    If you're talking about the projection mode, then most VR180 cameras use the side-by-side 'circles' for video, but ironically for stills, they use equirectangular projection where the entire frame is filled, just distorted.

    Now if you're speaking not about the projection issues, but the format of Google's VR180, for videos, it's as I said above... It has the two 'circles' on either side. But for stills, they do something a little different. Rather than store the images side-by-side, they only show the left eye and save it as a standard jpg. The view from the right eye is actually encoded and shoved in the metadata of the jpeg as a binary stream (along with some other metadata around lens distance and other projection-related data.) That's why you can open them with any standard Jpeg viewers.

    ...which brings me back to you here. At least for stills in VR180 3D format, you could grab the standard JPEG image, create a double-wide buffer, then render that image in the left side, leave the right side as just black, and treat it like it's a 360 equirectangular projection. Again, when it projects, you'll just see a dead/black half, but that's precisely what one would expect.

    Now if you really wanted to get crazy, you could pull out that second 'right' image and render it in a second buffer, put two of your views side-by-side on the screen, using one buffer for the left and the other for the right, and bam... you now have a 3D VR180 viewer when used with a Cardboard viewer.

    VR180 3D Sampe Images

    Anyway, happy to help experiment with you on this if you want. If you do, to get you started, I'm including a raw VR180 3D JPEG image from the Lenovo Mirage Camera, as well as a second JPEG image where I manually pulled out the right eye and rendered it next to the image from the standard JPEG stream. Using this you may be able to see if you can figure out how to get your library to use VR180, at least in mono. If you do, again, slap a second viewer next to the first with the data from the right eye and congrats... you support VR180 3D still images, which is a start!

    I myself personally like them better than videos because it's a moment frozen in time that you can look around as if you were there. Videos you're at the mercy of what the cameraman does/moves/goes. For instance, whenever I go apartment hunting, I bring the VR180 cam and snap images rather than videos. Then later, I can go back home and 'look around' again using my Quest 2 and Pigasus Viewer (after I extract them to the SBS view as I did here since Pigasus doesn't support the embedded right image. They support tons of projection modes and arrangements. Just none with the embedded data like VR180.) I basically take a photo from each 'corner' of a room, then down hallways and such, and I can virtually 'walk around', seeing everything in 3D and I can really plan things out how I want my furniture to go, etc. It's really great and has rejuvenated my use of the Lenovo Cam because again, videos, unless it's sitting on a tripod, are basically useless, to me anyway.

    Files

    Hallway.vr.jpeg Hallway_LR.jpg

    Hallway.vr.jpeg Hallway_LR.jpg

    opened by MarqueIV 0
  • Image resolution is low

    Image resolution is low

    I'm implementing the panorama view with this specs :

    device : iphone XR image : 4096 x 2048 (JPEG) panorama type : spherical bound size : full screen (828 x 1792)

    and, the quality is very low after implemented.

    what config should i make to make it high resolution as the image? i recognized that the image is zooming-in too much

    please advice. thank you

    opened by johanesgahari 1
  • Add the ability to get an image of the current view through sceneView.snapshot()

    Add the ability to get an image of the current view through sceneView.snapshot()

    For my use case I need to grab an image of the current view, but the sceneView is private and inaccessible. I don't think sceneView needs to be made public, but at least offer new snapshot() method that will give you the current view of the scene. I might submit a PR for this if necessary.

    Thanks

    opened by hardeverick 0
Releases(1.5)
Owner
Salih Cihan Tek
I'm a mobile application developer focused on the iOS platform.
Salih Cihan Tek
A custom image view that implements device motion scrolling

YXTMotionView A custom image view that implements device motion scrolling Installation CocoaPods Add the dependency to your Podfile: platform :ios pod

Hanton Yang 79 Dec 17, 2022
AirPodsMotionAPI - Test Swift's AirPods Motion API in this sample project

AirPods Motion API Overview Swift provides an AirPods motion API that works on s

Pallav Agarwal 47 Dec 9, 2022
Touch ID Plugin (Cordova) for iOS

cordova-plugin-gctouch-id Touch ID Plugin (Cordova) for iOS Author: Giulio Caruso aka rdn Index Description Technical Documentation Screenshots Adding

Giulio Caruso 20 Jan 3, 2022
AsyncImage before iOS 15. Lightweight, pure SwiftUI Image view, that displays an image downloaded from URL, with auxiliary views and local cache.

URLImage URLImage is a SwiftUI view that displays an image downloaded from provided URL. URLImage manages downloading remote image and caching it loca

Dmytro Anokhin 1k Jan 4, 2023
App that Displays the NASA Photo of Day

SpacePod We'll progressively build a small SwiftUI app that displays the NASA ph

Kern Jackson 6 Nov 6, 2022
NASAPictureOfTheDay - An app that displays pictures from the NASA APOD API

NASA Picture of the day This is an app that displays pictures from the NASA APOD

Dhaval Rajani 0 Jan 29, 2022
This mod displays in-world holographic arrows for quest/point of interest navigation, mirroring the dots in the minimap.

This mod displays in-world holographic arrows for quest/point of interest navigation, mirroring the dots in the minimap. They're currently displayed all of the time, but will eventually be configurable.

Jack Humbert 14 Oct 17, 2022
GPU-based media processing library using Metal written in Swift

GPU-based media processing library using Metal written in Swift. Overview MetalAcc is a GPU-Based media processing library that lets you apply GPU-acc

Jiawei Wang 259 Dec 17, 2022
A crop, compression, resize and trimming library for videos, based on AVKit.

VideoKit VideoKit is a high level layer on top of AVKit How it works // With this config, the video will get resized to 1920x1080p, the maximal length

Knoggl 9 Dec 24, 2022
Gifu adds protocol-based, performance-aware animated GIF support to UIKit.

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan). Install Swift Package Manager Add the fo

Reda Lemeden 2.8k Jan 7, 2023
📦 An extension that generates letter-based avatars/placeholders

LetterAvatarKit LetterAvatarKit provides an UIImage extension for generating letter-based avatars/placeholders. There are a few images showing what yo

Victor Peschenkov 215 Dec 21, 2022
A machine learning based emoji image classifier

BQBClassifier ??️ Download From App Store Given that my photo albums are mixed with various emojis that often spoil my good mood, I wrote such an app

Lakr Aream 38 Aug 30, 2022
XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage

XAnimatedImage is a performant animated GIF engine for iOS written in Swift based on FLAnimatedImage. An illustration is shown below: Features Plays m

Khaled Taha 561 Sep 9, 2022
Siri Shortcuts extension for calculating NN-based image hash.

NNHash Siri Shortcuts extension for calculating NN-based image hash. Based on nhcalc.

Yi Xie 3 Aug 9, 2021
An open source iOS framework for GPU-based image and video processing

GPUImage Brad Larson http://www.sunsetlakesoftware.com @bradlarson [email protected] Overview The GPUImage framework is a BSD-licensed iO

Brad Larson 20k Jan 1, 2023
Gallery has a clearer flow based on albums and focuses on the use case of selecting video

Description We all love image pickers, don't we? You may already know of ImagePicker, the all in one solution for capturing pictures and selecting ima

null 1 Sep 14, 2022
A demo of face recognition SwiftUI app on iOS. Based on Vision, OpenCV, Dlib and ResNet.

iOS-FaceRecognizer A demo of face recognition SwiftUI app on iOS, build for iPad. Based on Vision, OpenCV, Dlib and ResNet. Features Add face image an

js_john 11 Aug 20, 2022
A simple mesh viewer for MacOS based on Swift and Metal and using Assimp for loading meshes

Metal Mesh Viewer A simple triangle mesh viewer for MacOS This application is a simple (triangle) mesh viewer that should be capable of rendering even

J. Andreas Bærentzen 0 Dec 13, 2021
EbImagesSwiftUI - SDWebImageSwiftUI - a SwiftUI image loading framework, which based on SDWebImage

SDWebImageSwiftUI What's for SDWebImageSwiftUI is a SwiftUI image loading framew

An Tran 1 Jan 6, 2022