Skip to content

Commit

Permalink
Add support for side-by-side stereo images (.jps)
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Dumusc committed Aug 27, 2018
1 parent 278bcc6 commit d7a4339
Show file tree
Hide file tree
Showing 35 changed files with 373 additions and 145 deletions.
2 changes: 2 additions & 0 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Changelog {#changelog}

# Release 1.5 (git master)

* [265](https://github.com/BlueBrain/Tide/pull/265):
Add support for 3D images (side-by-side jpeg images with .jps extension).
* [264](https://github.com/BlueBrain/Tide/pull/264):
Fix a crash that could occur when playing large 3D movies.
* [261](https://github.com/BlueBrain/Tide/pull/261):
Expand Down
2 changes: 1 addition & 1 deletion tests/cpp/core/ContentControllerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(factory_method)
controller = ContentController::create(window);
BOOST_CHECK(dynamic_cast<ZoomController*>(controller.get()));

dummyContent.type = ContentType::texture;
dummyContent.type = ContentType::image;
controller = ContentController::create(window);
BOOST_CHECK(dynamic_cast<ZoomController*>(controller.get()));

Expand Down
36 changes: 18 additions & 18 deletions tests/cpp/core/StateSerializationTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#include "scene/ContentFactory.h"
#include "scene/DisplayGroup.h"
#include "scene/ErrorContent.h"
#include "scene/TextureContent.h"
#include "scene/ImageContent.h"
#include "scene/Window.h"
#include "serialization/utils.h"
#include "types.h"
Expand All @@ -68,7 +68,7 @@ const QSize CONTENT_SIZE(100, 100);
const int DUMMY_PARAM_VALUE = 10;
const QString DUMMY_URI = "/dummuy/uri";
const QString INVALID_URI = "/invalid/uri";
const QString VALID_TEXTURE_URI = "wall.png";
const QString VALID_IMAGE_URI = "wall.png";
const QString LEGACY_URI = "legacy.dcx";
const QString STATE_V0_URI = "state_v0.dcx";
const QString STATE_V0_PREVIEW_FILE = "state_v0.dcxpreview";
Expand All @@ -77,20 +77,20 @@ const QString STATE_V3_URI = "state_v3.dcx";
const QString STATE_V3_NOTITLES_URI = "state_v3_noTitles.dcx";
const QString STATE_V4_URI = "state_v4.dcx";
const QString TEST_DIR = "tmp";
const QSize VALID_TEXTURE_SIZE(256, 128);
const QSize VALID_IMAGE_SIZE(256, 128);
}

WindowPtr makeValidTestWindow(const QString& uri)
{
auto content = ContentFactory::getContent(uri);
BOOST_REQUIRE(content);
BOOST_REQUIRE_EQUAL(content->getDimensions(), VALID_TEXTURE_SIZE);
BOOST_REQUIRE_EQUAL(content->getDimensions(), VALID_IMAGE_SIZE);
return std::make_shared<Window>(std::move(content));
}

WindowPtr makeInvalidTestWindow(const QString& uri)
{
auto missingContent = std::make_unique<TextureContent>(uri);
auto missingContent = std::make_unique<ImageContent>(uri);
return std::make_shared<Window>(std::move(missingContent));
}

Expand Down Expand Up @@ -172,10 +172,10 @@ BOOST_AUTO_TEST_CASE(testWhenOpeningBrokenStateThenNoExceptionIsThrown)

void checkContent(const Content& content)
{
BOOST_CHECK_EQUAL(content.getDimensions(), VALID_TEXTURE_SIZE);
BOOST_CHECK_EQUAL(content.getType(), ContentType::texture);
BOOST_CHECK_EQUAL(content.getDimensions(), VALID_IMAGE_SIZE);
BOOST_CHECK_EQUAL(content.getType(), ContentType::image);
BOOST_CHECK_EQUAL(content.getUri().toStdString(),
VALID_TEXTURE_URI.toStdString());
VALID_IMAGE_URI.toStdString());
}

void checkLegacyWindow(WindowPtr window)
Expand Down Expand Up @@ -350,7 +350,7 @@ BOOST_AUTO_TEST_CASE(testStateSerializationHelperReadingFromVersion4File)

DisplayGroupPtr createTestDisplayGroup()
{
auto window = makeValidTestWindow(VALID_TEXTURE_URI);
auto window = makeValidTestWindow(VALID_IMAGE_URI);

const QPointF position(0.25 * wallSize.width(), 0.25 * wallSize.height());
window->setCoordinates(QRectF(position, 0.5 * wallSize));
Expand Down Expand Up @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(testStateSerializationUploadedToFile)
// 2) Create new file and put it into system temp folder
const auto uploadedFile = QString{"uploaded.png"};
const auto newValidUri = tempDir + "/" + uploadedFile;
QFile::copy(VALID_TEXTURE_URI, newValidUri);
QFile::copy(VALID_IMAGE_URI, newValidUri);

// 3) Test saving
auto displayGroup = createTestDisplayGroup();
Expand All @@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(testStateSerializationUploadedToFile)
savedSessionDir + uploadedFile);

// 4) Add another file with the same name and test saving
QFile::copy(VALID_TEXTURE_URI, newValidUri);
QFile::copy(VALID_IMAGE_URI, newValidUri);
auto newWindow = makeValidTestWindow(newValidUri);
displayGroup->add(newWindow);
BOOST_CHECK(
Expand All @@ -476,7 +476,7 @@ BOOST_AUTO_TEST_CASE(testErrorContentWhenFileMissing)

auto group = DisplayGroup::create(wallSize);
group->add(makeInvalidTestWindow(INVALID_URI));
group->add(makeValidTestWindow(VALID_TEXTURE_URI));
group->add(makeValidTestWindow(VALID_IMAGE_URI));
auto scene = Scene::create(group);

// 2) saving session
Expand All @@ -502,9 +502,9 @@ BOOST_AUTO_TEST_CASE(testErrorContentWhenFileMissing)
BOOST_CHECK_EQUAL(errorContent.getTitle(), "uri");

const auto& validContent = loadedGroup.getWindows()[1]->getContent();
BOOST_CHECK_EQUAL(validContent.getUri(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent.getFilePath(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent.getTitle(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent.getUri(), VALID_IMAGE_URI);
BOOST_CHECK_EQUAL(validContent.getFilePath(), VALID_IMAGE_URI);
BOOST_CHECK_EQUAL(validContent.getTitle(), VALID_IMAGE_URI);

// 4) saving session a second time (error content is not saved)
BOOST_CHECK(StateSerializationHelper{loadedScene}.save(file).result());
Expand All @@ -516,9 +516,9 @@ BOOST_AUTO_TEST_CASE(testErrorContentWhenFileMissing)

BOOST_REQUIRE_EQUAL(loadedGroup2.getWindows().size(), 1);
const auto& validContent2 = loadedGroup2.getWindows()[0]->getContent();
BOOST_CHECK_EQUAL(validContent2.getUri(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent2.getFilePath(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent2.getTitle(), VALID_TEXTURE_URI);
BOOST_CHECK_EQUAL(validContent2.getUri(), VALID_IMAGE_URI);
BOOST_CHECK_EQUAL(validContent2.getFilePath(), VALID_IMAGE_URI);
BOOST_CHECK_EQUAL(validContent2.getTitle(), VALID_IMAGE_URI);

// 5) cleanup
cleanupTestDir();
Expand Down
2 changes: 1 addition & 1 deletion tests/cpp/core/WindowTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ BOOST_AUTO_TEST_CASE(testWindowResizePolicyNonZoomableContent)
BOOST_AUTO_TEST_CASE(testWindowResizePolicyZoomableContent)
{
auto content = makeDummyContent();
static_cast<DummyContent&>(*content).type = ContentType::texture;
static_cast<DummyContent&>(*content).type = ContentType::image;
Window window(std::move(content));

// Default state
Expand Down
6 changes: 4 additions & 2 deletions tide/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ list(APPEND TIDECORE_PUBLIC_HEADERS
configuration/SurfaceConfigValidator.h
configuration/XmlParser.h
data/Image.h
data/ImageReader.h
data/QtImage.h
data/StreamImage.h
data/SVG.h
Expand Down Expand Up @@ -169,7 +170,7 @@ list(APPEND TIDECORE_PUBLIC_HEADERS
scene/ScreenLock.h
scene/Surface.h
scene/SVGContent.h
scene/TextureContent.h
scene/ImageContent.h
scene/VectorialContent.h
scene/Window.h
scene/ZoomHelper.h
Expand Down Expand Up @@ -206,6 +207,7 @@ list(APPEND TIDECORE_SOURCES
configuration/SurfaceConfig.cpp
configuration/SurfaceConfigValidator.cpp
configuration/XmlParser.cpp
data/ImageReader.cpp
data/QtImage.cpp
data/StreamImage.cpp
data/SVG.cpp
Expand Down Expand Up @@ -246,7 +248,7 @@ list(APPEND TIDECORE_SOURCES
scene/ScreenLock.cpp
scene/Surface.cpp
scene/SVGContent.cpp
scene/TextureContent.cpp
scene/ImageContent.cpp
scene/VectorialContent.cpp
scene/Window.cpp
scene/ZoomHelper.cpp
Expand Down
122 changes: 122 additions & 0 deletions tide/core/data/ImageReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*********************************************************************/
/* Copyright (c) 2018, EPFL/Blue Brain Project */
/* Raphael Dumusc <raphael.dumusc@epfl.ch> */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or */
/* without modification, are permitted provided that the following */
/* conditions are met: */
/* */
/* 1. Redistributions of source code must retain the above */
/* copyright notice, this list of conditions and the following */
/* disclaimer. */
/* */
/* 2. Redistributions in binary form must reproduce the above */
/* copyright notice, this list of conditions and the following */
/* disclaimer in the documentation and/or other materials */
/* provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */
/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */
/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */
/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */
/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
/* POSSIBILITY OF SUCH DAMAGE. */
/* */
/* The views and conclusions contained in the software and */
/* documentation are those of the authors and should not be */
/* interpreted as representing official policies, either expressed */
/* or implied, of Ecole polytechnique federale de Lausanne. */
/*********************************************************************/

#include "ImageReader.h"

#include "data/QtImage.h"

#include <QFileInfo>

namespace
{
bool _isStereoImage(const QString& uri)
{
return QFileInfo{uri}.suffix().toLower() == "jps";
}

QSize _getMonoSize(const QSize& stereoSize)
{
return QSize{stereoSize.width() / 2, stereoSize.height()};
}

QRect _getMonoRect(const QSize& image, const deflect::View view)
{
return view == deflect::View::right_eye
? QRect{QPoint{image.width() / 2, 0}, _getMonoSize(image)}
: QRect{QPoint{0, 0}, _getMonoSize(image)};
}

QImage _getMonoImage(const QImage& image, const deflect::View view)
{
return image.copy(_getMonoRect(image.size(), view));
}

QImage _ensureGlCompatibleFormat(const QImage& image)
{
const auto argb32 = QImage::Format_ARGB32;
return QtImage::is32Bits(image) ? image : image.convertToFormat(argb32);
}
}

ImageReader::ImageReader(const QString& uri)
: _reader{std::make_unique<QImageReader>(uri)}
, _stereo{_isStereoImage(uri)}
{
}

QString ImageReader::getUri() const
{
return _reader->fileName();
}

bool ImageReader::isValid() const
{
return _reader->canRead();
}

bool ImageReader::isStereo() const
{
return _stereo;
}

QSize ImageReader::getSize() const
{
return isStereo() ? _getMonoSize(_reader->size()) : _reader->size();
}

QImage ImageReader::getImage(const deflect::View view) const
{
return _ensureGlCompatibleFormat(_readImage(view));
}

QStringList ImageReader::getSupportedImageFormats()
{
QStringList extensions;

for (const auto& entry : QImageReader::supportedImageFormats())
extensions << entry;
extensions << "jps";

return extensions;
}

QImage ImageReader::_readImage(const deflect::View view) const
{
return isStereo() ? _getMonoImage(_reader->read(), view) : _reader->read();
}
71 changes: 71 additions & 0 deletions tide/core/data/ImageReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*********************************************************************/
/* Copyright (c) 2018, EPFL/Blue Brain Project */
/* Raphael Dumusc <raphael.dumusc@epfl.ch> */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or */
/* without modification, are permitted provided that the following */
/* conditions are met: */
/* */
/* 1. Redistributions of source code must retain the above */
/* copyright notice, this list of conditions and the following */
/* disclaimer. */
/* */
/* 2. Redistributions in binary form must reproduce the above */
/* copyright notice, this list of conditions and the following */
/* disclaimer in the documentation and/or other materials */
/* provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */
/* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */
/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */
/* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
/* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */
/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
/* POSSIBILITY OF SUCH DAMAGE. */
/* */
/* The views and conclusions contained in the software and */
/* documentation are those of the authors and should not be */
/* interpreted as representing official policies, either expressed */
/* or implied, of Ecole polytechnique federale de Lausanne. */
/*********************************************************************/

#ifndef IMAGEREADER_H
#define IMAGEREADER_H

#include "types.h"

#include <QImage>
#include <QImageReader>

/**
* Reader for regular 2D / stereo 3D images.
*/
class ImageReader
{
public:
ImageReader(const QString& uri);

QString getUri() const;
bool isValid() const;
bool isStereo() const;
QSize getSize() const;
QImage getImage(deflect::View view = deflect::View::mono) const;

static QStringList getSupportedImageFormats();

private:
std::unique_ptr<QImageReader> _reader;
bool _stereo = false;

QImage _readImage(deflect::View view) const;
};

#endif
Loading

0 comments on commit d7a4339

Please sign in to comment.