SC2 Image Thumbnails
Last updated August 12, 2020.
This is a community document based on contributions of informal test results from the theta360.guide independent community. This is not an official RICOH document. For official information, please contact RICOH. You should confirm these community tips with your own tests prior to deployment in a business setting. As these are unofficial tips, the official RICOH THETA API may change unexpectedly and these techniques could stop working.
Problem
Using camera.listFiles does not return image thumbnails even when the maxThumbSize is set to 640. In community tests, the SC2 hangs or freezes when 640 was specified as the maxThumbSize. No thumbnail was returned.
As the thumbnail is usually under 40kB compared to 3.5MB to 4MB for the SC2 image, using the full-size image as the visual tool to manage the images on the camera will slow down your mobile app during network transfer.
Workarounds Overview and Limitations
This article describes two different workarounds. Both techniques will only return a single thumbnail. To get all the thumbnails, you will need to implement a loop and manage async issues for the network and camera.
Workaround #1 - listFiles and _startFileUrl
Quick Point
Grab the URL of the file you want to get the thumbnail for and
then specify it in _startFileUrl
.
Example Request
Example in Dart map.
Map data = {
'name': 'camera.listFiles',
'parameters': {
'fileType': 'image',
'entryCount': 1,
'maxThumbSize': 640,
'_detail': true,
'_startFileUrl':
'http://192.168.1.1/files/thetasc26c21a247d9055838792badc5/100RICOH/R0010129.JPG'
}
Example Response
This is the response from a THETA SC2.
200
{
"name": "camera.listFiles",
"results": {
"entries": [
{
"name": "R0010129.JPG",
"fileUrl": "http://192.168.1.1/files/thetasc26c21a247d9055838792badc5/100RICOH/R0010129.JPG",
"size": 3943866,
"isProcessed": true,
"previewUrl": "",
"dateTimeZone": "2020:08:01 15:07:50-07:00",
"width": 5376,
"height": 2688,
"_thumbSize": 7349,
"thumbnail": "/9j/2wCEAAsICAoIBwsKCQoNDAsNERwSEQ8PESIZGhQcKSQrKigkJyctMkA3LTA9MCcnOEw5PUNFSElIKzZPVU5GVEBHSEUBDA0NEQ8RIRISIUUuJy5FRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRf/EAaIAAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo
...
Example Using the Thumbnail
The thumbnail is a base64 encoded string. Most languages have a library to decode base64 into bytes. You can then display the thumbnail to your mobile app screen or save it to disk. In the following example, the thumbnail is saved to disk.
/// returns base64 encoded string of the thumbnail
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:apitest/pretty_print.dart';
Future<String> getThumb(imageUrl) async {
var url = 'http://192.168.1.1/osc/commands/execute';
Map data = {
'name': 'camera.listFiles',
'parameters': {
'fileType': 'image',
'entryCount': 1,
'_startFileUrl': imageUrl,
'maxThumbSize': 640,
'_detail': true,
}
};
//encode Map to JSON
var body = jsonEncode(data);
var response = await http.post(url,
headers: {"Content-Type": "application/json;charset=utf-8"}, body: body);
print("${response.statusCode}");
prettyPrint("${response.body}");
Map<String, dynamic> imageInfo = jsonDecode(response.body);
String thumb64 = imageInfo['results']['entries'][0]['thumbnail'];
File('thumbnail.jpg').writeAsBytes(base64.decode(thumb64));
return thumb64;
}
Workaround #2 - GET fileUrl with ?type=thumb
You must first get the URL of the file you want to get the thumbnail for.
Once you have the URL, you can get the thumbnail by
adding ?type=thumb
to the end of the URL.
Workaround #2 - Example Request
The example below accepts a single URL as a parameter.
import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
Future<String> getThumb2(imageUrl) async {
print(imageUrl);
var response = await http.get('${imageUrl}?type=thumb',
headers: {"Content-Type": "application/json;charset=utf-8"});
print("${response.statusCode}");
File('thumbnail.jpg').writeAsBytes(response.bodyBytes);
return response.body;
}
Example to get a list of URLs
This example shows how to get the last five image URLs on the camera and return it as a list. You can then iterate through the list and grab the thumbnail for each image.
/// list urls of images on camera
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
var urls = [];
Future<List<dynamic>> listUrls() async {
var url = 'http://192.168.1.1/osc/commands/execute';
Map data = {
'name': 'camera.listFiles',
'parameters': {
'fileType': 'image',
'entryCount': 5,
'maxThumbSize': 0,
'_detail': true,
}
};
//encode Map to JSON
var body = jsonEncode(data);
var response = await http.post(url,
headers: {"Content-Type": "application/json;charset=utf-8"}, body: body);
print("${response.statusCode}");
var entries = await jsonDecode(response.body)["results"]["entries"];
entries.forEach((element) {
urls.add(element["fileUrl"]);
});
print(urls);
return urls;
}
Get All Thumbnails in a Loop
In the next example, I’m loading 29 thumbnails into an array of bytes.
The sequence of actions on my app is:
- create http client object
- open http connection to camera
- grab each thumbnail individually, once per loop. Loop runs 29 times.
- add bytes of thumbnail into array each time through the loop
- close http connection
- return array
Load Array of thumbnails as bytes
import 'dart:async';
import 'package:http/http.dart' as http;
Map<String, String> headers = {
"Content-Type": "application/json;charset=utf-8"
};
Future<List<dynamic>> getAllThumbs(urls) async {
// use httpClient instead of a one-off http.get command to
// keep network connection open
var client = http.Client();
List<dynamic> thumbs = [];
try {
// loop through list of urls
for (var i = 0; i < urls.length; i++) {
var response =
await client.get('${urls[i]}?type=thumb', headers: headers);
print(response.statusCode);
print('loading file ${i + 1}');
thumbs.add(response.bodyBytes);
}
} catch (e) {
print(e);
} finally {
client.close();
}
return thumbs;
}
Write Thumbnails to Local Storage
Once you have the array of thumbnails as bytes, you can display it to your mobile app screen or save the bytes to local storage. The files are JPG images of 320x160px
/// test of receiving thumbnails as an array of bytes
/// and writing thumbnails to local storage
/// intend to use as basis for Flutter app to display
/// thumbnails to mobile app screen
import 'package:apitest/thumbnails/get_all_thumbs.dart';
import 'package:apitest/list_urls.dart';
import 'dart:io';
Future<void> writeAllThumbs() async {
// get thumbs in byte format
try {
var thumbs = await getAllThumbs(await listUrls());
for (var i = 0; i < thumbs.length; i++) {
File('thumbnail-$i.jpg').writeAsBytes(thumbs[i]);
}
} catch (e) {
print(e);
}
}
Summary
There appears to be a bug in the SC2 API that prevents it from returning thumbnails in the listing of listFiles. Additionally, in some cases, the documented method of acquiring the thumbnail may lock the camera.
Developers can acquire the thumbnail with one of two
workarounds. When using listFiles
,
specifying a String for _startFileUrl
will give you a response with
a base64 String that needs to be decoded into bytes. The
bytes can be saved to storage or displayed to the mobile app
screen.
Adding ?type=thumb
to the end of the fileUrl and sending the
URL as a GET HTTP request will give you a binary image
file that you can display to the mobile app screen or save to local
storage.
This tip and many more SC2 developer articles are available on the SC2 Developers Community Site. Markdown to PDF conversion done with Grip.
This is not an official RICOH document. It is produced by an independent community. Please contact RICOH for official information.