diff --git a/doc/how_to_build_win.md b/doc/how_to_build_win.md
index fd29505..08d6ada 100644
--- a/doc/how_to_build_win.md
+++ b/doc/how_to_build_win.md
@@ -70,6 +70,23 @@ Rename the following files:
1. Open `$opentoonz/toonz/build/OpenToonz.sln` and change to `Debug` or `Release` in the top bar.
2. The output will be in the corresponding folder in `$opentoonz/toonz/build/`
+## Building with extended stop motion support for webcams and Canon DSLR cameras.
+You will need three additional libraries.
+ - [OpenCV](https://opencv.org/)
+ - [libjpeg-turbo](https://www.libjpeg-turbo.org/)
+ - The Canon SDK. This requires applying for the Canon developer program and downloading the SDK.
+
+Copy the following folders into the `$opentoonz/thirdparty` folder.
+ - Copy the Header and library folders from the Canon SDK to `$opentoonz/thirdparty/canon`
+ - Make sure that the library is the one from the EDSDK_64 folder.
+ - Copy the lib and include folders from libjpeg-turbo64 into `$opentoonz/thirdparty/libjpeg-turbo64`.
+ - Copy the include folder from opencv2/build into `$opentoonz/thirdparty/opencv2`
+ - Copy the lib folder from opencv2/build/x64/vc15 into `$opentoonz/thirdparty/opencv2`
+
+Check the checkbox in CMake to build with stop motion support.
+
+To run the program with stop motion support, you will need to copy the .dll files from opencv2, libjpeg-turbo and the Canon SDK into the folder where your project is built.
+
## Running the Program
### Setting Up the Program's Path
1. Copy the entire contents of `$opentoonz/toonz/build/Release` to an appropriate folder.
diff --git a/stuff/config/qss/Blue/Blue.qss b/stuff/config/qss/Blue/Blue.qss
index 834f586..3546927 100644
--- a/stuff/config/qss/Blue/Blue.qss
+++ b/stuff/config/qss/Blue/Blue.qss
@@ -151,6 +151,7 @@ QGroupBox {
qproperty-BottomBelowLineColor: #212223;
}
.tab-flat,
+#StopMotionTabBar::tab,
#StyleEditorTabBar::tab,
#PaletteTabBar::tab,
#FxSettingsTabBar::tab {
@@ -161,6 +162,7 @@ QGroupBox {
padding: 3 4 3 4;
}
.tab-flat:hover,
+#StopMotionTabBar::tab:hover,
#StyleEditorTabBar::tab:hover,
#PaletteTabBar::tab:hover,
#FxSettingsTabBar::tab:hover {
@@ -168,6 +170,7 @@ QGroupBox {
color: #94969a;
}
.tab-flat:selected,
+#StopMotionTabBar::tab:selected,
#StyleEditorTabBar::tab:selected,
#PaletteTabBar::tab:selected,
#FxSettingsTabBar::tab:selected {
@@ -176,6 +179,7 @@ QGroupBox {
border-bottom-color: #414345;
}
.tab-flat:only-one,
+#StopMotionTabBar::tab:only-one,
#StyleEditorTabBar::tab:only-one,
#PaletteTabBar::tab:only-one,
#FxSettingsTabBar::tab:only-one {
@@ -1159,6 +1163,29 @@ PencilTestPopup {
font-size: 17px;
}
/* -----------------------------------------------------------------------------
+ Stop Motion Controller
+----------------------------------------------------------------------------- */
+#StopMotionController QScrollArea {
+ margin: 8;
+}
+#StopMotionController QPushButton {
+ margin: 2 1;
+ padding: 0;
+}
+#StopMotionController #TabBarContainer {
+ margin-left: -4;
+}
+#StopMotionController #bottomWidget {
+ border-top: 1 solid #212223;
+ padding: 3 2 8 3;
+}
+#StopMotionController #bottomWidget QPushButton {
+ padding: 3 5;
+}
+#StopMotionTabBar::tab::first {
+ border-left: 1 solid #212223;
+}
+/* -----------------------------------------------------------------------------
Unknowns + Legacy
----------------------------------------------------------------------------- */
#StartupLabel {
diff --git a/stuff/config/qss/Dark/Dark.qss b/stuff/config/qss/Dark/Dark.qss
index 18d74b9..2fc49e3 100644
--- a/stuff/config/qss/Dark/Dark.qss
+++ b/stuff/config/qss/Dark/Dark.qss
@@ -151,6 +151,7 @@ QGroupBox {
qproperty-BottomBelowLineColor: #161616;
}
.tab-flat,
+#StopMotionTabBar::tab,
#StyleEditorTabBar::tab,
#PaletteTabBar::tab,
#FxSettingsTabBar::tab {
@@ -161,6 +162,7 @@ QGroupBox {
padding: 3 4 3 4;
}
.tab-flat:hover,
+#StopMotionTabBar::tab:hover,
#StyleEditorTabBar::tab:hover,
#PaletteTabBar::tab:hover,
#FxSettingsTabBar::tab:hover {
@@ -168,6 +170,7 @@ QGroupBox {
color: #8b8b8b;
}
.tab-flat:selected,
+#StopMotionTabBar::tab:selected,
#StyleEditorTabBar::tab:selected,
#PaletteTabBar::tab:selected,
#FxSettingsTabBar::tab:selected {
@@ -176,6 +179,7 @@ QGroupBox {
border-bottom-color: #303030;
}
.tab-flat:only-one,
+#StopMotionTabBar::tab:only-one,
#StyleEditorTabBar::tab:only-one,
#PaletteTabBar::tab:only-one,
#FxSettingsTabBar::tab:only-one {
@@ -1159,6 +1163,29 @@ PencilTestPopup {
font-size: 17px;
}
/* -----------------------------------------------------------------------------
+ Stop Motion Controller
+----------------------------------------------------------------------------- */
+#StopMotionController QScrollArea {
+ margin: 8;
+}
+#StopMotionController QPushButton {
+ margin: 2 1;
+ padding: 0;
+}
+#StopMotionController #TabBarContainer {
+ margin-left: -4;
+}
+#StopMotionController #bottomWidget {
+ border-top: 1 solid #161616;
+ padding: 3 2 8 3;
+}
+#StopMotionController #bottomWidget QPushButton {
+ padding: 3 5;
+}
+#StopMotionTabBar::tab::first {
+ border-left: 1 solid #161616;
+}
+/* -----------------------------------------------------------------------------
Unknowns + Legacy
----------------------------------------------------------------------------- */
#StartupLabel {
diff --git a/stuff/config/qss/Default/Default.qss b/stuff/config/qss/Default/Default.qss
index a40646d..dc2f370 100644
--- a/stuff/config/qss/Default/Default.qss
+++ b/stuff/config/qss/Default/Default.qss
@@ -151,6 +151,7 @@ QGroupBox {
qproperty-BottomBelowLineColor: #272727;
}
.tab-flat,
+#StopMotionTabBar::tab,
#StyleEditorTabBar::tab,
#PaletteTabBar::tab,
#FxSettingsTabBar::tab {
@@ -161,6 +162,7 @@ QGroupBox {
padding: 3 4 3 4;
}
.tab-flat:hover,
+#StopMotionTabBar::tab:hover,
#StyleEditorTabBar::tab:hover,
#PaletteTabBar::tab:hover,
#FxSettingsTabBar::tab:hover {
@@ -168,6 +170,7 @@ QGroupBox {
color: #a1a1a1;
}
.tab-flat:selected,
+#StopMotionTabBar::tab:selected,
#StyleEditorTabBar::tab:selected,
#PaletteTabBar::tab:selected,
#FxSettingsTabBar::tab:selected {
@@ -176,6 +179,7 @@ QGroupBox {
border-bottom-color: #484848;
}
.tab-flat:only-one,
+#StopMotionTabBar::tab:only-one,
#StyleEditorTabBar::tab:only-one,
#PaletteTabBar::tab:only-one,
#FxSettingsTabBar::tab:only-one {
@@ -1159,6 +1163,29 @@ PencilTestPopup {
font-size: 17px;
}
/* -----------------------------------------------------------------------------
+ Stop Motion Controller
+----------------------------------------------------------------------------- */
+#StopMotionController QScrollArea {
+ margin: 8;
+}
+#StopMotionController QPushButton {
+ margin: 2 1;
+ padding: 0;
+}
+#StopMotionController #TabBarContainer {
+ margin-left: -4;
+}
+#StopMotionController #bottomWidget {
+ border-top: 1 solid #272727;
+ padding: 3 2 8 3;
+}
+#StopMotionController #bottomWidget QPushButton {
+ padding: 3 5;
+}
+#StopMotionTabBar::tab::first {
+ border-left: 1 solid #272727;
+}
+/* -----------------------------------------------------------------------------
Unknowns + Legacy
----------------------------------------------------------------------------- */
#StartupLabel {
diff --git a/stuff/config/qss/Default/less/layouts/misc.less b/stuff/config/qss/Default/less/layouts/misc.less
index d1fb1b9..b22dbc9 100644
--- a/stuff/config/qss/Default/less/layouts/misc.less
+++ b/stuff/config/qss/Default/less/layouts/misc.less
@@ -26,6 +26,44 @@ PencilTestPopup {
}
/* -----------------------------------------------------------------------------
+ Stop Motion Controller
+----------------------------------------------------------------------------- */
+
+#StopMotionController {
+ & QScrollArea {
+ margin: 8;
+ }
+ & QPushButton {
+ // Adds spacing to buttons, but this setting may be temporary
+ margin: 2 1;
+ padding: 0;
+ }
+ & #TabBarContainer {
+ margin-left: -4; // reset left edge margin
+ }
+ & #bottomWidget {
+ border-top: 1 solid @accent;
+ padding: 3 2 8 3;
+ & QPushButton {
+ // override above margin reset
+ padding: 3 5;
+ }
+ }
+}
+
+#StopMotionTabBar {
+ &::tab {
+ &:extend(.tab-flat all);
+ &::first {
+ // add a border to first item on
+ // the left side due to the spacer
+ // coded in the cpp file
+ border-left: 1 solid @accent;
+ }
+ }
+}
+
+/* -----------------------------------------------------------------------------
Unknowns + Legacy
----------------------------------------------------------------------------- */
// below are classes that are unknown and considered legacy
diff --git a/stuff/config/qss/Light/Light.qss b/stuff/config/qss/Light/Light.qss
index 8503827..a3608db 100644
--- a/stuff/config/qss/Light/Light.qss
+++ b/stuff/config/qss/Light/Light.qss
@@ -151,6 +151,7 @@ QGroupBox {
qproperty-BottomBelowLineColor: #404040;
}
.tab-flat,
+#StopMotionTabBar::tab,
#StyleEditorTabBar::tab,
#PaletteTabBar::tab,
#FxSettingsTabBar::tab {
@@ -161,6 +162,7 @@ QGroupBox {
padding: 3 4 3 4;
}
.tab-flat:hover,
+#StopMotionTabBar::tab:hover,
#StyleEditorTabBar::tab:hover,
#PaletteTabBar::tab:hover,
#FxSettingsTabBar::tab:hover {
@@ -168,6 +170,7 @@ QGroupBox {
color: #fff;
}
.tab-flat:selected,
+#StopMotionTabBar::tab:selected,
#StyleEditorTabBar::tab:selected,
#PaletteTabBar::tab:selected,
#FxSettingsTabBar::tab:selected {
@@ -176,6 +179,7 @@ QGroupBox {
border-bottom-color: #808080;
}
.tab-flat:only-one,
+#StopMotionTabBar::tab:only-one,
#StyleEditorTabBar::tab:only-one,
#PaletteTabBar::tab:only-one,
#FxSettingsTabBar::tab:only-one {
@@ -1159,6 +1163,29 @@ PencilTestPopup {
font-size: 17px;
}
/* -----------------------------------------------------------------------------
+ Stop Motion Controller
+----------------------------------------------------------------------------- */
+#StopMotionController QScrollArea {
+ margin: 8;
+}
+#StopMotionController QPushButton {
+ margin: 2 1;
+ padding: 0;
+}
+#StopMotionController #TabBarContainer {
+ margin-left: -4;
+}
+#StopMotionController #bottomWidget {
+ border-top: 1 solid #404040;
+ padding: 3 2 8 3;
+}
+#StopMotionController #bottomWidget QPushButton {
+ padding: 3 5;
+}
+#StopMotionTabBar::tab::first {
+ border-left: 1 solid #404040;
+}
+/* -----------------------------------------------------------------------------
Unknowns + Legacy
----------------------------------------------------------------------------- */
#StartupLabel {
diff --git a/thirdparty/canon/.gitignore b/thirdparty/canon/.gitignore
new file mode 100644
index 0000000..7551faf
--- /dev/null
+++ b/thirdparty/canon/.gitignore
@@ -0,0 +1,2 @@
+Header/*
+library/*
\ No newline at end of file
diff --git a/thirdparty/canon/copy_canon_sdk.txt b/thirdparty/canon/copy_canon_sdk.txt
new file mode 100644
index 0000000..20bfeeb
--- /dev/null
+++ b/thirdparty/canon/copy_canon_sdk.txt
@@ -0,0 +1,2 @@
+Copy the Header and library folders from the Canon SDK to this folder.
+Make sure that the library is the one from the EDSDK_64 folder.
\ No newline at end of file
diff --git a/thirdparty/libjpeg-turbo64/.gitignore b/thirdparty/libjpeg-turbo64/.gitignore
new file mode 100644
index 0000000..0a61909
--- /dev/null
+++ b/thirdparty/libjpeg-turbo64/.gitignore
@@ -0,0 +1,2 @@
+include/*
+lib/*
diff --git a/thirdparty/libjpeg-turbo64/.gitkeep b/thirdparty/libjpeg-turbo64/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/thirdparty/libjpeg-turbo64/.gitkeep
diff --git a/thirdparty/libjpeg-turbo64/copy_libjpeg-turbo64.txt b/thirdparty/libjpeg-turbo64/copy_libjpeg-turbo64.txt
new file mode 100644
index 0000000..d507ae6
--- /dev/null
+++ b/thirdparty/libjpeg-turbo64/copy_libjpeg-turbo64.txt
@@ -0,0 +1 @@
+Copy the lib and include folders from libjpeg-turbo64 into this folder.
\ No newline at end of file
diff --git a/thirdparty/opencv2/.gitignore b/thirdparty/opencv2/.gitignore
new file mode 100644
index 0000000..01d5602
--- /dev/null
+++ b/thirdparty/opencv2/.gitignore
@@ -0,0 +1,2 @@
+lib/*
+include/*
diff --git a/thirdparty/opencv2/.gitkeep b/thirdparty/opencv2/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/thirdparty/opencv2/.gitkeep
diff --git a/thirdparty/opencv2/copy_opencv2.txt b/thirdparty/opencv2/copy_opencv2.txt
new file mode 100644
index 0000000..899d66d
--- /dev/null
+++ b/thirdparty/opencv2/copy_opencv2.txt
@@ -0,0 +1,2 @@
+Copy the include folder from opencv2/build into this folder
+Copy the lib folder from opencv2/build/x64/vc15 into this folder
\ No newline at end of file
diff --git a/toonz/sources/CMakeLists.txt b/toonz/sources/CMakeLists.txt
index 32a5828..76d23d0 100644
--- a/toonz/sources/CMakeLists.txt
+++ b/toonz/sources/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.11)
+cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_BUILD_TYPE_INIT Release)
@@ -101,6 +101,7 @@ endif()
option(WITH_SYSTEM_LZO "Use the system LZO library instead of 'thirdpary'" ${_init_SYSTEM_LZO})
option(WITH_SYSTEM_SUPERLU "Use the system SuperLU library instead of 'thirdpary'" ${_init_SYSTEM_SUPERLU})
+option(WITH_STOPMOTION "Build with Stop Motion features - Requires Canon SDK" OFF)
# avoid using again
option_defaults_clear()
@@ -258,12 +259,27 @@ if(Qt5Core_VERSION VERSION_LESS QT_MINIMUM_VERSION)
endif()
unset(QT_MINIMUM_VERSION)
-if(BUILD_ENV_MSVC)
+if(BUILD_ENV_MSVC AND NOT WITH_STOPMOTION)
+ include_directories(
+ SYSTEM
+ ${SDKROOT}/glut/3.7.6/include
+ ${SDKROOT}/zlib-1.2.8
+ ${SDKROOT}/LibJPEG/jpeg-9
+ )
+ add_definitions(
+ -DGLUT_NO_LIB_PRAGMA
+ )
+endif()
+
+if(BUILD_ENV_MSVC AND WITH_STOPMOTION)
include_directories(
SYSTEM
${SDKROOT}/glut/3.7.6/include
${SDKROOT}/zlib-1.2.8
${SDKROOT}/LibJPEG/jpeg-9
+ ${SDKROOT}/canon/Header
+ ${SDKROOT}/libjpeg-turbo64/include
+ ${SDKROOT}/opencv2/include
)
add_definitions(
-DGLUT_NO_LIB_PRAGMA
@@ -330,6 +346,14 @@ if(BUILD_ENV_MSVC)
set(SUPERLU_LIB ${SDKROOT}/superlu/SuperLU_${MSVC_LIB_VERSION}_${PLATFORM}.lib)
set(OPENBLAS_LIB ${SDKROOT}/openblas/libopenblas_${PLATFORM}.lib)
set(USB_LIB) # unused
+ if (WITH_STOPMOTION)
+ set(CANON_LIB ${SDKROOT}/canon/library/EDSDK.lib)
+ set(TURBOJPEG_LIB ${SDKROOT}/libjpeg-turbo64/lib/turbojpeg.lib)
+ set(OPENCV_LIB
+ optimized ${SDKROOT}/opencv2/lib/opencv_world412.lib
+ debug ${SDKROOT}/opencv2/lib/opencv_world412d.lib
+ )
+ endif()
if(PLATFORM EQUAL 32)
set(QT_LIB ${SDKROOT}/quicktime/QT73SDK/Libraries/QTMLClient.lib)
endif()
diff --git a/toonz/sources/include/toonz/levelproperties.h b/toonz/sources/include/toonz/levelproperties.h
index c6c4531..93ce2f0 100644
--- a/toonz/sources/include/toonz/levelproperties.h
+++ b/toonz/sources/include/toonz/levelproperties.h
@@ -48,11 +48,13 @@ public:
//! adpoted.
bool m_whiteTransp, //!< [default: false] Whether white should be
- //! visualized as transparent.
- m_premultiply; //!< [default: false] Whether level images should
+ //! visualized as transparent.
+ m_premultiply, //!< [default: false] Whether level images should
//! be
- //! premultiplied by Toonz for alpha compositing (because they
- //! are not).
+ //! premultiplied by Toonz for alpha compositing (because they
+ //! are not).
+ m_isStopMotionLevel;
+
public:
LevelOptions(); //!< Constructs with default values.
@@ -220,6 +222,13 @@ ie
}
bool whiteTransp() const { return m_options.m_whiteTransp; }
+ void setIsStopMotion(bool isStopMotion) // Is this level used for Stop Motion
+
+ {
+ m_options.m_isStopMotionLevel = isStopMotion;
+ }
+ bool isStopMotionLevel() const { return m_options.m_isStopMotionLevel; }
+
private:
TPointD m_imageDpi;
diff --git a/toonz/sources/include/toonz/ttileset.h b/toonz/sources/include/toonz/ttileset.h
index c2cefcd..3e64e0c 100644
--- a/toonz/sources/include/toonz/ttileset.h
+++ b/toonz/sources/include/toonz/ttileset.h
@@ -84,7 +84,7 @@ public:
Tile(const TRasterCM32P &ras, const TPoint &p);
~Tile();
QString id() const override {
- return "TileCM" + QString::number((uintptr_t)this);
+ return "TileCM" + QString::number((uintptr_t) this);
}
Tile *clone() const override;
@@ -124,7 +124,7 @@ public:
Tile(const TRasterP &ras, const TPoint &p);
~Tile();
QString id() const override {
- return "TTileSet32::Tile" + QString::number((uintptr_t)this);
+ return "TTileSet32::Tile" + QString::number((uintptr_t) this);
}
Tile *clone() const override;
diff --git a/toonz/sources/stopmotion/stopmotion.cpp b/toonz/sources/stopmotion/stopmotion.cpp
new file mode 100644
index 0000000..3b92539
--- /dev/null
+++ b/toonz/sources/stopmotion/stopmotion.cpp
@@ -0,0 +1,4013 @@
+#include "stopmotion.h"
+
+#ifdef WIN32
+#include
+#include
+#include
+#include
+#pragma comment(lib, "Mfplat.lib")
+#pragma comment(lib, "Mf.lib")
+#pragma comment(lib, "Mfreadwrite.lib")
+#pragma comment(lib, "mfuuid.lib")
+#pragma comment(lib, "shlwapi.lib")
+#endif
+
+// TnzCore includes
+#include "menubarcommandids.h"
+#include "tapp.h"
+#include "tenv.h"
+#include "tsystem.h"
+#include "filebrowsermodel.h"
+#include "penciltestpopup.h"
+#include "tlevel_io.h"
+#include "toutputproperties.h"
+
+#include "toonz/namebuilder.h"
+#include "toonz/preferences.h"
+#include "toonz/tcamera.h"
+#include "toonz/tcolumnhandle.h"
+#include "toonz/tframehandle.h"
+#include "toonz/levelset.h"
+#include "toonz/sceneproperties.h"
+#include "toonz/toonzscene.h"
+#include "toonz/tscenehandle.h"
+#include "toonz/stage.h"
+#include "toonz/txsheethandle.h"
+#include "toonz/txshlevelhandle.h"
+#include "toonz/txshsimplelevel.h"
+#include "toonz/levelproperties.h"
+#include "toonz/tstageobjecttree.h"
+
+#include "toonzqt/menubarcommand.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Connected camera
+TEnv::IntVar StopMotionUseScaledImages("StopMotionUseScaledImages", 0);
+TEnv::IntVar StopMotionOpacity("StopMotionOpacity", 100);
+TEnv::IntVar StopMotionUseDirectShow("StopMotionUseDirectShow", 1);
+TEnv::IntVar StopMotionAlwaysLiveView("StopMotionAlwaysLiveView", 0);
+
+TEnv::IntVar StopMotionBlackCapture("StopMotionBlackCapture", 0);
+TEnv::IntVar StopMotionPlaceOnXSheet("StopMotionPlaceOnXSheet", 1);
+TEnv::IntVar StopMotionReviewTime("StopMotionReviewTime", 1);
+TEnv::IntVar StopMotionUseMjpg("StopMotionUseMjpg", 1);
+TEnv::IntVar StopMotionUseNumpad("StopMotionUseNumpad", 0);
+
+// Connected camera
+TEnv::StringVar StopMotionCameraName("CamCapCameraName", "");
+// Camera resolution
+TEnv::StringVar StopMotionCameraResolution("CamCapCameraResolution", "");
+
+namespace {
+bool l_quitLoop = false;
+
+TPointD getCurrentCameraDpi() {
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimensionD size = camera->getSize();
+ TDimension res = camera->getRes();
+ return TPointD(res.lx / size.lx, res.ly / size.ly);
+}
+
+//-----------------------------------------------------------------------------
+
+bool findCell(TXsheet *xsh, int col, const TXshCell &targetCell,
+ int &bottomRowWithTheSameLevel) {
+ bottomRowWithTheSameLevel = -1;
+ TXshColumnP column = const_cast(xsh)->getColumn(col);
+ if (!column) return false;
+
+ TXshCellColumn *cellColumn = column->getCellColumn();
+ if (!cellColumn) return false;
+
+ int r0, r1;
+ if (!cellColumn->getRange(r0, r1)) return false;
+
+ for (int r = r0; r <= r1; r++) {
+ TXshCell cell = cellColumn->getCell(r);
+ if (cell == targetCell) {
+ bottomRowWithTheSameLevel = r;
+ return true;
+ }
+ if (cell.m_level == targetCell.m_level) bottomRowWithTheSameLevel = r;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+QChar numToLetter(int letterNum) {
+ switch (letterNum) {
+ case 0:
+ return QChar();
+ break;
+ case 1:
+ return 'A';
+ break;
+ case 2:
+ return 'B';
+ break;
+ case 3:
+ return 'C';
+ break;
+ case 4:
+ return 'D';
+ break;
+ case 5:
+ return 'E';
+ break;
+ case 6:
+ return 'F';
+ break;
+ case 7:
+ return 'G';
+ break;
+ case 8:
+ return 'H';
+ break;
+ case 9:
+ return 'I';
+ break;
+ default:
+ return QChar();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+QString convertToFrameWithLetter(int value, int length = -1) {
+ QString str;
+ str.setNum((int)(value / 10));
+ while (str.length() < length) str.push_front("0");
+ QChar letter = numToLetter(value % 10);
+ if (!letter.isNull()) str.append(letter);
+ return str;
+}
+
+//-----------------------------------------------------------------------------
+
+QString fidsToString(const std::vector &fids,
+ bool letterOptionEnabled) {
+ if (fids.empty()) return StopMotion::tr("No", "frame id");
+ QString retStr("");
+ if (letterOptionEnabled) {
+ bool beginBlock = true;
+ for (int f = 0; f < fids.size() - 1; f++) {
+ int num = fids[f].getNumber();
+ int next_num = fids[f + 1].getNumber();
+
+ if (num % 10 == 0 && num + 10 == next_num) {
+ if (beginBlock) {
+ retStr += convertToFrameWithLetter(num) + " - ";
+ beginBlock = false;
+ }
+ } else {
+ retStr += convertToFrameWithLetter(num) + ", ";
+ beginBlock = true;
+ }
+ }
+ retStr += convertToFrameWithLetter(fids.back().getNumber());
+ } else {
+ bool beginBlock = true;
+ for (int f = 0; f < fids.size() - 1; f++) {
+ int num = fids[f].getNumber();
+ int next_num = fids[f + 1].getNumber();
+ if (num + 1 == next_num) {
+ if (beginBlock) {
+ retStr += QString::number(num) + " - ";
+ beginBlock = false;
+ }
+ } else {
+ retStr += QString::number(num) + ", ";
+ beginBlock = true;
+ }
+ }
+ retStr += QString::number(fids.back().getNumber());
+ }
+ return retStr;
+}
+
+//-----------------------------------------------------------------------------
+
+bool getRasterLevelSize(TXshLevel *level, TDimension &dim) {
+ std::vector fids;
+ level->getFids(fids);
+ if (fids.empty()) return false;
+ TXshSimpleLevel *simpleLevel = level->getSimpleLevel();
+ if (!simpleLevel) return false;
+ TRasterImageP rimg = (TRasterImageP)simpleLevel->getFrame(fids[0], false);
+ if (!rimg || rimg->isEmpty()) return false;
+
+ dim = rimg->getRaster()->getSize();
+ return true;
+}
+
+}; // namespace
+
+//=============================================================================
+//=============================================================================
+
+JpgConverter::JpgConverter() {}
+JpgConverter::~JpgConverter() {}
+
+void JpgConverter::setStream(EdsStreamRef stream) { m_stream = stream; }
+
+void JpgConverter::convertFromJpg() {
+ unsigned __int64 mySize = 0;
+ unsigned char *data = NULL;
+ EdsError err = EdsGetPointer(m_stream, (EdsVoid **)&data);
+ err = EdsGetLength(m_stream, &mySize);
+
+ int width, height, pixelFormat;
+ int inSubsamp, inColorspace;
+ tjhandle tjInstance = NULL;
+ unsigned char *imgBuf = NULL;
+ tjInstance = tjInitDecompress();
+ tjDecompressHeader3(tjInstance, data, mySize, &width, &height, &inSubsamp,
+ &inColorspace);
+
+ if (width < 0 || height < 0) {
+ emit(imageReady(false));
+ return;
+ }
+
+ pixelFormat = TJPF_BGRX;
+ imgBuf = (unsigned char *)tjAlloc(width * height * tjPixelSize[pixelFormat]);
+ int flags = 0;
+#ifdef WIN32
+ flags |= TJFLAG_BOTTOMUP;
+#endif
+ int factorsNum;
+ tjscalingfactor scalingFactor = {1, 1};
+ tjscalingfactor *factor = tjGetScalingFactors(&factorsNum);
+ int i = 0;
+ int tempWidth, tempHeight;
+ while (i < factorsNum) {
+ scalingFactor = factor[i];
+ i++;
+ tempWidth = TJSCALED(width, scalingFactor);
+ tempHeight = TJSCALED(height, scalingFactor);
+ }
+ tjDecompress2(tjInstance, data, mySize, imgBuf, width,
+ width * tjPixelSize[pixelFormat], height, pixelFormat, flags);
+
+ m_finalImage = TRaster32P(width, height);
+ m_finalImage->lock();
+ uchar *rawData = m_finalImage->getRawData();
+ memcpy(rawData, imgBuf, width * height * tjPixelSize[pixelFormat]);
+ m_finalImage->unlock();
+
+ tjFree(imgBuf);
+ imgBuf = NULL;
+ tjDestroy(tjInstance);
+ tjInstance = NULL;
+
+ if (m_stream != NULL) {
+ EdsRelease(m_stream);
+ m_stream = NULL;
+ }
+ data = NULL;
+ emit(imageReady(true));
+}
+
+void JpgConverter::run() { convertFromJpg(); }
+
+//-----------------------------------------------------------------------------
+
+StopMotion::StopMotion() {
+ m_opacity = StopMotionOpacity;
+ m_useScaledImages = StopMotionUseScaledImages;
+ buildAvMap();
+ buildIsoMap();
+ buildTvMap();
+ buildModeMap();
+ buildExposureMap();
+ buildWhiteBalanceMap();
+ buildColorTemperatures();
+ buildImageQualityMap();
+ buildPictureStyleMap();
+ m_useDirectShow = StopMotionUseDirectShow;
+ m_useMjpg = StopMotionUseMjpg;
+ m_alwaysLiveView = StopMotionAlwaysLiveView;
+ m_blackCapture = StopMotionBlackCapture;
+ m_placeOnXSheet = StopMotionPlaceOnXSheet;
+ m_reviewTime = StopMotionReviewTime;
+ m_useNumpadShortcuts = StopMotionUseNumpad;
+ m_numpadForStyleSwitching =
+ Preferences::instance()->isUseNumpadForSwitchingStylesEnabled();
+ setUseNumpadShortcuts(m_useNumpadShortcuts);
+ m_turnOnRewind = Preferences::instance()->rewindAfterPlaybackEnabled();
+ m_timer = new QTimer(this);
+ m_reviewTimer = new QTimer(this);
+ m_reviewTimer->setSingleShot(true);
+
+ m_fullScreen1 = new QDialog();
+ m_fullScreen1->setModal(false);
+ m_fullScreen1->setStyleSheet("background-color:black;");
+ m_screenCount = QApplication::desktop()->screenCount();
+ if (m_screenCount > 1) {
+ m_fullScreen2 = new QDialog();
+ m_fullScreen2->setModal(false);
+ m_fullScreen2->setStyleSheet("background-color:black;");
+ if (m_screenCount == 3) {
+ m_fullScreen3 = new QDialog();
+ m_fullScreen3->setModal(false);
+ m_fullScreen3->setStyleSheet("background-color:black;");
+ }
+ }
+
+ TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
+ TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
+ TFrameHandle *frameHandle = TApp::instance()->getCurrentFrame();
+ bool ret = true;
+
+ ret = ret &&
+ connect(xsheetHandle, SIGNAL(xsheetSwitched()), this, SLOT(update()));
+ ret = ret && connect(m_reviewTimer, SIGNAL(timeout()), this,
+ SLOT(onReviewTimeout()));
+ ret = ret && connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
+ ret =
+ ret && connect(this, SIGNAL(newImageReady()), this, SLOT(importImage()));
+ ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this,
+ SLOT(onSceneSwitched()));
+ ret = ret && connect(frameHandle, SIGNAL(isPlayingStatusChanged()), this,
+ SLOT(onPlaybackChanged()));
+ assert(ret);
+
+ ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+
+ setToNextNewLevel();
+ m_filePath = scene->getDefaultLevelPath(OVL_TYPE, m_levelName.toStdWString())
+ .getParentDir()
+ .getQString();
+
+ // set handler for a camera detected
+ initializeCanonSDK();
+ if (!m_error)
+ m_error = EdsSetCameraAddedHandler(StopMotion::handleCameraAddedEvent,
+ (EdsVoid *)this);
+}
+
+//-----------------------------------------------------------------
+
+StopMotion::~StopMotion() {
+ if (m_liveViewStatus != LiveViewClosed) endLiveView();
+ if (m_sessionOpen) closeCameraSession();
+ if (m_camera) releaseCamera();
+ if (m_cameraList != NULL) releaseCameraList();
+ if (m_isSDKLoaded) closeCanonSDK();
+ setUseNumpadShortcuts(false);
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::onSceneSwitched() {
+ TApp *app = TApp::instance();
+ ToonzScene *scene = app->getCurrentScene()->getScene();
+ TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
+ setToNextNewLevel();
+ m_filePath = scene->getDefaultLevelPath(OVL_TYPE, m_levelName.toStdWString())
+ .getParentDir()
+ .getQString();
+ m_frameNumber = 1;
+ m_xSheetFrameNumber = 0;
+
+ TLevelSet *levelSet = scene->getLevelSet();
+ std::vector levels;
+ levelSet->listLevels(levels);
+ int size = levels.size();
+ for (int i = 0; i < size; i++) {
+ TXshLevel *level = levels[i];
+ if (level->getType() == OVL_XSHLEVEL) {
+ TXshSimpleLevel *sl = 0;
+ sl = level->getSimpleLevel();
+ bool isStopMotionLevel = sl->getProperties()->isStopMotionLevel();
+ if (isStopMotionLevel) {
+ m_filePath = sl->getPath().getParentDir().getQString();
+ m_levelName = QString::fromStdWString(sl->getName());
+ m_frameNumber = sl->getFrameCount() + 1;
+ setXSheetFrameNumber(xsh->getFrameCount() + 1);
+ break;
+ }
+ }
+ }
+ emit(levelNameChanged(m_levelName));
+ emit(filePathChanged(m_filePath));
+ emit(frameNumberChanged(m_frameNumber));
+ emit(xSheetFrameNumberChanged(m_xSheetFrameNumber));
+ refreshFrameInfo();
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::onPlaybackChanged() {
+ if (TApp::instance()->getCurrentFrame()->isPlaying() || m_liveViewStatus == 0)
+ return;
+
+ int r0, r1, step;
+ ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+ scene->getProperties()->getPreviewProperties()->getRange(r0, r1, step);
+ if (r1 > -1) return;
+
+ int frame = TApp::instance()->getCurrentFrame()->getFrame();
+ int lastFrame = TApp::instance()->getCurrentFrame()->getMaxFrameIndex();
+ if (frame == 0 || frame == lastFrame) {
+ TApp::instance()->getCurrentFrame()->setFrame(m_xSheetFrameNumber - 1);
+ }
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setOpacity(int opacity) {
+ m_opacity = opacity;
+ StopMotionOpacity = m_opacity;
+ emit(opacityChanged(m_opacity));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::lowerOpacity() {
+ int opacity = round((double)m_opacity / 255.0 * 10.0);
+ opacity *= 10;
+ opacity -= 10;
+ m_opacity = double(opacity) / 100.0 * 255.0;
+ m_opacity = max(0, m_opacity);
+ StopMotionOpacity = m_opacity;
+ emit(opacityChanged(m_opacity));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::raiseOpacity() {
+ int opacity = round((double)m_opacity / 255.0 * 10.0);
+ opacity *= 10;
+ opacity += 10;
+ m_opacity = double(opacity) / 100.0 * 255.0;
+ m_opacity = min(255, m_opacity);
+ StopMotionOpacity = m_opacity;
+ emit(opacityChanged(m_opacity));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setUseScaledImages(bool on) {
+ m_useScaledImages = on;
+ StopMotionUseScaledImages = int(on);
+ emit(scaleFullSizeImagesSignal(on));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setAlwaysLiveView(bool on) {
+ m_alwaysLiveView = on;
+ StopMotionAlwaysLiveView = int(on);
+ emit(liveViewOnAllFramesSignal(on));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setBlackCapture(bool on) {
+ m_blackCapture = on;
+ StopMotionBlackCapture = int(on);
+ emit(blackCaptureSignal(on));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setPlaceOnXSheet(bool on) {
+ m_placeOnXSheet = on;
+ StopMotionPlaceOnXSheet = int(on);
+ emit(placeOnXSheetSignal(on));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setReviewTime(int time) {
+ m_reviewTime = time;
+ StopMotionReviewTime = time;
+ emit(reviewTimeChangedSignal(time));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setUseMjpg(bool on) {
+ m_useMjpg = on;
+ StopMotionUseMjpg = int(on);
+ emit(useMjpgSignal(on));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::jumpToCameraFrame() {
+ TApp::instance()->getCurrentFrame()->setFrame(m_xSheetFrameNumber - 1);
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setUseNumpadShortcuts(bool on) {
+ m_useNumpadShortcuts = on;
+ StopMotionUseNumpad = int(on);
+ emit(useNumpadSignal(on));
+}
+
+void StopMotion::toggleNumpadShortcuts(bool on) {
+ // can't just return if this feature is off
+ // it could have been toggled while the camera was active
+ if (!m_useNumpadShortcuts) on = false;
+ CommandManager *comm = CommandManager::instance();
+
+ if (on) {
+ // if turning it on, get all old shortcuts
+ if (m_numpadForStyleSwitching) {
+ Preferences::instance()->setValue(useNumpadForSwitchingStyles, false);
+ }
+ std::string shortcut;
+ QAction *action;
+ for (int i = 0; i <= 9; i++) {
+ shortcut = QString::number(i).toStdString();
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ m_oldActionMap.insert(
+ std::pair(shortcut, action));
+ action->setShortcut(QKeySequence(""));
+ action = NULL;
+ }
+ }
+ shortcut = "+";
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ m_oldActionMap.insert(
+ std::pair(shortcut, action));
+ action = NULL;
+ }
+ shortcut = "-";
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ m_oldActionMap.insert(
+ std::pair(shortcut, action));
+ action = NULL;
+ }
+ shortcut = "Return";
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ m_oldActionMap.insert(
+ std::pair(shortcut, action));
+ action = NULL;
+ }
+ shortcut = "*";
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ m_oldActionMap.insert(
+ std::pair(shortcut, action));
+ action = NULL;
+ }
+
+ // now set all new shortcuts
+ action = comm->getAction(MI_PrevDrawing);
+ if (action) {
+ action->setShortcut(QKeySequence("1"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_NextDrawing);
+ if (action) {
+ action->setShortcut(QKeySequence("2"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionJumpToCamera);
+ if (action) {
+ action->setShortcut(QKeySequence("3"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_Loop);
+ if (action) {
+ action->setShortcut(QKeySequence("8"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_Play);
+ if (action) {
+ action->setShortcut(QKeySequence("0"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionRaiseOpacity);
+ if (action) {
+ action->setShortcut(QKeySequence("+"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionLowerOpacity);
+ if (action) {
+ action->setShortcut(QKeySequence("-"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionCapture);
+ if (action) {
+ action->setShortcut(QKeySequence("Enter"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionToggleLiveView);
+ if (action) {
+ action->setShortcut(QKeySequence("5"));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionToggleZoom);
+ if (action) {
+ action->setShortcut(QKeySequence("*"));
+ action = NULL;
+ }
+
+ } else {
+ // unset the new shortcuts first
+ QAction *action;
+ action = comm->getAction(MI_PrevDrawing);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_NextDrawing);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionJumpToCamera);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_Loop);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_Play);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionCapture);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionLowerOpacity);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionRaiseOpacity);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionToggleLiveView);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+ action = comm->getAction(MI_StopMotionToggleZoom);
+ if (action) {
+ action->setShortcut(
+ QKeySequence(comm->getShortcutFromAction(action).c_str()));
+ action = NULL;
+ }
+
+ // now put back the old shortcuts
+ auto it = m_oldActionMap.begin();
+ while (it != m_oldActionMap.end()) {
+ it->second->setShortcut(QKeySequence(it->first.c_str()));
+ it++;
+ }
+ if (m_numpadForStyleSwitching) {
+ std::string shortcut;
+ QAction *action;
+ for (int i = 0; i <= 9; i++) {
+ shortcut = QString::number(i).toStdString();
+ action = comm->getActionFromShortcut(shortcut);
+ if (action) {
+ action->setShortcut(QKeySequence(""));
+ action = NULL;
+ }
+ }
+ Preferences::instance()->setValue(useNumpadForSwitchingStyles, true);
+ }
+ }
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setXSheetFrameNumber(int frameNumber) {
+ m_xSheetFrameNumber = frameNumber;
+ loadLineUpImage();
+ emit(xSheetFrameNumberChanged(m_xSheetFrameNumber));
+ TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
+}
+
+//-----------------------------------------------------------------
+
+bool StopMotion::loadLineUpImage() {
+ if (m_liveViewStatus < 1) return false;
+ m_hasLineUpImage = false;
+ // first see if the level exists in the current level set
+ ToonzScene *currentScene = TApp::instance()->getCurrentScene()->getScene();
+ TLevelSet *levelSet = currentScene->getLevelSet();
+
+ std::wstring levelName = m_levelName.toStdWString();
+
+ // level with the same name
+ TXshLevel *level_sameName = levelSet->getLevel(levelName);
+
+ TFilePath levelFp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+
+ // level with the same path
+ TXshLevel *level_samePath = levelSet->getLevel(*(currentScene), levelFp);
+
+ TFilePath actualLevelFp = currentScene->decodeFilePath(levelFp);
+ TXshSimpleLevelP sl;
+ if (level_sameName && level_samePath && level_sameName == level_samePath) {
+ sl = dynamic_cast(level_sameName);
+ bool isRasterLevel = sl && (sl->getType() == OVL_XSHLEVEL);
+ if (!isRasterLevel) {
+ return false;
+ }
+ } else
+ return false;
+
+ // next we need to find the column the level is on
+
+ TApp *app = TApp::instance();
+ TXsheet *xsh = currentScene->getXsheet();
+ int row;
+ if (m_xSheetFrameNumber == 1) {
+ row = 0;
+ } else {
+ row = m_xSheetFrameNumber - 2;
+ }
+ int col = app->getCurrentColumn()->getColumnIndex();
+
+ int foundCol = -1;
+ // most possibly, it's in the current column
+ int rowCheck;
+ findCell(xsh, col, TXshCell(level_sameName, TFrameId(1)), rowCheck);
+ if (rowCheck >= 0) {
+ foundCol = col;
+ } else {
+ // search entire xsheet
+ for (int c = 0; c < xsh->getColumnCount(); c++) {
+ if (c == col) continue;
+ findCell(xsh, c, TXshCell(level_sameName, TFrameId(1)), rowCheck);
+ if (rowCheck >= 0) {
+ foundCol = c;
+ }
+ }
+ }
+ if (rowCheck < 0) return false;
+
+ // note found row represents the last row found that uses
+ // the active level
+
+ TFrameId frameId = xsh->getCell(row, foundCol).getFrameId();
+
+ int frameNumber = frameId.getNumber();
+
+ if (m_usingWebcam) {
+ if (frameNumber > 0) {
+ m_lineUpImage = sl->getFrame(frameId, false)->raster();
+ m_hasLineUpImage = true;
+ return true;
+ } else
+ return false;
+ }
+
+ // now check to see if a file actually exists there
+ TFilePath liveViewFolder = currentScene->decodeFilePath(
+ TFilePath(m_filePath) + TFilePath(levelName + L"_LiveView"));
+ TFilePath liveViewFp = currentScene->decodeFilePath(
+ liveViewFolder + TFilePath(levelName + L"..jpg"));
+ TFilePath liveViewFile(liveViewFp.withFrame(frameNumber));
+ if (TFileStatus(liveViewFile).doesExist()) {
+ if (loadJpg(liveViewFile, m_lineUpImage)) {
+ m_hasLineUpImage = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setFrameNumber(int frameNumber) {
+ m_frameNumber = frameNumber;
+ emit(frameNumberChanged(m_frameNumber));
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::nextFrame() {
+ if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
+ int f = m_frameNumber;
+ if (f % 10 == 0) // next number
+ m_frameNumber = ((int)(f / 10) + 1) * 10;
+ else // next alphabet
+ m_frameNumber = f + 1;
+ } else
+ m_frameNumber = m_frameNumber + 1;
+ emit(frameNumberChanged(m_frameNumber));
+ refreshFrameInfo();
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::lastFrame() {}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::previousFrame() {
+ int f = m_frameNumber;
+ if (f > 1) {
+ if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
+ if (f % 10 == 0) // next number
+ m_frameNumber = ((int)(f / 10) - 1) * 10;
+ else // next alphabet
+ m_frameNumber = f - 1;
+ } else
+ m_frameNumber = f - 1;
+ emit(frameNumberChanged(m_frameNumber));
+ refreshFrameInfo();
+ }
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setLevelName(QString levelName) { m_levelName = levelName; }
+
+//-----------------------------------------------------------------
+
+void StopMotion::nextName() {
+ std::unique_ptr nameCreator(new FlexibleNameCreator());
+ if (!nameCreator->setCurrent(m_levelName.toStdWString())) {
+ setToNextNewLevel();
+ return;
+ }
+
+ std::wstring levelName = nameCreator->getNext();
+ updateLevelNameAndFrame(levelName);
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::previousName() {
+ std::unique_ptr nameCreator(new FlexibleNameCreator());
+
+ std::wstring levelName;
+
+ // if the current level name is non-sequencial, then try to switch the last
+ // sequencial level in the scene.
+ if (!nameCreator->setCurrent(m_levelName.toStdWString())) {
+ TLevelSet *levelSet =
+ TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
+ nameCreator->setCurrent(L"ZZ");
+ for (;;) {
+ levelName = nameCreator->getPrevious();
+ if (levelSet->getLevel(levelName) != 0) break;
+ if (levelName == L"A") {
+ setToNextNewLevel();
+ return;
+ }
+ }
+ } else
+ levelName = nameCreator->getPrevious();
+
+ updateLevelNameAndFrame(levelName);
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setFileType(QString fileType) {
+ m_fileType = fileType;
+ emit(fileTypeChanged(m_fileType));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setFilePath(QString filePath) {
+ m_filePath = filePath;
+
+ ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+ TFilePath saveInPath(filePath.toStdWString());
+ scene->getProperties()->setCameraCaptureSaveInPath(saveInPath);
+ refreshFrameInfo();
+
+ emit(filePathChanged(m_filePath));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setSubsamplingValue(int subsampling) {
+ m_subsampling = subsampling;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::getSubsampling() {
+ ToonzScene *currentScene = TApp::instance()->getCurrentScene()->getScene();
+ TLevelSet *levelSet = currentScene->getLevelSet();
+
+ std::wstring levelName = m_levelName.toStdWString();
+
+ // level with the same name
+ TXshLevel *level_sameName = levelSet->getLevel(levelName);
+
+ TFilePath levelFp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+
+ // level with the same path
+ TXshLevel *level_samePath = levelSet->getLevel(*(currentScene), levelFp);
+
+ TFilePath actualLevelFp = currentScene->decodeFilePath(levelFp);
+
+ if (level_sameName && level_samePath && level_sameName == level_samePath) {
+ TXshSimpleLevelP m_sl;
+ m_sl = dynamic_cast(level_sameName);
+ bool isRasterLevel = m_sl && (m_sl->getType() == OVL_XSHLEVEL);
+ if (isRasterLevel) {
+ int currSubsampling = m_sl->getProperties()->getSubsampling();
+ m_subsampling = currSubsampling;
+ emit(subsamplingChanged(m_subsampling));
+ } else
+ emit(subsamplingChanged(-1));
+ } else
+ emit(subsamplingChanged(-1));
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::update() { getSubsampling(); }
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::setSubsampling() {
+ ToonzScene *currentScene = TApp::instance()->getCurrentScene()->getScene();
+ TLevelSet *levelSet = currentScene->getLevelSet();
+
+ std::wstring levelName = m_levelName.toStdWString();
+
+ // level with the same name
+ TXshLevel *level_sameName = levelSet->getLevel(levelName);
+
+ TFilePath levelFp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+
+ // level with the same path
+ TXshLevel *level_samePath = levelSet->getLevel(*(currentScene), levelFp);
+
+ TFilePath actualLevelFp = currentScene->decodeFilePath(levelFp);
+
+ if (level_sameName && level_samePath && level_sameName == level_samePath) {
+ TXshSimpleLevelP m_sl;
+ m_sl = dynamic_cast(level_sameName);
+ bool isRasterLevel = m_sl && (m_sl->getType() & RASTER_TYPE);
+ if (isRasterLevel) {
+ int currSubsampling = m_sl->getProperties()->getSubsampling();
+ int newSubsampling = m_subsampling;
+ if (currSubsampling != newSubsampling) {
+ m_sl->getProperties()->setSubsampling(newSubsampling);
+ m_sl->invalidateFrames();
+ TApp::instance()->getCurrentScene()->setDirtyFlag(true);
+ TApp::instance()
+ ->getCurrentXsheet()
+ ->getXsheet()
+ ->getStageObjectTree()
+ ->invalidateAll();
+ TApp::instance()->getCurrentLevel()->notifyLevelChange();
+ emit(subsamplingChanged(m_subsampling));
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::onTimeout() {
+ int currentFrame = TApp::instance()->getCurrentFrame()->getFrame();
+ // int destinationFrame = m_xSheetFrameNumber - 1;
+ if (m_liveViewStatus > 0 && m_liveViewStatus < 3 &&
+ !TApp::instance()->getCurrentFrame()->isPlaying()) {
+ if (getAlwaysLiveView() || (currentFrame == m_xSheetFrameNumber - 1)) {
+ if (!m_usingWebcam)
+ downloadEVFData();
+ else
+ getWebcamImage();
+ if (getAlwaysLiveView() && currentFrame != m_xSheetFrameNumber - 1 ||
+ m_pickLiveViewZoom) {
+ m_showLineUpImage = false;
+ } else {
+ m_showLineUpImage = true;
+ }
+ } else if (m_liveViewStatus == 2) {
+ m_liveViewStatus = 3;
+ TApp::instance()->getCurrentScene()->notifySceneChanged();
+ }
+ } else if (m_liveViewStatus == 3 && !m_userCalledPause) {
+ if (getAlwaysLiveView() || (currentFrame == m_xSheetFrameNumber - 1)) {
+ if (!m_usingWebcam)
+ downloadEVFData();
+ else
+ getWebcamImage();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::onReviewTimeout() {
+ if (m_liveViewStatus > 0) {
+ m_liveViewStatus = 2;
+ m_timer->start(40);
+ }
+ TApp::instance()->getCurrentFrame()->setFrame(m_xSheetFrameNumber - 1);
+}
+
+//-----------------------------------------------------------------------------
+
+bool StopMotion::importImage() {
+ if (getBlackCapture()) {
+ m_fullScreen1->hide();
+
+ if (m_screenCount > 1) {
+ m_fullScreen2->hide();
+
+ if (m_screenCount == 3) {
+ m_fullScreen3->hide();
+ }
+ }
+ }
+ if (getReviewTime() > 0) {
+ m_reviewTimer->start(getReviewTime() * 1000);
+ }
+
+ TApp *app = TApp::instance();
+ ToonzScene *scene = app->getCurrentScene()->getScene();
+ TXsheet *xsh = scene->getXsheet();
+
+ std::wstring levelName = m_levelName.toStdWString();
+ if (levelName.empty()) {
+ DVGui::error(
+ tr("No level name specified: please choose a valid level name"));
+ return false;
+ }
+
+ if (m_usingWebcam) {
+ m_newImage = m_liveViewImage;
+ }
+ int frameNumber = m_frameNumber;
+
+ /* create parent directory if it does not exist */
+ TFilePath parentDir = scene->decodeFilePath(TFilePath(m_filePath));
+ TFilePath fullResFolder = scene->decodeFilePath(
+ TFilePath(m_filePath) + TFilePath(levelName + L"_FullRes"));
+ TFilePath liveViewFolder = scene->decodeFilePath(
+ TFilePath(m_filePath) + TFilePath(levelName + L"_LiveView"));
+
+ TFilePath levelFp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+ TFilePath actualLevelFp = scene->decodeFilePath(levelFp);
+
+ TFilePath fullResFp =
+ scene->decodeFilePath(fullResFolder + TFilePath(levelName + L"..jpg"));
+ TFilePath fullResFile(fullResFp.withFrame(frameNumber));
+
+ TFilePath liveViewFp =
+ scene->decodeFilePath(liveViewFolder + TFilePath(levelName + L"..jpg"));
+ TFilePath liveViewFile(liveViewFp.withFrame(frameNumber));
+
+ TFilePath tempFile = parentDir + "temp.jpg";
+
+ TXshSimpleLevel *sl = 0;
+ TXshLevel *level = scene->getLevelSet()->getLevel(levelName);
+ enum State { NEWLEVEL = 0, ADDFRAME, OVERWRITE } state;
+
+ /* if the level already exists in the scene cast */
+ if (level) {
+ /* if the existing level is not a raster level, then return */
+ if (level->getType() != OVL_XSHLEVEL) {
+ DVGui::error(
+ tr("The level name specified is already used: please choose a "
+ "different level name."));
+ return false;
+ }
+ /* if the existing level does not match file path and pixel size, then
+ * return */
+ sl = level->getSimpleLevel();
+ if (scene->decodeFilePath(sl->getPath()) != actualLevelFp) {
+ DVGui::error(
+ tr("The save in path specified does not match with the existing "
+ "level."));
+ return false;
+ }
+ if (sl->getProperties()->getImageRes() !=
+ TDimension(m_newImage->getLx(), m_newImage->getLy())) {
+ DVGui::error(tr(
+ "The captured image size does not match with the existing level."));
+ return false;
+ }
+ /* if the level already have the same frame, then ask if overwrite it */
+ TFilePath frameFp(actualLevelFp.withFrame(frameNumber));
+ if (TFileStatus(frameFp).doesExist()) {
+ QString question =
+ tr("File %1 already exists.\nDo you want to overwrite it?")
+ .arg(toQString(frameFp));
+ int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
+ QObject::tr("Cancel"));
+ if (ret == 0 || ret == 2) return false;
+ state = OVERWRITE;
+ } else
+ state = ADDFRAME;
+ }
+ /* if the level does not exist in the scene cast */
+ else {
+ /* if the file does exist, load it first */
+ if (TSystem::doesExistFileOrLevel(actualLevelFp)) {
+ level = scene->loadLevel(actualLevelFp);
+ if (!level) {
+ DVGui::error(tr("Failed to load %1.").arg(toQString(actualLevelFp)));
+ return false;
+ }
+
+ /* if the loaded level does not match in pixel size, then return */
+ sl = level->getSimpleLevel();
+ if (!sl ||
+ sl->getProperties()->getImageRes() !=
+ TDimension(m_newImage->getLx(), m_newImage->getLy())) {
+ DVGui::error(
+ tr("The captured image size does not match with the existing "
+ "level."));
+ return false;
+ }
+
+ /* confirm overwrite */
+ TFilePath frameFp(actualLevelFp.withFrame(frameNumber));
+ if (TFileStatus(frameFp).doesExist()) {
+ QString question =
+ tr("File %1 already exists.\nDo you want to overwrite it?")
+ .arg(toQString(frameFp));
+ int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
+ QObject::tr("Cancel"));
+ if (ret == 0 || ret == 2) return false;
+ }
+ }
+ /* if the file does not exist, then create a new level */
+ else {
+ TXshLevel *level = scene->createNewLevel(OVL_XSHLEVEL, levelName,
+ TDimension(), 0, levelFp);
+ sl = level->getSimpleLevel();
+ sl->setPath(levelFp, true);
+ sl->getProperties()->setDpiPolicy(LevelProperties::DP_CustomDpi);
+ TPointD dpi;
+ // Right now always set the dpi to scale to the camera width
+ if (Preferences::instance()->getPixelsOnly() && false)
+ dpi = getCurrentCameraDpi();
+ // Compute the dpi so that the image will fit
+ // to the camera frame
+ else {
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimensionD size = camera->getSize();
+ double minimumDpi = std::min(m_newImage->getLx() / size.lx,
+ m_newImage->getLy() / size.ly);
+ dpi = TPointD(minimumDpi, minimumDpi);
+ }
+ sl->getProperties()->setDpi(dpi.x);
+ sl->getProperties()->setImageDpi(dpi);
+ sl->getProperties()->setImageRes(
+ TDimension(m_newImage->getLx(), m_newImage->getLy()));
+ }
+
+ state = NEWLEVEL;
+ getSubsampling();
+ }
+
+ if (!TFileStatus(parentDir).doesExist()) {
+ QString question;
+ question = tr("Folder %1 doesn't exist.\nDo you want to create it?")
+ .arg(toQString(parentDir));
+ int ret = DVGui::MsgBox(question, QObject::tr("Yes"), QObject::tr("No"));
+ if (ret == 0 || ret == 2) return false;
+ try {
+ TSystem::mkDir(parentDir);
+ DvDirModel::instance()->refreshFolder(parentDir.getParentDir());
+ } catch (...) {
+ DVGui::error(tr("Unable to create") + toQString(parentDir));
+ return false;
+ }
+ }
+ if (!m_usingWebcam) {
+ if (!TFileStatus(fullResFolder).doesExist()) {
+ try {
+ TSystem::mkDir(fullResFolder);
+ DvDirModel::instance()->refreshFolder(fullResFolder.getParentDir());
+ } catch (...) {
+ DVGui::error(tr("Unable to create") + toQString(fullResFolder));
+ return false;
+ }
+ }
+ if (!TFileStatus(liveViewFolder).doesExist()) {
+ try {
+ TSystem::mkDir(liveViewFolder);
+ DvDirModel::instance()->refreshFolder(liveViewFolder.getParentDir());
+ } catch (...) {
+ DVGui::error(tr("Unable to create") + toQString(liveViewFolder));
+ return false;
+ }
+ }
+ }
+
+ // move the temp file
+ if (!m_usingWebcam) {
+ if (m_useScaledImages) {
+ TSystem::copyFile(fullResFile, tempFile);
+ TSystem::deleteFile(tempFile);
+ }
+ if (m_hasLineUpImage) {
+ saveJpg(m_lineUpImage, liveViewFile);
+ }
+ }
+
+ TFrameId fid(frameNumber);
+ TPointD levelDpi = sl->getDpi();
+ /* create the raster */
+ TRaster32P raster = m_newImage;
+
+ TRasterImageP ri(raster);
+ ri->setDpi(levelDpi.x, levelDpi.y);
+
+ /* setting the frame */
+ sl->setFrame(fid, ri);
+
+ /* set dirty flag */
+ sl->getProperties()->setDirtyFlag(true);
+ sl->getProperties()->setIsStopMotion(true);
+ sl->setIsReadOnly(true);
+
+ // if (m_saveOnCaptureCB->isChecked()) sl->save();
+ // for now always save. This can be tweaked later
+ sl->save();
+
+ /* placement in xsheet */
+ if (!getPlaceOnXSheet()) {
+ postImportProcess();
+ return true;
+ }
+ int row = m_xSheetFrameNumber - 1;
+ int col = app->getCurrentColumn()->getColumnIndex();
+
+ // if the level is newly created or imported, then insert a new column
+ if (state == NEWLEVEL) {
+ if (!xsh->isColumnEmpty(col)) {
+ col += 1;
+ xsh->insertColumn(col);
+ }
+ xsh->insertCells(row, col);
+ xsh->setCell(row, col, TXshCell(sl, fid));
+ app->getCurrentColumn()->setColumnIndex(col);
+ if (getReviewTime() == 0) app->getCurrentFrame()->setFrame(row + 1);
+ m_xSheetFrameNumber = row + 2;
+ emit(xSheetFrameNumberChanged(m_xSheetFrameNumber));
+ postImportProcess();
+ // if (m_newImage->getLx() > 2000) {
+ // m_subsampling = 4;
+ // setSubsampling();
+ //}
+ return true;
+ }
+
+ // state == OVERWRITE, ADDFRAME
+
+ // if the same cell is already in the column, then just replace the content
+ // and do not set a new cell
+ int foundCol, foundRow = -1;
+ // most possibly, it's in the current column
+ int rowCheck;
+ if (findCell(xsh, col, TXshCell(sl, fid), rowCheck)) {
+ postImportProcess();
+ return true;
+ }
+ if (rowCheck >= 0) {
+ foundRow = rowCheck;
+ foundCol = col;
+ }
+ // search entire xsheet
+ for (int c = 0; c < xsh->getColumnCount(); c++) {
+ if (c == col) continue;
+ if (findCell(xsh, c, TXshCell(sl, fid), rowCheck)) {
+ postImportProcess();
+ return true;
+ }
+ if (rowCheck >= 0) {
+ foundRow = rowCheck;
+ foundCol = c;
+ }
+ }
+
+ // note found row represents the last row found that uses
+ // the active level
+
+ // if there is a column containing the same level
+ if (foundRow >= 0) {
+ // put the cell at the bottom
+ xsh->insertCells(row, foundCol);
+ xsh->setCell(row, foundCol, TXshCell(sl, fid));
+ app->getCurrentColumn()->setColumnIndex(foundCol);
+ if (getReviewTime() == 0) app->getCurrentFrame()->setFrame(row + 1);
+ m_xSheetFrameNumber = row + 2;
+ emit(xSheetFrameNumberChanged(m_xSheetFrameNumber));
+ }
+ // if the level is registered in the scene, but is not placed in the xsheet,
+ // then insert a new column
+ else {
+ if (!xsh->isColumnEmpty(col)) {
+ col += 1;
+ xsh->insertColumn(col);
+ }
+ xsh->setCell(row, col, TXshCell(sl, fid));
+ app->getCurrentColumn()->setColumnIndex(col);
+ if (getReviewTime() == 0) app->getCurrentFrame()->setFrame(row + 1);
+ m_xSheetFrameNumber = row + 2;
+ emit(xSheetFrameNumberChanged(m_xSheetFrameNumber));
+ }
+ postImportProcess();
+ return true;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::captureImage() {
+ if (!m_usingWebcam && !m_sessionOpen) {
+ DVGui::warning("Please start live view before capturing an image.");
+ return;
+ }
+ if (m_usingWebcam) {
+ if (!m_hasLiveViewImage) {
+ DVGui::warning("Cannot capture webcam image unless live view is active.");
+ return;
+ }
+ if (getReviewTime() > 0) {
+ m_timer->stop();
+ if (m_liveViewStatus > 0) {
+ m_liveViewStatus = 3;
+ }
+ }
+ m_lineUpImage = m_liveViewImage;
+ m_hasLineUpImage = true;
+ emit(newLiveViewImageReady());
+ importImage();
+ return;
+ }
+ if (getBlackCapture()) {
+ m_fullScreen1->showFullScreen();
+ m_fullScreen1->setGeometry(QApplication::desktop()->screenGeometry(0));
+ if (m_screenCount > 1) {
+ m_fullScreen2->showFullScreen();
+ m_fullScreen2->setGeometry(QApplication::desktop()->screenGeometry(1));
+
+ if (m_screenCount == 3) {
+ m_fullScreen3->showFullScreen();
+ m_fullScreen3->setGeometry(QApplication::desktop()->screenGeometry(2));
+ }
+ }
+ // this allows the full screen qdialogs to go full screen before
+ // taking a photo
+ qApp->processEvents(QEventLoop::AllEvents, 1500);
+ }
+
+ if (getReviewTime() > 0) {
+ m_timer->stop();
+ }
+
+ if (m_liveViewStatus > 0) {
+ m_liveViewStatus = 3;
+ }
+
+ if (m_hasLiveViewImage) {
+ m_lineUpImage = m_liveViewImage;
+ m_hasLineUpImage = true;
+ emit(newLiveViewImageReady());
+ }
+
+ TApp *app = TApp::instance();
+ ToonzScene *scene = app->getCurrentScene()->getScene();
+
+ int frameNumber = m_frameNumber;
+ std::wstring levelName = m_levelName.toStdWString();
+
+ TFilePath parentDir = scene->decodeFilePath(TFilePath(m_filePath));
+ TFilePath tempFile = parentDir + "temp.jpg";
+
+ if (!TFileStatus(parentDir).doesExist()) {
+ TSystem::mkDir(parentDir);
+ }
+ m_tempFile = tempFile.getQString();
+ takePicture();
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::saveJpg(TRaster32P image, TFilePath path) {
+ unsigned char *jpegBuf = NULL; /* Dynamically allocate the JPEG buffer */
+ unsigned long jpegSize = 0;
+ int pixelFormat = TJPF_BGRX;
+ int outQual = 95;
+ int subSamp = TJSAMP_411;
+ bool success = false;
+ tjhandle tjInstance;
+
+ int width = image->getLx();
+ int height = image->getLy();
+ int flags = 0;
+#ifdef WIN32
+ flags |= TJFLAG_BOTTOMUP;
+#endif
+
+ image->lock();
+ uchar *rawData = image->getRawData();
+ if ((tjInstance = tjInitCompress()) != NULL) {
+ if (tjCompress2(tjInstance, rawData, width, 0, height, pixelFormat,
+ &jpegBuf, &jpegSize, subSamp, outQual, flags) >= 0) {
+ success = true;
+ }
+ }
+ image->unlock();
+ tjDestroy(tjInstance);
+ tjInstance = NULL;
+
+ if (success) {
+ /* Write the JPEG image to disk. */
+ QFile fullImage(path.getQString());
+ fullImage.open(QIODevice::WriteOnly);
+ QDataStream dataStream(&fullImage);
+ dataStream.writeRawData((const char *)jpegBuf, jpegSize);
+ fullImage.close();
+ }
+ tjFree(jpegBuf);
+ jpegBuf = NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+bool StopMotion::loadJpg(TFilePath path, TRaster32P &image) {
+ long size;
+ int inSubsamp, inColorspace, width, height;
+ unsigned long jpegSize;
+ unsigned char *jpegBuf;
+ FILE *jpegFile;
+ QString qPath = path.getQString();
+ QByteArray ba = qPath.toLocal8Bit();
+ const char *c_path = ba.data();
+ bool success = true;
+ tjhandle tjInstance;
+
+ /* Read the JPEG file into memory. */
+ if ((jpegFile = fopen(c_path, "rb")) == NULL) success = false;
+ if (success && fseek(jpegFile, 0, SEEK_END) < 0 ||
+ ((size = ftell(jpegFile)) < 0) || fseek(jpegFile, 0, SEEK_SET) < 0)
+ success = false;
+ if (success && size == 0) success = false;
+ jpegSize = (unsigned long)size;
+ if (success && (jpegBuf = (unsigned char *)tjAlloc(jpegSize)) == NULL)
+ success = false;
+ if (success && fread(jpegBuf, jpegSize, 1, jpegFile) < 1) success = false;
+ fclose(jpegFile);
+ jpegFile = NULL;
+
+ if (success && (tjInstance = tjInitDecompress()) == NULL) success = false;
+
+ if (success &&
+ tjDecompressHeader3(tjInstance, jpegBuf, jpegSize, &width, &height,
+ &inSubsamp, &inColorspace) < 0)
+ success = false;
+
+ int pixelFormat = TJPF_BGRX;
+ unsigned char *imgBuf = NULL;
+ if (success &&
+ (imgBuf = tjAlloc(width * height * tjPixelSize[pixelFormat])) == NULL)
+ success = false;
+
+ int flags = 0;
+#ifdef WIN32
+ flags |= TJFLAG_BOTTOMUP;
+#endif
+ if (success &&
+ tjDecompress2(tjInstance, jpegBuf, jpegSize, imgBuf, width, 0, height,
+ pixelFormat, flags) < 0)
+ success = false;
+ tjFree(jpegBuf);
+ jpegBuf = NULL;
+ tjDestroy(tjInstance);
+ tjInstance = NULL;
+
+ image = TRaster32P(width, height);
+ image->lock();
+ uchar *rawData = image->getRawData();
+ memcpy(rawData, imgBuf, width * height * tjPixelSize[pixelFormat]);
+ image->unlock();
+
+ tjFree(imgBuf);
+ imgBuf = NULL;
+
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::postImportProcess() {
+ if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) {
+ int f = m_frameNumber;
+ if (f % 10 == 0) // next number
+ m_frameNumber = ((int)(f / 10) + 1) * 10;
+ else // next alphabet
+ m_frameNumber = f + 1;
+ } else
+ m_frameNumber += 1;
+ emit(frameNumberChanged(m_frameNumber));
+ /* notify */
+ refreshFrameInfo();
+ TApp::instance()->getCurrentScene()->notifySceneChanged();
+ TApp::instance()->getCurrentScene()->notifyCastChange();
+ TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
+}
+
+//-----------------------------------------------------------------------------
+
+// Refresh information that how many & which frames are saved for the current
+// level
+void StopMotion::refreshFrameInfo() {
+ if ((!m_sessionOpen && m_liveViewStatus < 2) && !m_usingWebcam) {
+ m_frameInfoText = "";
+ return;
+ }
+
+ QString tooltipStr, labelStr;
+ enum InfoType { NEW = 0, ADD, OVERWRITE, WARNING } infoType(WARNING);
+
+ static QColor infoColors[4] = {Qt::cyan, Qt::green, Qt::yellow, Qt::red};
+
+ ToonzScene *currentScene = TApp::instance()->getCurrentScene()->getScene();
+ TLevelSet *levelSet = currentScene->getLevelSet();
+
+ std::wstring levelName = m_levelName.toStdWString();
+ int frameNumber = m_frameNumber;
+
+ TDimension stopMotionRes;
+ bool checkRes = true;
+ if (m_usingWebcam)
+ stopMotionRes = m_liveViewImageDimensions;
+
+ else if (m_useScaledImages || !getCurrentImageQuality().contains("Large")) {
+ stopMotionRes = m_proxyImageDimensions;
+ if (m_proxyImageDimensions == TDimension(0, 0)) {
+ checkRes = false;
+ }
+ } else
+ stopMotionRes = m_fullImageDimensions;
+
+ bool letterOptionEnabled =
+ Preferences::instance()->isShowFrameNumberWithLettersEnabled();
+
+ // level with the same name
+ TXshLevel *level_sameName = levelSet->getLevel(levelName);
+
+ TFilePath levelFp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+
+ // level with the same path
+ TXshLevel *level_samePath = levelSet->getLevel(*(currentScene), levelFp);
+
+ TFilePath actualLevelFp = currentScene->decodeFilePath(levelFp);
+
+ // level existence
+ bool levelExist = TSystem::doesExistFileOrLevel(actualLevelFp);
+
+ // frame existence
+ TFilePath frameFp(actualLevelFp.withFrame(frameNumber));
+ bool frameExist = false;
+ if (levelExist) frameExist = TFileStatus(frameFp).doesExist();
+
+ // reset acceptable camera size
+ m_allowedCameraSize = QSize();
+
+ // ### CASE 1 ###
+ // If there is no same level registered in the scene cast
+ if (!level_sameName && !level_samePath) {
+ // If there is a level in the file system
+ if (levelExist) {
+ TLevelReaderP lr;
+ TLevelP level_p;
+ try {
+ lr = TLevelReaderP(actualLevelFp);
+ } catch (...) {
+ // TODO: output something
+ m_frameInfoText = tr("UNDEFINED WARNING");
+ return;
+ }
+ if (!lr) {
+ // TODO: output something
+ m_frameInfoText = tr("UNDEFINED WARNING");
+ return;
+ }
+ try {
+ level_p = lr->loadInfo();
+ } catch (...) {
+ // TODO: output something
+ m_frameInfoText = tr("UNDEFINED WARNING");
+ return;
+ }
+ if (!level_p) {
+ // TODO: output something
+ m_frameInfoText = tr("UNDEFINED WARNING");
+ return;
+ }
+ int frameCount = level_p->getFrameCount();
+ TLevel::Iterator it = level_p->begin();
+ std::vector fids;
+ for (int i = 0; it != level_p->end(); ++it, ++i)
+ fids.push_back(it->first);
+
+ tooltipStr +=
+ tr("The level is not registered in the scene, but exists in the file "
+ "system.");
+
+ // check resolution
+ const TImageInfo *ii;
+ try {
+ ii = lr->getImageInfo(fids[0]);
+ } catch (...) {
+ // TODO: output something
+ m_frameInfoText = tr("UNDEFINED WARNING");
+ return;
+ }
+ TDimension dim(ii->m_lx, ii->m_ly);
+ // if the saved images has not the same resolution as the current camera
+ // resolution
+ if (checkRes && m_hasLiveViewImage && stopMotionRes != dim) {
+ tooltipStr += tr("\nWARNING : Image size mismatch. The saved image "
+ "size is %1 x %2.")
+ .arg(dim.lx)
+ .arg(dim.ly);
+ labelStr += tr("WARNING ");
+ infoType = WARNING;
+ }
+ // if the resolutions are matched
+ {
+ if (frameCount == 1)
+ tooltipStr += tr("\nFrame %1 exists.")
+ .arg(fidsToString(fids, letterOptionEnabled));
+ else
+ tooltipStr += tr("\nFrames %1 exist.")
+ .arg(fidsToString(fids, letterOptionEnabled));
+ // if the frame exists, then it will be overwritten
+ if (frameExist) {
+ labelStr += tr("OVERWRITE 1 of");
+ infoType = OVERWRITE;
+ } else {
+ labelStr += tr("ADD to");
+ infoType = ADD;
+ }
+ if (frameCount == 1)
+ labelStr += tr(" %1 frame").arg(frameCount);
+ else
+ labelStr += tr(" %1 frames").arg(frameCount);
+ }
+ m_allowedCameraSize = QSize(dim.lx, dim.ly);
+ }
+ // If no level exists in the file system, then it will be a new level
+ else {
+ tooltipStr += tr("The level will be newly created.");
+ labelStr += tr("NEW");
+ infoType = NEW;
+ }
+ }
+ // ### CASE 2 ###
+ // If there is already the level registered in the scene cast
+ else if (level_sameName && level_samePath &&
+ level_sameName == level_samePath) {
+ tooltipStr += tr("The level is already registered in the scene.");
+ if (!levelExist) tooltipStr += tr("\nNOTE : The level is not saved.");
+
+ std::vector fids;
+ level_sameName->getFids(fids);
+
+ // check resolution
+ TDimension dim;
+ bool ret = getRasterLevelSize(level_sameName, dim);
+ if (!ret) {
+ tooltipStr +=
+ tr("\nWARNING : Failed to get image size of the existing level %1.")
+ .arg(QString::fromStdWString(levelName));
+ labelStr += tr("WARNING ");
+ infoType = WARNING;
+ }
+ // if the saved images has not the same resolution as the current camera
+ // resolution
+ else if (checkRes && m_hasLiveViewImage && stopMotionRes != dim) {
+ tooltipStr += tr("\nWARNING : Image size mismatch. The existing level "
+ "size is %1 x %2.")
+ .arg(dim.lx)
+ .arg(dim.ly);
+ labelStr += tr("WARNING ");
+ infoType = WARNING;
+ }
+ // if the resolutions are matched
+ {
+ int frameCount = fids.size();
+ if (fids.size() == 1)
+ tooltipStr += tr("\nFrame %1 exists.")
+ .arg(fidsToString(fids, letterOptionEnabled));
+ else
+ tooltipStr += tr("\nFrames %1 exist.")
+ .arg(fidsToString(fids, letterOptionEnabled));
+ // Check if the target frame already exist in the level
+ bool hasFrame = false;
+ for (int f = 0; f < frameCount; f++) {
+ if (fids.at(f).getNumber() == frameNumber) {
+ hasFrame = true;
+ break;
+ }
+ }
+ // If there is already the frame then it will be overwritten
+ if (hasFrame) {
+ labelStr += tr("OVERWRITE 1 of");
+ infoType = OVERWRITE;
+ }
+ // Or, the frame will be added to the level
+ else {
+ labelStr += tr("ADD to");
+ infoType = ADD;
+ }
+ if (frameCount == 1)
+ labelStr += tr(" %1 frame").arg(frameCount);
+ else
+ labelStr += tr(" %1 frames").arg(frameCount);
+ }
+ m_allowedCameraSize = QSize(dim.lx, dim.ly);
+ }
+ // ### CASE 3 ###
+ // If there are some conflicts with the existing level.
+ else {
+ if (level_sameName) {
+ TFilePath anotherPath = level_sameName->getPath();
+ tooltipStr +=
+ tr("WARNING : Level name conflicts. There already is a level %1 in the scene with the path\
+ \n %2.")
+ .arg(QString::fromStdWString(levelName))
+ .arg(toQString(anotherPath));
+ // check resolution
+ TDimension dim;
+ bool ret = getRasterLevelSize(level_sameName, dim);
+ if (ret && checkRes && m_hasLiveViewImage && stopMotionRes != dim)
+ tooltipStr += tr("\nWARNING : Image size mismatch. The size of level "
+ "with the same name is is %1 x %2.")
+ .arg(dim.lx)
+ .arg(dim.ly);
+ m_allowedCameraSize = QSize(dim.lx, dim.ly);
+ }
+ if (level_samePath) {
+ std::wstring anotherName = level_samePath->getName();
+ if (!tooltipStr.isEmpty()) tooltipStr += QString("\n");
+ tooltipStr +=
+ tr("WARNING : Level path conflicts. There already is a level with the path %1\
+ \n in the scene with the name %2.")
+ .arg(toQString(levelFp))
+ .arg(QString::fromStdWString(anotherName));
+ // check resolution
+ TDimension dim;
+ bool ret = getRasterLevelSize(level_samePath, dim);
+ if (ret && checkRes && m_hasLiveViewImage && stopMotionRes != dim)
+ tooltipStr += tr("\nWARNING : Image size mismatch. The size of level "
+ "with the same path is %1 x %2.")
+ .arg(dim.lx)
+ .arg(dim.ly);
+ m_allowedCameraSize = QSize(dim.lx, dim.ly);
+ }
+ labelStr += tr("WARNING");
+ infoType = WARNING;
+ }
+
+ QColor infoColor = infoColors[(int)infoType];
+ m_infoColorName = infoColor.name();
+ m_frameInfoText = labelStr;
+ m_frameInfoToolTip = tooltipStr;
+ emit(frameInfoTextChanged(m_frameInfoText));
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::updateLevelNameAndFrame(std::wstring levelName) {
+ if (levelName != m_levelName.toStdWString()) {
+ m_levelName = QString::fromStdWString(levelName);
+ loadLineUpImage();
+ }
+ emit(levelNameChanged(m_levelName));
+ // m_previousLevelButton->setDisabled(levelName == L"A");
+
+ // set the start frame 10 if the option in preferences
+ // "Show ABC Appendix to the Frame Number in Xsheet Cell" is active.
+ // (frame 10 is displayed as "1" with this option)
+ bool withLetter =
+ Preferences::instance()->isShowFrameNumberWithLettersEnabled();
+
+ TLevelSet *levelSet =
+ TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
+ TXshLevel *level_p = levelSet->getLevel(levelName);
+ int startFrame;
+ if (!level_p) {
+ startFrame = withLetter ? 10 : 1;
+ } else {
+ std::vector fids;
+ level_p->getFids(fids);
+ if (fids.empty()) {
+ startFrame = withLetter ? 10 : 1;
+ } else {
+ int lastNum = fids.back().getNumber();
+ startFrame = withLetter ? ((int)(lastNum / 10) + 1) * 10 : lastNum + 1;
+ }
+ }
+ m_frameNumber = startFrame;
+ emit(frameNumberChanged(startFrame));
+ refreshFrameInfo();
+ getSubsampling();
+}
+
+//-----------------------------------------------------------------------------
+
+void StopMotion::setToNextNewLevel() {
+ const std::unique_ptr nameBuilder(NameBuilder::getBuilder(L""));
+
+ TLevelSet *levelSet =
+ TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
+ ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
+ std::wstring levelName = L"";
+
+ // Select a different unique level name in case it already exists (either in
+ // scene or on disk)
+ TFilePath fp;
+ TFilePath actualFp;
+ for (;;) {
+ levelName = nameBuilder->getNext();
+
+ if (levelSet->getLevel(levelName) != 0) continue;
+
+ fp = TFilePath(m_filePath) +
+ TFilePath(levelName + L".." + m_fileType.toStdWString());
+ actualFp = scene->decodeFilePath(fp);
+
+ if (TSystem::doesExistFileOrLevel(actualFp)) {
+ continue;
+ }
+
+ break;
+ }
+
+ updateLevelNameAndFrame(levelName);
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::refreshCameraList() { emit(updateCameraList()); }
+
+//-----------------------------------------------------------------
+
+void StopMotion::changeCameras(int index) {
+ QList cameras = QCameraInfo::availableCameras();
+
+ // if selected the non-connected state, then disconnect the current camera
+ if (index == 0) {
+ m_active = false;
+ m_webcamDeviceName = QString();
+ m_webcamDescription = QString();
+ m_webcamIndex = -1;
+ m_proxyDpi = TPointD(0.0, 0.0);
+ m_proxyImageDimensions = TDimension(0, 0);
+
+ if (m_sessionOpen || m_usingWebcam) {
+ if (m_liveViewStatus > 0) {
+ endLiveView();
+ }
+ closeCameraSession();
+ m_usingWebcam = false;
+ }
+
+ setTEnvCameraName("");
+
+ emit(newCameraSelected(index, false));
+ toggleNumpadShortcuts(false);
+ return;
+ }
+
+ // There is a "Select Camera" as the first index
+ index -= 1;
+ m_active = true;
+
+ // Check if its a webcam or DSLR
+ // Webcams are listed first, so see if one of them is selected
+ if (index > cameras.size() - 1) {
+ m_usingWebcam = false;
+ } else {
+ m_usingWebcam = true;
+ m_webcamIndex = index;
+ }
+
+ // in case the camera is not changed
+ if (m_usingWebcam) {
+ if (cameras.at(index).deviceName() == m_webcamDeviceName) {
+ return;
+ }
+
+ if (m_sessionOpen) {
+ if (m_liveViewStatus > 0) {
+ endLiveView();
+ closeCameraSession();
+ }
+ }
+
+ setWebcam(new QCamera(cameras.at(index)));
+ m_webcamDeviceName = cameras.at(index).deviceName();
+ m_webcamDescription = cameras.at(index).description();
+
+#ifdef MACOSX
+ // this line is needed only in macosx
+ m_stopMotion->getWebcam()->setViewfinder(m_dummyViewFinder);
+#endif
+
+ // loading new camera
+ getWebcam()->load();
+
+ m_webcamResolutions.clear();
+
+ m_webcamResolutions = getWebcam()->supportedViewfinderResolutions();
+ int sizeCount = m_webcamResolutions.count();
+
+ int width;
+ int height;
+ for (int s = 0; s < m_webcamResolutions.size(); s++) {
+ width = m_webcamResolutions.at(s).width();
+ height = m_webcamResolutions.at(s).height();
+ }
+
+ getWebcam()->unload();
+
+ setWebcamResolution(
+ QString(QString::number(width) + " x " + QString::number(height)));
+ setTEnvCameraName(m_webcamDescription.toStdString());
+ emit(newCameraSelected(index + 1, true));
+ emit(webcamResolutionsChanged());
+ emit(newWebcamResolutionSelected(sizeCount - 1));
+
+ } else {
+ m_webcamDeviceName = QString();
+ m_webcamDescription = QString();
+ m_webcamIndex = -1;
+ openCameraSession();
+ setTEnvCameraName(getCameraName());
+ emit(newCameraSelected(index + 1, false));
+ }
+ if (m_useNumpadShortcuts) toggleNumpadShortcuts(true);
+ m_liveViewDpi = TPointD(0.0, 0.0);
+ refreshFrameInfo();
+}
+
+//-----------------------------------------------------------------
+
+QList StopMotion::getWebcams() {
+ m_webcams.clear();
+ m_webcams = QCameraInfo::availableCameras();
+ return m_webcams;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setWebcam(QCamera *camera) { m_webcam = camera; }
+
+//-----------------------------------------------------------------
+
+bool StopMotion::translateIndex(int index) {
+ // We are using Qt to get the camera info and supported resolutions, but
+ // we are using OpenCV to actually get the images.
+ // The camera index from OpenCV and from Qt don't always agree,
+ // So this checks the name against the correct index.
+ m_webcamIndex = index;
+
+#ifdef WIN32
+
+// Thanks to:
+// https://elcharolin.wordpress.com/2017/08/28/webcam-capture-with-the-media-foundation-sdk/
+// for the webcam enumeration here
+
+#define CLEAN_ATTRIBUTES() \
+ if (attributes) { \
+ attributes->Release(); \
+ attributes = NULL; \
+ } \
+ for (DWORD i = 0; i < count; i++) { \
+ if (&devices[i]) { \
+ devices[i]->Release(); \
+ devices[i] = NULL; \
+ } \
+ } \
+ CoTaskMemFree(devices); \
+ return hr;
+
+ HRESULT hr = S_OK;
+
+ // this is important!!
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+
+ UINT32 count = 0;
+ IMFAttributes *attributes = NULL;
+ IMFActivate **devices = NULL;
+
+ if (FAILED(hr)) {
+ CLEAN_ATTRIBUTES()
+ }
+ // Create an attribute store to specify enumeration parameters.
+ hr = MFCreateAttributes(&attributes, 1);
+
+ if (FAILED(hr)) {
+ CLEAN_ATTRIBUTES()
+ }
+
+ // The attribute to be requested is devices that can capture video
+ hr = attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
+ MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
+ if (FAILED(hr)) {
+ CLEAN_ATTRIBUTES()
+ }
+ // Enummerate the video capture devices
+ hr = MFEnumDeviceSources(attributes, &devices, &count);
+
+ if (FAILED(hr)) {
+ CLEAN_ATTRIBUTES()
+ }
+ // if there are any available devices
+ if (count > 0) {
+ WCHAR *nameString = NULL;
+ // Get the human-friendly name of the device
+ UINT32 cchName;
+
+ for (int i = 0; i < count; i++) {
+ hr = devices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
+ &nameString, &cchName);
+ std::string desc = m_webcamDescription.toStdString();
+ if (nameString == m_webcamDescription.toStdWString()) {
+ m_webcamIndex = i;
+ break;
+ }
+ // devices[0]->ShutdownObject();
+ }
+
+ CoTaskMemFree(nameString);
+ }
+ // clean
+ CLEAN_ATTRIBUTES()
+#else
+ return true;
+#endif
+}
+
+//-----------------------------------------------------------------
+
+bool StopMotion::initWebcam(int index) {
+ if (!m_useDirectShow) {
+ // the webcam order obtained from Qt isn't always the same order as
+ // the one obtained from OpenCV without DirectShow
+ translateIndex(index);
+ m_cvWebcam.open(m_webcamIndex);
+ } else {
+ m_webcamIndex = index;
+ m_cvWebcam.open(m_webcamIndex, cv::CAP_DSHOW);
+ }
+ if (m_cvWebcam.isOpened() == false) {
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::releaseWebcam() {
+ m_cvWebcam.release();
+ m_liveViewStatus = 0;
+ emit(liveViewStopped());
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setWebcamResolution(QString resolution) {
+ m_cvWebcam.release();
+
+ // resolution is written in the itemText with the format " x
+ // " (e.g. "800 x 600")
+ QStringList texts = resolution.split(' ');
+ // the splited text must be "" "x" and ""
+ if (texts.size() != 3) return;
+ int tempStatus = m_liveViewStatus;
+ m_liveViewStatus = 0;
+ bool startTimer = false;
+ if (m_timer->isActive()) {
+ m_timer->stop();
+ startTimer = true;
+ }
+ qApp->processEvents(QEventLoop::AllEvents, 1000);
+
+ m_webcamWidth = texts[0].toInt();
+ m_webcamHeight = texts[2].toInt();
+
+ m_liveViewDpi = TPointD(0.0, 0.0);
+ m_liveViewStatus = tempStatus;
+ if (startTimer) m_timer->start(40);
+
+ // update env
+ setTEnvCameraResolution(resolution.toStdString());
+
+ refreshFrameInfo();
+
+ int index = m_webcamResolutions.indexOf(QSize(m_webcamWidth, m_webcamHeight));
+ emit(newWebcamResolutionSelected(index));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::getWebcamImage() {
+ bool error = false;
+ cv::Mat imgOriginal;
+ cv::Mat imgCorrected;
+
+ if (m_cvWebcam.isOpened() == false) {
+ initWebcam(m_webcamIndex);
+ // mjpg is used by many webcams
+ // opencv runs very slow on some webcams without it.
+ if (m_useMjpg) {
+ m_cvWebcam.set(cv::CAP_PROP_FOURCC,
+ cv::VideoWriter::fourcc('m', 'j', 'p', 'g'));
+ m_cvWebcam.set(cv::CAP_PROP_FOURCC,
+ cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
+ }
+ m_cvWebcam.set(3, m_webcamWidth);
+ m_cvWebcam.set(4, m_webcamHeight);
+ if (!m_cvWebcam.isOpened()) {
+ m_hasLiveViewImage = false;
+ error = true;
+ }
+ }
+
+ bool blnFrameReadSuccessfully =
+ m_cvWebcam.read(imgOriginal); // get next frame
+
+ if (!blnFrameReadSuccessfully ||
+ imgOriginal.empty()) { // if frame not read successfully
+ std::cout << "error: frame not read from webcam\n";
+ error = true; // print error message to std out
+ }
+
+ if (!error) {
+ cv::cvtColor(imgOriginal, imgCorrected, cv::COLOR_BGR2BGRA);
+ cv::flip(imgCorrected, imgCorrected, 0);
+ int width = m_cvWebcam.get(3);
+ int height = m_cvWebcam.get(4);
+ int size = imgCorrected.total() * imgCorrected.elemSize();
+
+ m_liveViewImage = TRaster32P(width, height);
+ m_liveViewImage->lock();
+ uchar *imgBuf = imgCorrected.data;
+ uchar *rawData = m_liveViewImage->getRawData();
+ memcpy(rawData, imgBuf, size);
+ m_liveViewImage->unlock();
+ m_hasLiveViewImage = true;
+ m_liveViewStatus = 2;
+ if (m_hasLiveViewImage &&
+ (m_liveViewDpi.x == 0.0 || m_liveViewImageDimensions.lx == 0)) {
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimensionD size = camera->getSize();
+ m_liveViewImageDimensions =
+ TDimension(m_liveViewImage->getLx(), m_liveViewImage->getLy());
+ double minimumDpi = std::min(m_liveViewImageDimensions.lx / size.lx,
+ m_liveViewImageDimensions.ly / size.ly);
+ m_liveViewDpi = TPointD(minimumDpi, minimumDpi);
+
+ m_fullImageDimensions = m_liveViewImageDimensions;
+
+ m_fullImageDpi = m_liveViewDpi;
+
+ emit(newDimensions());
+ }
+
+ emit(newLiveViewImageReady());
+ } else
+ m_hasLiveViewImage = false;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::setUseDirectShow(int state) {
+ m_useDirectShow = state;
+ StopMotionUseDirectShow = state;
+ emit(useDirectShowSignal(state));
+}
+
+//-----------------------------------------------------------------
+
+bool StopMotion::toggleLiveView() {
+ if ((m_sessionOpen || m_usingWebcam) && m_liveViewStatus == 0) {
+ m_liveViewDpi = TPointD(0.0, 0.0);
+ m_liveViewImageDimensions = TDimension(0, 0);
+ if (!m_usingWebcam) {
+ startLiveView();
+ } else
+ m_liveViewStatus = 1;
+ loadLineUpImage();
+ m_timer->start(40);
+ emit(liveViewChanged(true));
+ Preferences::instance()->setValue(rewindAfterPlayback, false);
+ TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
+ return true;
+ } else if ((m_sessionOpen || m_usingWebcam) && m_liveViewStatus > 0) {
+ if (!m_usingWebcam)
+ endLiveView();
+ else
+ releaseWebcam();
+ m_timer->stop();
+ emit(liveViewChanged(false));
+ if (m_turnOnRewind) {
+ Preferences::instance()->setValue(rewindAfterPlayback, true);
+ }
+ TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
+ return false;
+ } else {
+ DVGui::warning(tr("No camera selected."));
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::pauseLiveView() {
+ if (m_liveViewStatus == 2) {
+ m_liveViewStatus = 3;
+ m_userCalledPause = true;
+ emit(liveViewStopped());
+ } else if (m_liveViewStatus == 3) {
+ m_liveViewStatus = 2;
+ m_userCalledPause = false;
+ }
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::initializeCanonSDK() {
+ m_error = EdsInitializeSDK();
+ if (m_error == EDS_ERR_OK) {
+ m_isSDKLoaded = true;
+ }
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+EdsCameraListRef StopMotion::getCameraList() {
+ if (!m_isSDKLoaded) initializeCanonSDK();
+ if (m_isSDKLoaded) {
+ m_error = EdsGetCameraList(&m_cameraList);
+ }
+ return m_cameraList;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::releaseCameraList() {
+ if (m_cameraList != NULL) m_error = EdsRelease(m_cameraList);
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+int StopMotion::getCameraCount() {
+ if (m_cameraList == NULL) {
+ getCameraList();
+ }
+ if (m_cameraList != NULL) {
+ m_error = EdsGetChildCount(m_cameraList, &m_count);
+ if (m_count == 0) {
+ m_error = EDS_ERR_DEVICE_NOT_FOUND;
+ m_sessionOpen = false;
+ m_liveViewStatus = 0;
+ }
+ return m_count;
+ } else
+ return -1;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getCamera(int index) {
+ if (m_count == 0) {
+ m_error = EDS_ERR_DEVICE_NOT_FOUND;
+ }
+ if (m_count > 0) {
+ m_error = EdsGetChildAtIndex(m_cameraList, index, &m_camera);
+ }
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::releaseCamera() {
+ if (m_camera != NULL) {
+ m_error = EdsRelease(m_camera);
+ }
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::cameraAdded() {
+ if (!m_active) refreshCameraList();
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::closeCanonSDK() {
+ if (m_isSDKLoaded) {
+ EdsTerminateSDK();
+ }
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::openCameraSession() {
+ if (m_camera != NULL) {
+ m_error = EdsOpenSession(m_camera);
+ if (m_error == EDS_ERR_OK) m_sessionOpen = true;
+ }
+ m_error =
+ EdsSetObjectEventHandler(m_camera, kEdsObjectEvent_All,
+ StopMotion::handleObjectEvent, (EdsVoid *)this);
+
+ m_error = EdsSetPropertyEventHandler(m_camera, kEdsPropertyEvent_All,
+ StopMotion::handlePropertyEvent,
+ (EdsVoid *)this);
+
+ m_error = EdsSetCameraStateEventHandler(m_camera, kEdsStateEvent_All,
+ StopMotion::handleStateEvent,
+ (EdsVoid *)this);
+
+ // We can't handle raw images yet, so make sure we are getting jpgs
+ if (getCurrentImageQuality().contains("RAW"))
+ setImageQuality("Large Fine Jpeg");
+
+ EdsUInt32 saveto = kEdsSaveTo_Host;
+ m_error = EdsSetPropertyData(m_camera, kEdsPropID_SaveTo, 0,
+ sizeof(EdsUInt32), &saveto);
+ EdsCapacity newCapacity = {0x7FFFFFFF, 0x1000, 1};
+ m_error = EdsSetCapacity(m_camera, newCapacity);
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::closeCameraSession() {
+ if (m_camera != NULL) {
+ m_error = EdsCloseSession(m_camera);
+ m_sessionOpen = false;
+ }
+ return m_error;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::refreshOptions() {
+ getAvailableShutterSpeeds();
+ getAvailableIso();
+ getAvailableApertures();
+ getAvailableExposureCompensations();
+ getAvailableWhiteBalances();
+ buildColorTemperatures();
+ getAvailableImageQualities();
+ getAvailablePictureStyles();
+}
+
+//-----------------------------------------------------------------
+
+std::string StopMotion::getCameraName() {
+ EdsChar name[EDS_MAX_NAME];
+ EdsError err = EDS_ERR_OK;
+ EdsDataType dataType;
+ EdsUInt32 dataSize;
+ m_error = EdsGetPropertySize(m_camera, kEdsPropID_ProductName, 0, &dataType,
+ &dataSize);
+
+ if (m_error == EDS_ERR_OK) {
+ m_error =
+ EdsGetPropertyData(m_camera, kEdsPropID_ProductName, 0, dataSize, name);
+ }
+ m_cameraName = name;
+ return m_cameraName;
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getMode() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType modeType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_AEMode, 0, &modeType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_AEMode, 0, sizeof(size), &data);
+
+ return QString::fromStdString(m_modeMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableIso() {
+ EdsPropertyDesc *IsoDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_isoOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_ISOSpeed, IsoDesc);
+ int count = IsoDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_isoOptions.push_back(
+ QString::fromStdString(m_isoMap[IsoDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete IsoDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableShutterSpeeds() {
+ EdsPropertyDesc *TvDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_shutterSpeedOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_Tv, TvDesc);
+ int count = TvDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_shutterSpeedOptions.push_back(
+ QString::fromStdString(m_tvMap[TvDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete TvDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableApertures() {
+ EdsPropertyDesc *AvDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_apertureOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_Av, AvDesc);
+ int count = AvDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_apertureOptions.push_back(
+ QString::fromStdString(m_avMap[AvDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete AvDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableExposureCompensations() {
+ EdsPropertyDesc *exposureDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_exposureOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_ExposureCompensation,
+ exposureDesc);
+ int count = exposureDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_exposureOptions.push_back(
+ QString::fromStdString(m_exposureMap[exposureDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete exposureDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableWhiteBalances() {
+ EdsPropertyDesc *whiteBalanceDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_whiteBalanceOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_WhiteBalance, whiteBalanceDesc);
+ int count = whiteBalanceDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_whiteBalanceOptions.push_back(QString::fromStdString(
+ m_whiteBalanceMap[whiteBalanceDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete whiteBalanceDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailableImageQualities() {
+ EdsPropertyDesc *imageQualityDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_imageQualityOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_ImageQuality, imageQualityDesc);
+ int count = imageQualityDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ QString quality = QString::fromStdString(
+ m_imageQualityMap[imageQualityDesc->propDesc[i]]);
+ if (!quality.contains("RAW")) {
+ m_imageQualityOptions.push_back(quality);
+ }
+ i++;
+ }
+ }
+ delete imageQualityDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::getAvailablePictureStyles() {
+ EdsPropertyDesc *pictureStyleDesc = new EdsPropertyDesc;
+ EdsError err = EDS_ERR_OK;
+ m_pictureStyleOptions.clear();
+
+ err = EdsGetPropertyDesc(m_camera, kEdsPropID_PictureStyle, pictureStyleDesc);
+ int count = pictureStyleDesc->numElements;
+ if (count > 0) {
+ int i = 0;
+ while (i < count) {
+ m_pictureStyleOptions.push_back(QString::fromStdString(
+ m_pictureStyleMap[pictureStyleDesc->propDesc[i]]));
+ i++;
+ }
+ }
+ delete pictureStyleDesc;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildColorTemperatures() {
+ m_colorTempOptions.clear();
+ int i = 2800;
+ while (i <= 10000) {
+ m_colorTempOptions.push_back(QString::number(i));
+ i += 100;
+ }
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentShutterSpeed() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType tvType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_Tv, 0, &tvType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_Tv, 0, sizeof(size), &data);
+
+ return QString::fromStdString(m_tvMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentIso() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType isoType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_ISOSpeed, 0, &isoType, &size);
+ err =
+ EdsGetPropertyData(m_camera, kEdsPropID_ISOSpeed, 0, sizeof(size), &data);
+
+ return QString::fromStdString(m_isoMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentAperture() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType avType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_Av, 0, &avType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_Av, 0, sizeof(size), &data);
+
+ return QString::fromStdString(m_avMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentExposureCompensation() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType exposureType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_ExposureCompensation, 0,
+ &exposureType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_ExposureCompensation, 0,
+ sizeof(size), &data);
+
+ return QString::fromStdString(m_exposureMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentWhiteBalance() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType whiteBalanceType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_WhiteBalance, 0,
+ &whiteBalanceType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_WhiteBalance, 0, sizeof(size),
+ &data);
+ std::string wbString = m_whiteBalanceMap[data];
+ return QString::fromStdString(m_whiteBalanceMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentImageQuality() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType imageQualityType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_ImageQuality, 0,
+ &imageQualityType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_ImageQuality, 0, sizeof(size),
+ &data);
+ std::string wbString = m_imageQualityMap[data];
+ return QString::fromStdString(m_imageQualityMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentPictureStyle() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType pictureStyleType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_PictureStyle, 0,
+ &pictureStyleType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_PictureStyle, 0, sizeof(size),
+ &data);
+ std::string wbString = m_pictureStyleMap[data];
+ return QString::fromStdString(m_pictureStyleMap[data]);
+}
+
+//-----------------------------------------------------------------
+
+QString StopMotion::getCurrentColorTemperature() {
+ EdsError err = EDS_ERR_OK;
+ EdsDataType colorTempType;
+ EdsUInt32 size;
+ EdsUInt32 data;
+
+ err = EdsGetPropertySize(m_camera, kEdsPropID_ColorTemperature, 0,
+ &colorTempType, &size);
+ err = EdsGetPropertyData(m_camera, kEdsPropID_ColorTemperature, 0,
+ sizeof(size), &data);
+
+ return QString::number(data);
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setShutterSpeed(QString shutterSpeed) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_tvMap.begin();
+ while (it != m_tvMap.end()) {
+ if (it->second == shutterSpeed.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Tv, 0, sizeof(value), &value);
+ emit(shutterSpeedChangedSignal(shutterSpeed));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setIso(QString iso) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_isoMap.begin();
+ while (it != m_isoMap.end()) {
+ if (it->second == iso.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_ISOSpeed, 0, sizeof(value),
+ &value);
+ emit(isoChangedSignal(iso));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setAperture(QString aperture) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_avMap.begin();
+ while (it != m_avMap.end()) {
+ if (it->second == aperture.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Av, 0, sizeof(value), &value);
+ emit(apertureChangedSignal(aperture));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setExposureCompensation(QString exposure) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_exposureMap.begin();
+ while (it != m_exposureMap.end()) {
+ if (it->second == exposure.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_ExposureCompensation, 0,
+ sizeof(value), &value);
+ emit(exposureChangedSignal(exposure));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setWhiteBalance(QString whiteBalance) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_whiteBalanceMap.begin();
+ while (it != m_whiteBalanceMap.end()) {
+ if (it->second == whiteBalance.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_WhiteBalance, 0, sizeof(value),
+ &value);
+ emit(whiteBalanceChangedSignal(whiteBalance));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setImageQuality(QString quality) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_imageQualityMap.begin();
+ while (it != m_imageQualityMap.end()) {
+ if (it->second == quality.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_ImageQuality, 0, sizeof(value),
+ &value);
+ emit(imageQualityChangedSignal(quality));
+ m_proxyImageDimensions = TDimension(0, 0);
+ m_proxyDpi = TPointD(0.0, 0.0);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setPictureStyle(QString style) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ auto it = m_pictureStyleMap.begin();
+ while (it != m_pictureStyleMap.end()) {
+ if (it->second == style.toStdString()) {
+ value = it->first;
+ break;
+ }
+ it++;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_PictureStyle, 0, sizeof(value),
+ &value);
+ err = EdsSetPropertyData(m_camera, kEdsPropID_PictureStyle, 0, sizeof(value),
+ &value);
+ emit(pictureStyleChangedSignal(style));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setColorTemperature(QString temp) {
+ EdsError err = EDS_ERR_OK;
+ EdsUInt32 value;
+ value = temp.toInt();
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_ColorTemperature, 0,
+ sizeof(value), &value);
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Evf_ColorTemperature, 0,
+ sizeof(value), &value);
+ emit(colorTemperatureChangedSignal(temp));
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::downloadImage(EdsBaseRef object) {
+ EdsError err = EDS_ERR_OK;
+ EdsStreamRef stream = NULL;
+ EdsDirectoryItemInfo dirItemInfo;
+
+ err = EdsGetDirectoryItemInfo(object, &dirItemInfo);
+ err = EdsCreateMemoryStream(0, &stream);
+ err = EdsDownload(object, dirItemInfo.size, stream);
+ EdsDownloadComplete(object);
+
+ // tj code
+
+ unsigned __int64 mySize = 0;
+ unsigned char *data = NULL;
+ err = EdsGetPointer(stream, (EdsVoid **)&data);
+ err = EdsGetLength(stream, &mySize);
+
+ int width, height, pixelFormat;
+ // long size;
+ int inSubsamp, inColorspace;
+ // unsigned long jpegSize;
+ tjhandle tjInstance = NULL;
+ unsigned char *imgBuf = NULL;
+ tjInstance = tjInitDecompress();
+ tjDecompressHeader3(tjInstance, data, mySize, &width, &height, &inSubsamp,
+ &inColorspace);
+
+ pixelFormat = TJPF_BGRX;
+ imgBuf = (unsigned char *)tjAlloc(width * height * tjPixelSize[pixelFormat]);
+ int flags = 0;
+#ifdef WIN32
+ flags |= TJFLAG_BOTTOMUP;
+#endif
+ int tempWidth, tempHeight;
+
+ if (m_useScaledImages) {
+ int factorsNum;
+ tjscalingfactor scalingFactor = {1, 1};
+ tjscalingfactor *factor = tjGetScalingFactors(&factorsNum);
+ int intRatio = (float)width / (float)height * 100.0;
+ int i = 0;
+
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimension res = camera->getRes();
+
+ // find the scaling factor that is at least as big as the current camera
+ while (i < factorsNum) {
+ scalingFactor = factor[i];
+ tempWidth = TJSCALED(width, scalingFactor);
+ if (tempWidth < res.lx && i > 0) {
+ scalingFactor = factor[i - 1];
+ break;
+ }
+ i++;
+ }
+ // make sure the scaling factor has the right aspect ratio
+ while (i >= 0) {
+ tempWidth = TJSCALED(width, scalingFactor);
+ tempHeight = TJSCALED(height, scalingFactor);
+ if ((int)((float)tempWidth / (float)tempHeight * 100.0) == intRatio) {
+ break;
+ }
+ i--;
+ scalingFactor = factor[i];
+ }
+ } else {
+ tempWidth = width;
+ tempHeight = height;
+ }
+
+ if (m_useScaledImages || !getCurrentImageQuality().contains("Large")) {
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimensionD size = camera->getSize();
+ m_proxyImageDimensions = TDimension(tempWidth, tempHeight);
+ double minimumDpi = std::min(m_proxyImageDimensions.lx / size.lx,
+ m_proxyImageDimensions.ly / size.ly);
+ m_proxyDpi = TPointD(minimumDpi, minimumDpi);
+ }
+
+ tjDecompress2(tjInstance, data, mySize, imgBuf, tempWidth,
+ tempWidth * tjPixelSize[pixelFormat], tempHeight, pixelFormat,
+ flags);
+
+ m_newImage = TRaster32P(tempWidth, tempHeight);
+ m_newImage->lock();
+ uchar *rawData = m_newImage->getRawData();
+ memcpy(rawData, imgBuf, tempWidth * tempHeight * tjPixelSize[pixelFormat]);
+ m_newImage->unlock();
+
+ tjFree(imgBuf);
+ imgBuf = NULL;
+ tjDestroy(tjInstance);
+ tjInstance = NULL;
+
+ // end tj code
+
+ if (m_useScaledImages) {
+ QFile fullImage(m_tempFile);
+ fullImage.open(QIODevice::WriteOnly);
+ QDataStream dataStream(&fullImage);
+ dataStream.writeRawData((const char *)data, mySize);
+ fullImage.close();
+ }
+
+ EdsRelease(stream);
+ stream = NULL;
+ if (object) EdsRelease(object);
+
+ if (err == EDS_ERR_OK) {
+ emit(newImageReady());
+ }
+
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::takePicture() {
+ EdsError err;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_PressShutterButton,
+ kEdsCameraCommand_ShutterButton_Completely_NonAF);
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_PressShutterButton,
+ kEdsCameraCommand_ShutterButton_OFF);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::startLiveView() {
+ if (m_camera && m_sessionOpen) {
+ EdsError err = EDS_ERR_OK;
+ // Get the output device for the live view image
+ EdsUInt32 device;
+ err = EdsGetPropertyData(m_camera, kEdsPropID_Evf_OutputDevice, 0,
+ sizeof(device), &device);
+ // PC live view starts by setting the PC as the output device for the live
+ // view image.
+ if (err == EDS_ERR_OK) {
+ device |= kEdsEvfOutputDevice_PC;
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Evf_OutputDevice, 0,
+ sizeof(device), &device);
+ }
+ if (err == EDS_ERR_OK) {
+ m_liveViewStatus = LiveViewStarting;
+ }
+ // A property change event notification is issued from the camera if
+ // property settings are made successfully. Start downloading of the live
+ // view image once the property change notification arrives.
+ return err;
+ } else
+ return EDS_ERR_DEVICE_NOT_FOUND;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::endLiveView() {
+ EdsError err = EDS_ERR_OK;
+ // Get the output device for the live view image
+ EdsUInt32 device;
+ err = EdsGetPropertyData(m_camera, kEdsPropID_Evf_OutputDevice, 0,
+ sizeof(device), &device);
+ // PC live view ends if the PC is disconnected from the live view image output
+ // device.
+ if (err == EDS_ERR_OK) {
+ device &= ~kEdsEvfOutputDevice_PC;
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Evf_OutputDevice, 0,
+ sizeof(device), &device);
+ }
+ m_liveViewStatus = LiveViewClosed;
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::zoomLiveView() {
+ if (!m_sessionOpen) return EDS_ERR_DEVICE_INVALID;
+ EdsError err = EDS_ERR_OK;
+
+ if (m_liveViewZoom == 1) {
+ m_liveViewZoom = 5;
+ m_zooming = true;
+ } else if (m_liveViewZoom == 5) {
+ m_liveViewZoom = 1;
+ m_zooming = false;
+ }
+
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Evf_Zoom, 0,
+ sizeof(m_liveViewZoom), &m_liveViewZoom);
+ if (m_liveViewZoom == 5) setZoomPoint();
+
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::makeZoomPoint(TPointD pos) {
+ m_liveViewZoomPickPoint = pos;
+ double maxFullWidth =
+ (double)m_fullImageDimensions.lx / m_fullImageDpi.x * Stage::inch;
+ double maxFullHeight =
+ (double)m_fullImageDimensions.ly / m_fullImageDpi.y * Stage::inch;
+ double newX = m_liveViewZoomPickPoint.x + maxFullWidth / 2.0;
+ double newY = -m_liveViewZoomPickPoint.y + maxFullHeight / 2.0;
+ m_calculatedZoomPoint.x = newX / Stage::inch * m_fullImageDpi.x;
+ m_calculatedZoomPoint.y = newY / Stage::inch * m_fullImageDpi.x;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::setZoomPoint() {
+ EdsError err = EDS_ERR_OK;
+
+ EdsPoint zoomPoint;
+ if (m_liveViewZoomPickPoint == TPointD(0.0, 0.0)) {
+ m_calculatedZoomPoint =
+ TPoint(m_fullImageDimensions.lx / 2, m_fullImageDimensions.ly / 2);
+ m_finalZoomPoint.x = m_calculatedZoomPoint.x - (m_zoomRect.x / 2);
+ m_finalZoomPoint.y = m_calculatedZoomPoint.y - (m_zoomRect.y / 2);
+ } else {
+ m_finalZoomPoint.x = m_calculatedZoomPoint.x - (m_zoomRect.x / 2);
+ m_finalZoomPoint.y = m_calculatedZoomPoint.y - (m_zoomRect.y / 2);
+ if (m_finalZoomPoint.x < 0) m_finalZoomPoint.x = 0;
+ if (m_finalZoomPoint.y < 0) m_finalZoomPoint.y = 0;
+ if (m_finalZoomPoint.x > m_fullImageDimensions.lx - (m_zoomRect.x)) {
+ m_finalZoomPoint.x = m_fullImageDimensions.lx - (m_zoomRect.x);
+ }
+ if (m_finalZoomPoint.y > m_fullImageDimensions.ly - (m_zoomRect.y)) {
+ m_finalZoomPoint.y = m_fullImageDimensions.ly - (m_zoomRect.y);
+ }
+ }
+
+ zoomPoint.x = m_finalZoomPoint.x;
+ zoomPoint.y = m_finalZoomPoint.y;
+
+ // make sure this is set AFTER starting zoom
+ err = EdsSetPropertyData(m_camera, kEdsPropID_Evf_ZoomPosition, 0,
+ sizeof(zoomPoint), &zoomPoint);
+
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::downloadEVFData() {
+ EdsError err = EDS_ERR_OK;
+ EdsStreamRef stream = NULL;
+ EdsEvfImageRef evfImage = NULL;
+
+ // Create memory stream.
+ err = EdsCreateMemoryStream(0, &stream);
+ // Create EvfImageRef.
+ if (err == EDS_ERR_OK) {
+ err = EdsCreateEvfImageRef(stream, &evfImage);
+ }
+ // Download live view image data.
+ if (err == EDS_ERR_OK) {
+ err = EdsDownloadEvfImage(m_camera, evfImage);
+ }
+
+ EdsDataType evfZoom;
+ EdsDataType evfZoomPos;
+ EdsDataType evfZoomRect;
+ EdsUInt32 size;
+ EdsUInt32 sizePos;
+ EdsUInt32 sizeRect;
+ EdsUInt32 sizeImagePos;
+ EdsUInt32 sizeCoordSys;
+ EdsUInt32 zoomAmount;
+ EdsPoint zoomPos;
+ EdsRect zoomRect;
+ EdsPoint imagePos;
+ EdsSize coordSys;
+
+ err = EdsGetPropertySize(evfImage, kEdsPropID_Evf_Zoom, 0, &evfZoom, &size);
+ err = EdsGetPropertyData(evfImage, kEdsPropID_Evf_Zoom, 0, sizeof(size),
+ &zoomAmount);
+
+ // this is the top corner? of the zoomed image
+ err = EdsGetPropertySize(evfImage, kEdsPropID_Evf_ZoomPosition, 0,
+ &evfZoomPos, &sizePos);
+ err = EdsGetPropertyData(evfImage, kEdsPropID_Evf_ZoomPosition, 0, sizePos,
+ &zoomPos);
+ // this is the top corner of the zoomed image and the size of the zoomed image
+ err = EdsGetPropertySize(evfImage, kEdsPropID_Evf_ZoomRect, 0, &evfZoomRect,
+ &sizeRect);
+ err = EdsGetPropertyData(evfImage, kEdsPropID_Evf_ZoomRect, 0, sizeRect,
+ &zoomRect);
+
+ err = EdsGetPropertySize(evfImage, kEdsPropID_Evf_ImagePosition, 0,
+ &evfZoomRect, &sizeImagePos);
+ err = EdsGetPropertyData(evfImage, kEdsPropID_Evf_ImagePosition, 0,
+ sizeImagePos, &imagePos);
+ // this returns the size of the full image
+ err = EdsGetPropertySize(evfImage, kEdsPropID_Evf_CoordinateSystem, 0,
+ &evfZoomRect, &sizeCoordSys);
+ err = EdsGetPropertyData(evfImage, kEdsPropID_Evf_CoordinateSystem, 0,
+ sizeCoordSys, &coordSys);
+
+ m_zoomRect = TPoint(zoomRect.size.width, zoomRect.size.height);
+ if (zoomAmount == 5 && m_zoomRect == TPoint(0, 0)) {
+ setZoomPoint();
+ }
+
+ // Get the incidental data of the image.
+ if (err == EDS_ERR_OK) {
+ JpgConverter *converter = new JpgConverter;
+ converter->setStream(stream);
+ converter->setScale(m_useScaledImages);
+
+ connect(converter, SIGNAL(imageReady(bool)), this, SLOT(onImageReady(bool)),
+ Qt::QueuedConnection);
+ connect(converter, SIGNAL(finished()), this, SLOT(onFinished()),
+ Qt::QueuedConnection);
+
+ converter->start();
+
+ while (!l_quitLoop)
+ QCoreApplication::processEvents(QEventLoop::AllEvents |
+ QEventLoop::WaitForMoreEvents);
+
+ l_quitLoop = false;
+ m_liveViewImage = converter->getImage();
+ m_hasLiveViewImage = true;
+ delete converter;
+ if (!m_converterSucceeded) return EDS_ERR_UNEXPECTED_EXCEPTION;
+
+ // make sure not to set to LiveViewOpen if it has been turned off
+ if (m_liveViewStatus > 0) {
+ m_liveViewStatus = LiveViewOpen;
+ }
+ emit(newLiveViewImageReady());
+
+ if (m_hasLiveViewImage &&
+ (m_liveViewDpi.x == 0.0 || m_liveViewImageDimensions.lx == 0)) {
+ TCamera *camera =
+ TApp::instance()->getCurrentScene()->getScene()->getCurrentCamera();
+ TDimensionD size = camera->getSize();
+ m_liveViewImageDimensions =
+ TDimension(m_liveViewImage->getLx(), m_liveViewImage->getLy());
+ double minimumDpi = std::min(m_liveViewImageDimensions.lx / size.lx,
+ m_liveViewImageDimensions.ly / size.ly);
+ m_liveViewDpi = TPointD(minimumDpi, minimumDpi);
+
+ m_fullImageDimensions = TDimension(coordSys.width, coordSys.height);
+ minimumDpi = std::min(m_fullImageDimensions.lx / size.lx,
+ m_fullImageDimensions.ly / size.ly);
+ m_fullImageDpi = TPointD(minimumDpi, minimumDpi);
+
+ emit(newDimensions());
+ }
+ }
+
+ if (stream != NULL) {
+ EdsRelease(stream);
+ }
+ stream = NULL;
+ if (evfImage != NULL) {
+ EdsRelease(evfImage);
+ evfImage = NULL;
+ }
+
+ // calculate dpi data
+
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusNear() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Near1);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusFar() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Far1);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusNear2() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Near2);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusFar2() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Far2);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusNear3() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Near3);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::focusFar3() {
+ EdsError err = EDS_ERR_OK;
+ err = EdsSendCommand(m_camera, kEdsCameraCommand_DriveLensEvf,
+ kEdsEvfDriveLens_Far3);
+ return err;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::onImageReady(const bool &status) {
+ m_converterSucceeded = status;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::onFinished() { l_quitLoop = true; }
+
+//-----------------------------------------------------------------
+//-----------------------------------------------------------------
+
+EdsError StopMotion::handleObjectEvent(EdsObjectEvent event, EdsBaseRef object,
+ EdsVoid *context) {
+ if (event == kEdsObjectEvent_DirItemRequestTransfer) {
+ instance()->downloadImage(object);
+ }
+
+ return EDS_ERR_OK;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::handlePropertyEvent(EdsPropertyEvent event,
+ EdsPropertyID property,
+ EdsUInt32 param, EdsVoid *context) {
+ if (property == kEdsPropID_Evf_OutputDevice &&
+ event == kEdsPropertyEvent_PropertyChanged) {
+ if (instance()->m_liveViewStatus == LiveViewStarting)
+ instance()->m_liveViewStatus = LiveViewOpen;
+ }
+ if (property == kEdsPropID_AEMode &&
+ event == kEdsPropertyEvent_PropertyChanged) {
+ emit(instance()->modeChanged());
+ }
+
+ if (property == kEdsPropID_Av &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->apertureOptionsChanged());
+ }
+
+ if (property == kEdsPropID_Tv &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->shutterSpeedOptionsChanged());
+ }
+ if (property == kEdsPropID_ISOSpeed &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->isoOptionsChanged());
+ }
+ if (property == kEdsPropID_ExposureCompensation &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->exposureOptionsChanged());
+ }
+ if (property == kEdsPropID_WhiteBalance &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->whiteBalanceOptionsChanged());
+ }
+ if (property == kEdsPropID_PictureStyle &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->pictureStyleOptionsChanged());
+ }
+ if (property == kEdsPropID_ImageQuality &&
+ event == kEdsPropertyEvent_PropertyDescChanged) {
+ emit(instance()->imageQualityOptionsChanged());
+ }
+
+ return EDS_ERR_OK;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::handleStateEvent(EdsStateEvent event, EdsUInt32 parameter,
+ EdsVoid *context) {
+ if (event == kEdsStateEvent_Shutdown) {
+ if (instance()->m_sessionOpen) {
+ instance()->closeCameraSession();
+ instance()->releaseCamera();
+ instance()->m_liveViewStatus = LiveViewClosed;
+ emit(instance()->cameraChanged());
+ }
+ }
+ return EDS_ERR_OK;
+}
+
+//-----------------------------------------------------------------
+
+EdsError StopMotion::handleCameraAddedEvent(EdsVoid *context) {
+ instance()->cameraAdded();
+ return EDS_ERR_OK;
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildAvMap() {
+ m_avMap.insert(std::pair(0x00, "00"));
+ m_avMap.insert(std::pair(0x08, "1"));
+ m_avMap.insert(std::pair(0x0B, "1.1"));
+ m_avMap.insert(std::pair(0x0C, "1.2"));
+ m_avMap.insert(std::pair(0x0D, "1.2"));
+ m_avMap.insert(std::pair(0x10, "1.4"));
+ m_avMap.insert(std::pair(0x13, "1.6"));
+ m_avMap.insert(std::pair(0x14, "1.8"));
+ m_avMap.insert(std::pair(0x15, "1.8"));
+ m_avMap.insert(std::pair(0x18, "2"));
+ m_avMap.insert(std::pair(0x1B, "2.2"));
+ m_avMap.insert(std::pair(0x1C, "2.5"));
+ m_avMap.insert(std::pair(0x1D, "2.5"));
+ m_avMap.insert(std::pair(0x20, "2.8"));
+ m_avMap.insert(std::pair(0x23, "3.2"));
+ m_avMap.insert(std::pair(0x24, "3.5"));
+ m_avMap.insert(std::pair(0x25, "3.5"));
+ m_avMap.insert(std::pair(0x28, "4"));
+ m_avMap.insert(std::pair(0x2B, "4.5"));
+ m_avMap.insert(std::pair(0x2C, "4.5"));
+ m_avMap.insert(std::pair(0x2D, "5.0"));
+ m_avMap.insert(std::pair(0x30, "5.6"));
+ m_avMap.insert(std::pair(0x33, "6.3"));
+ m_avMap.insert(std::pair(0x34, "6.7"));
+ m_avMap.insert(std::pair(0x35, "7.1"));
+ m_avMap.insert(std::pair(0x38, "8"));
+ m_avMap.insert(std::pair(0x3B, "9"));
+ m_avMap.insert(std::pair(0x3C, "9.5"));
+ m_avMap.insert(std::pair(0x3D, "10"));
+ m_avMap.insert(std::pair(0x40, "11"));
+ m_avMap.insert(std::pair(0x43, "13"));
+ m_avMap.insert(std::pair(0x44, "13"));
+ m_avMap.insert(std::pair(0x45, "14"));
+ m_avMap.insert(std::pair(0x48, "16"));
+ m_avMap.insert(std::pair(0x4B, "18"));
+ m_avMap.insert(std::pair(0x4C, "19"));
+ m_avMap.insert(std::pair(0x4D, "20"));
+ m_avMap.insert(std::pair(0x50, "22"));
+ m_avMap.insert(std::pair(0x53, "25"));
+ m_avMap.insert(std::pair(0x54, "27"));
+ m_avMap.insert(std::pair(0x55, "29"));
+ m_avMap.insert(std::pair(0x58, "32"));
+ m_avMap.insert(std::pair(0x5B, "36"));
+ m_avMap.insert(std::pair(0x5C, "38"));
+ m_avMap.insert(std::pair(0x5D, "40"));
+ m_avMap.insert(std::pair(0x60, "45"));
+ m_avMap.insert(std::pair(0x63, "51"));
+ m_avMap.insert(std::pair(0x64, "54"));
+ m_avMap.insert(std::pair(0x65, "57"));
+ m_avMap.insert(std::pair(0x68, "64"));
+ m_avMap.insert(std::pair(0x6B, "72"));
+ m_avMap.insert(std::pair(0x6C, "76"));
+ m_avMap.insert(std::pair(0x6D, "80"));
+ m_avMap.insert(std::pair(0x70, "91"));
+ m_avMap.insert(std::pair(0xFF, "Auto"));
+ m_avMap.insert(std::pair(0xffffffff, "unknown"));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildIsoMap() {
+ m_isoMap.insert(std::pair(0x00, "Auto"));
+ m_isoMap.insert(std::pair(0x28, "6"));
+ m_isoMap.insert(std::pair(0x30, "12"));
+ m_isoMap.insert(std::pair(0x38, "25"));
+ m_isoMap.insert(std::pair(0x40, "50"));
+ m_isoMap.insert(std::pair(0x48, "100"));
+ m_isoMap.insert(std::pair(0x4b, "125"));
+ m_isoMap.insert(std::pair(0x4d, "160"));
+ m_isoMap.insert(std::pair(0x50, "200"));
+ m_isoMap.insert(std::pair(0x53, "250"));
+ m_isoMap.insert(std::pair(0x55, "320"));
+ m_isoMap.insert(std::pair(0x58, "400"));
+ m_isoMap.insert(std::pair(0x5b, "500"));
+ m_isoMap.insert(std::pair(0x5d, "640"));
+ m_isoMap.insert(std::pair(0x60, "800"));
+ m_isoMap.insert(std::pair(0x63, "1000"));
+ m_isoMap.insert(std::pair(0x65, "1250"));
+ m_isoMap.insert(std::pair(0x68, "1600"));
+ m_isoMap.insert(std::pair(0x6b, "2000"));
+ m_isoMap.insert(std::pair(0x6d, "2500"));
+ m_isoMap.insert(std::pair(0x70, "3200"));
+ m_isoMap.insert(std::pair(0x73, "4000"));
+ m_isoMap.insert(std::pair(0x75, "5000"));
+ m_isoMap.insert(std::pair(0x78, "6400"));
+ m_isoMap.insert(std::pair(0x7b, "8000"));
+ m_isoMap.insert(std::pair(0x7d, "10000"));
+ m_isoMap.insert(std::pair(0x80, "12800"));
+ m_isoMap.insert(std::pair(0x83, "16000"));
+ m_isoMap.insert(std::pair(0x85, "20000"));
+ m_isoMap.insert(std::pair(0x88, "25600"));
+ m_isoMap.insert(std::pair(0x8b, "32000"));
+ m_isoMap.insert(std::pair(0x8d, "40000"));
+ m_isoMap.insert(std::pair(0x90, "51200"));
+ m_isoMap.insert(std::pair(0x98, "102400"));
+ m_isoMap.insert(std::pair(0xa0, "204800"));
+ m_isoMap.insert(std::pair(0xa8, "409600"));
+ m_isoMap.insert(std::pair(0xffffffff, "unknown"));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildTvMap() {
+ m_tvMap.insert(std::pair(0x04, "Auto"));
+ m_tvMap.insert(std::pair(0x0c, "Bulb"));
+ m_tvMap.insert(std::pair(0x10, "30\""));
+ m_tvMap.insert(std::pair(0x13, "25\""));
+ m_tvMap.insert(std::pair(0x14, "20\""));
+ m_tvMap.insert(std::pair(0x15, "20\""));
+ m_tvMap.insert(std::pair(0x18, "15\""));
+ m_tvMap.insert(std::pair(0x1B, "13\""));
+ m_tvMap.insert(std::pair(0x1C, "10\""));
+ m_tvMap.insert(std::pair(0x1D, "10\""));
+ m_tvMap.insert(std::pair(0x20, "8\""));
+ m_tvMap.insert(std::pair(0x23, "6\""));
+ m_tvMap.insert(std::pair(0x24, "6\""));
+ m_tvMap.insert(std::pair(0x25, "5\""));
+ m_tvMap.insert(std::pair(0x28, "4\""));
+ m_tvMap.insert(std::pair(0x2B, "3\"2"));
+ m_tvMap.insert(std::pair(0x2C, "3\""));
+ m_tvMap.insert(std::pair(0x2D, "2\"5"));
+ m_tvMap.insert(std::pair(0x30, "2\""));
+ m_tvMap.insert(std::pair(0x33, "1\"6"));
+ m_tvMap.insert(std::pair(0x34, "1\"5"));
+ m_tvMap.insert(std::pair(0x35, "1\"3"));
+ m_tvMap.insert(std::pair(0x38, "1\""));
+ m_tvMap.insert(std::pair(0x3B, "0\"8"));
+ m_tvMap.insert(std::pair(0x3C, "0\"7"));
+ m_tvMap.insert(std::pair(0x3D, "0\"6"));
+ m_tvMap.insert(std::pair(0x40, "0\"5"));
+ m_tvMap.insert(std::pair(0x43, "0\"4"));
+ m_tvMap.insert(std::pair(0x44, "0\"3"));
+ m_tvMap.insert(std::pair(0x45, "0\"3"));
+ m_tvMap.insert(std::pair(0x48, "1/4"));
+ m_tvMap.insert(std::pair(0x4B, "1/5"));
+ m_tvMap.insert(std::pair(0x4C, "1/6"));
+ m_tvMap.insert(std::pair(0x4D, "1/6"));
+ m_tvMap.insert(std::pair(0x50, "1/8"));
+ m_tvMap.insert(std::pair(0x53, "1/10"));
+ m_tvMap.insert(std::pair(0x54, "1/10"));
+ m_tvMap.insert(std::pair(0x55, "1/13"));
+ m_tvMap.insert(std::pair(0x58, "1/15"));
+ m_tvMap.insert(std::pair(0x5B, "1/20"));
+ m_tvMap.insert(std::pair(0x5C, "1/20"));
+ m_tvMap.insert(std::pair(0x5D, "1/25"));
+ m_tvMap.insert(std::pair(0x60, "1/30"));
+ m_tvMap.insert(std::pair(0x63, "1/40"));
+ m_tvMap.insert(std::pair(0x64, "1/45"));
+ m_tvMap.insert(std::pair(0x65, "1/50"));
+ m_tvMap.insert(std::pair(0x68, "1/60"));
+ m_tvMap.insert(std::pair(0x6B, "1/80"));
+ m_tvMap.insert(std::pair(0x6C, "1/90"));
+ m_tvMap.insert(std::pair(0x6D, "1/100"));
+ m_tvMap.insert(std::pair(0x70, "1/125"));
+ m_tvMap.insert(std::pair(0x73, "1/160"));
+ m_tvMap.insert(std::pair(0x74, "1/180"));
+ m_tvMap.insert(std::pair(0x75, "1/200"));
+ m_tvMap.insert(std::pair(0x78, "1/250"));
+ m_tvMap.insert(std::pair(0x7B, "1/320"));
+ m_tvMap.insert(std::pair(0x7C, "1/350"));
+ m_tvMap.insert(std::pair(0x7D, "1/400"));
+ m_tvMap.insert(std::pair(0x80, "1/500"));
+ m_tvMap.insert(std::pair(0x83, "1/640"));
+ m_tvMap.insert(std::pair(0x84, "1/750"));
+ m_tvMap.insert(std::pair(0x85, "1/800"));
+ m_tvMap.insert(std::pair(0x88, "1/1000"));
+ m_tvMap.insert(std::pair(0x8B, "1/1250"));
+ m_tvMap.insert(std::pair(0x8C, "1/1500"));
+ m_tvMap.insert(std::pair(0x8D, "1/1600"));
+ m_tvMap.insert(std::pair(0x90, "1/2000"));
+ m_tvMap.insert(std::pair(0x93, "1/2500"));
+ m_tvMap.insert(std::pair(0x94, "1/3000"));
+ m_tvMap.insert(std::pair(0x95, "1/3200"));
+ m_tvMap.insert(std::pair(0x98, "1/4000"));
+ m_tvMap.insert(std::pair(0x9B, "1/5000"));
+ m_tvMap.insert(std::pair(0x9C, "1/6000"));
+ m_tvMap.insert(std::pair(0x9D, "1/6400"));
+ m_tvMap.insert(std::pair(0xA0, "1/8000"));
+ m_tvMap.insert(std::pair(0xffffffff, "unknown"));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildModeMap() {
+ m_modeMap.insert(std::pair(0, "P"));
+ m_modeMap.insert(std::pair(1, "Tv"));
+ m_modeMap.insert(std::pair(2, "Av"));
+ m_modeMap.insert(std::pair(3, "M"));
+ m_modeMap.insert(std::pair(55, "FV"));
+ m_modeMap.insert(std::pair(4, "Bulb"));
+ m_modeMap.insert(std::pair(5, "A-DEP"));
+ m_modeMap.insert(std::pair(6, "DEP"));
+ m_modeMap.insert(std::pair(7, "C1"));
+ m_modeMap.insert(std::pair(16, "C2"));
+ m_modeMap.insert(std::pair(17, "C3"));
+ m_modeMap.insert(std::pair(8, "Lock"));
+ m_modeMap.insert(std::pair(9, "GreenMode"));
+ m_modeMap.insert(std::pair(10, "Night Portrait"));
+ m_modeMap.insert(std::pair(11, "Sports"));
+ m_modeMap.insert(std::pair(13, "LandScape"));
+ m_modeMap.insert(std::pair(14, "Close-Up"));
+ m_modeMap.insert(std::pair(15, "No Strobo"));
+ m_modeMap.insert(std::pair(12, "Portrait"));
+ m_modeMap.insert(std::pair(19, "Creative Auto"));
+ m_modeMap.insert(std::pair(20, "Movies"));
+ m_modeMap.insert(std::pair(25, "SCN"));
+ m_modeMap.insert(
+ std::pair(22, "Scene Intelligent Auto"));
+ m_modeMap.insert(std::pair(29, "Creative filters"));
+ m_modeMap.insert(std::pair(0xffffffff, "unknown"));
+}
+
+//-----------------------------------------------------------------
+
+void StopMotion::buildExposureMap() {
+ m_exposureMap.insert(std::pair(0x28, "+5"));
+ m_exposureMap.insert(std::pair(0x25, "+4 2/3"));
+ m_exposureMap.insert(std::pair(0x24, "+4 1/2"));
+ m_exposureMap.insert(std::pair(0x23, "+4 1/3"));
+ m_exposureMap.insert(std::pair(0x20, "+4"));
+ m_exposureMap.insert(std::pair(0x1D, "+3 2/3"));
+ m_exposureMap.insert(std::pair(0x1C, "+3 1/2"));
+ m_exposureMap.insert(std::pair(0x1B, "+3 1/3"));
+
+ m_exposureMap.insert(std::pair(0x18, "+3"));
+ m_exposureMap.insert(std::pair(0x15, "+2 2/3"));
+ m_exposureMap.insert(std::pair(0x14, "+2 1/2"));
+ m_exposureMap.insert(std::pair(0x13, "+2 1/3"));
+ m_exposureMap.insert(std::pair(0x10, "+2"));
+ m_exposureMap.insert(std::pair(0x0d, "+1 2/3"));
+ m_exposureMap.insert(std::pair(0x0c, "+1 1/2"));
+ m_exposureMap.insert(std::pair(0x0b, "+1 1/3"));
+ m_exposureMap.insert(std::pair(0x08, "+1"));
+ m_exposureMap.insert(std::pair(0x05, "+2/3"));
+ m_exposureMap.insert(std::pair(0x04, "+1/2"));
+ m_exposureMap.insert(std::pair(0x03, "+1/3"));
+ m_exposureMap.insert(std::pair(0x00, "0"));
+ m_exposureMap.insert(std::pair(0xfd, "-1/3"));
+ m_exposureMap.insert(std::pair(0xfc, "-1/2"));
+ m_exposureMap.insert(std::pair