Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for side-by-side stereo images (.jps) #265

Merged
merged 1 commit into from
Aug 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
124 changes: 124 additions & 0 deletions tide/core/data/ImageReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*********************************************************************/
/* 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& imageSize, const deflect::View view)
{
return view == deflect::View::right_eye
? QRect{QPoint{imageSize.width() / 2, 0},
_getMonoSize(imageSize)}
: QRect{QPoint{0, 0}, _getMonoSize(imageSize)};
}

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

QImage _ensureGlCompatibleFormat(const QImage& image)
{
return QtImage::is32Bits(image)
? image
: image.convertToFormat(QImage::Format_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