panorama: loosened identification criteria, handle missing parameter
This commit is contained in:
parent
79b6276846
commit
79aefc3aa5
3 changed files with 33 additions and 15 deletions
|
@ -594,14 +594,16 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
val metadata = ImageMetadataReader.readMetadata(input)
|
val metadata = ImageMetadataReader.readMetadata(input)
|
||||||
val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java)
|
val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java)
|
||||||
try {
|
try {
|
||||||
fun getProp(propName: String): Int? = xmpDirs.map { it.xmpMeta.getPropertyInteger(XMP.GPANO_SCHEMA_NS, propName) }.firstOrNull { it != null }
|
fun getIntProp(propName: String): Int? = xmpDirs.map { it.xmpMeta.getPropertyInteger(XMP.GPANO_SCHEMA_NS, propName) }.firstOrNull { it != null }
|
||||||
|
fun getStringProp(propName: String): String? = xmpDirs.map { it.xmpMeta.getPropertyString(XMP.GPANO_SCHEMA_NS, propName) }.firstOrNull { it != null }
|
||||||
val fields: FieldMap = hashMapOf(
|
val fields: FieldMap = hashMapOf(
|
||||||
"croppedAreaLeft" to getProp(XMP.GPANO_CROPPED_AREA_LEFT_PROP_NAME),
|
"croppedAreaLeft" to getIntProp(XMP.GPANO_CROPPED_AREA_LEFT_PROP_NAME),
|
||||||
"croppedAreaTop" to getProp(XMP.GPANO_CROPPED_AREA_TOP_PROP_NAME),
|
"croppedAreaTop" to getIntProp(XMP.GPANO_CROPPED_AREA_TOP_PROP_NAME),
|
||||||
"croppedAreaWidth" to getProp(XMP.GPANO_CROPPED_AREA_WIDTH_PROP_NAME),
|
"croppedAreaWidth" to getIntProp(XMP.GPANO_CROPPED_AREA_WIDTH_PROP_NAME),
|
||||||
"croppedAreaHeight" to getProp(XMP.GPANO_CROPPED_AREA_HEIGHT_PROP_NAME),
|
"croppedAreaHeight" to getIntProp(XMP.GPANO_CROPPED_AREA_HEIGHT_PROP_NAME),
|
||||||
"fullPanoWidth" to getProp(XMP.GPANO_FULL_PANO_WIDTH_PROP_NAME),
|
"fullPanoWidth" to getIntProp(XMP.GPANO_FULL_PANO_WIDTH_PROP_NAME),
|
||||||
"fullPanoHeight" to getProp(XMP.GPANO_FULL_PANO_HEIGHT_PROP_NAME),
|
"fullPanoHeight" to getIntProp(XMP.GPANO_FULL_PANO_HEIGHT_PROP_NAME),
|
||||||
|
"projectionType" to (getStringProp(XMP.GPANO_PROJECTION_TYPE_PROP_NAME) ?: XMP.GPANO_PROJECTION_TYPE_DEFAULT),
|
||||||
)
|
)
|
||||||
result.success(fields)
|
result.success(fields)
|
||||||
return
|
return
|
||||||
|
|
|
@ -54,18 +54,19 @@ object XMP {
|
||||||
const val GPANO_CROPPED_AREA_TOP_PROP_NAME = "GPano:CroppedAreaTopPixels"
|
const val GPANO_CROPPED_AREA_TOP_PROP_NAME = "GPano:CroppedAreaTopPixels"
|
||||||
const val GPANO_FULL_PANO_HEIGHT_PROP_NAME = "GPano:FullPanoHeightPixels"
|
const val GPANO_FULL_PANO_HEIGHT_PROP_NAME = "GPano:FullPanoHeightPixels"
|
||||||
const val GPANO_FULL_PANO_WIDTH_PROP_NAME = "GPano:FullPanoWidthPixels"
|
const val GPANO_FULL_PANO_WIDTH_PROP_NAME = "GPano:FullPanoWidthPixels"
|
||||||
private const val GPANO_PROJECTION_TYPE_PROP_NAME = "GPano:ProjectionType"
|
const val GPANO_PROJECTION_TYPE_PROP_NAME = "GPano:ProjectionType"
|
||||||
|
const val GPANO_PROJECTION_TYPE_DEFAULT = "equirectangular"
|
||||||
|
|
||||||
private const val PMTM_IS_PANO360 = "pmtm:IsPano360"
|
private const val PMTM_IS_PANO360 = "pmtm:IsPano360"
|
||||||
|
|
||||||
|
// `GPano:ProjectionType` is required by spec but it is sometimes missing, assuming default
|
||||||
|
// `GPano:FullPanoHeightPixels` is required by spec but it is sometimes missing (e.g. Samsung Camera app panorama mode)
|
||||||
private val gpanoRequiredProps = listOf(
|
private val gpanoRequiredProps = listOf(
|
||||||
GPANO_CROPPED_AREA_HEIGHT_PROP_NAME,
|
GPANO_CROPPED_AREA_HEIGHT_PROP_NAME,
|
||||||
GPANO_CROPPED_AREA_WIDTH_PROP_NAME,
|
GPANO_CROPPED_AREA_WIDTH_PROP_NAME,
|
||||||
GPANO_CROPPED_AREA_LEFT_PROP_NAME,
|
GPANO_CROPPED_AREA_LEFT_PROP_NAME,
|
||||||
GPANO_CROPPED_AREA_TOP_PROP_NAME,
|
GPANO_CROPPED_AREA_TOP_PROP_NAME,
|
||||||
GPANO_FULL_PANO_HEIGHT_PROP_NAME,
|
|
||||||
GPANO_FULL_PANO_WIDTH_PROP_NAME,
|
GPANO_FULL_PANO_WIDTH_PROP_NAME,
|
||||||
GPANO_PROJECTION_TYPE_PROP_NAME,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
|
|
|
@ -4,24 +4,38 @@ import 'package:flutter/widgets.dart';
|
||||||
class PanoramaInfo {
|
class PanoramaInfo {
|
||||||
final Rect croppedAreaRect;
|
final Rect croppedAreaRect;
|
||||||
final Size fullPanoSize;
|
final Size fullPanoSize;
|
||||||
|
final String projectionType;
|
||||||
|
|
||||||
PanoramaInfo({
|
PanoramaInfo({
|
||||||
this.croppedAreaRect,
|
this.croppedAreaRect,
|
||||||
this.fullPanoSize,
|
this.fullPanoSize,
|
||||||
|
this.projectionType,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory PanoramaInfo.fromMap(Map map) {
|
factory PanoramaInfo.fromMap(Map map) {
|
||||||
final cLeft = map['croppedAreaLeft'] as int;
|
var cLeft = map['croppedAreaLeft'] as int;
|
||||||
final cTop = map['croppedAreaTop'] as int;
|
var cTop = map['croppedAreaTop'] as int;
|
||||||
final cWidth = map['croppedAreaWidth'] as int;
|
final cWidth = map['croppedAreaWidth'] as int;
|
||||||
final cHeight = map['croppedAreaHeight'] as int;
|
final cHeight = map['croppedAreaHeight'] as int;
|
||||||
|
var fWidth = map['fullPanoWidth'] as int;
|
||||||
|
var fHeight = map['fullPanoHeight'] as int;
|
||||||
|
final projectionType = map['projectionType'] as String;
|
||||||
|
|
||||||
|
// handle missing `fullPanoHeight` (e.g. Samsung camera app panorama mode)
|
||||||
|
if (fHeight == null && cWidth != null && cHeight != null) {
|
||||||
|
// assume the cropped area is actually covering 360 degrees horizontally
|
||||||
|
// even when `croppedAreaLeft` is non zero
|
||||||
|
fWidth = cWidth;
|
||||||
|
fHeight = (fWidth / 2).round();
|
||||||
|
cTop = ((fHeight - cHeight) / 2).round();
|
||||||
|
cLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Rect croppedAreaRect;
|
Rect croppedAreaRect;
|
||||||
if (cLeft != null && cTop != null && cWidth != null && cHeight != null) {
|
if (cLeft != null && cTop != null && cWidth != null && cHeight != null) {
|
||||||
croppedAreaRect = Rect.fromLTWH(cLeft.toDouble(), cTop.toDouble(), cWidth.toDouble(), cHeight.toDouble());
|
croppedAreaRect = Rect.fromLTWH(cLeft.toDouble(), cTop.toDouble(), cWidth.toDouble(), cHeight.toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
final fWidth = map['fullPanoWidth'] as int;
|
|
||||||
final fHeight = map['fullPanoHeight'] as int;
|
|
||||||
Size fullPanoSize;
|
Size fullPanoSize;
|
||||||
if (fWidth != null && fHeight != null) {
|
if (fWidth != null && fHeight != null) {
|
||||||
fullPanoSize = Size(fWidth.toDouble(), fHeight.toDouble());
|
fullPanoSize = Size(fWidth.toDouble(), fHeight.toDouble());
|
||||||
|
@ -30,11 +44,12 @@ class PanoramaInfo {
|
||||||
return PanoramaInfo(
|
return PanoramaInfo(
|
||||||
croppedAreaRect: croppedAreaRect,
|
croppedAreaRect: croppedAreaRect,
|
||||||
fullPanoSize: fullPanoSize,
|
fullPanoSize: fullPanoSize,
|
||||||
|
projectionType: projectionType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get hasCroppedArea => croppedAreaRect != null && fullPanoSize != null;
|
bool get hasCroppedArea => croppedAreaRect != null && fullPanoSize != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType#${shortHash(this)}{croppedAreaRect=$croppedAreaRect, fullPanoSize=$fullPanoSize}';
|
String toString() => '$runtimeType#${shortHash(this)}{croppedAreaRect=$croppedAreaRect, fullPanoSize=$fullPanoSize, projectionType=$projectionType}';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue