<commit_before>/*
 * producer_glaxnimate.cpp -- a Glaxnimate/Qt based producer for MLT
 * Copyright (C) 2022 Meltytech, LLC
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 */

#include <framework/mlt.h>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>

#include "io/io_registry.hpp"
using namespace glaxnimate;

class Glaxnimate
{
private:
    mlt_producer m_producer = nullptr;
    std::unique_ptr<model::Document> m_document;

public:
    mlt_profile m_profile = nullptr;

    void setProducer( mlt_producer producer )
        { m_producer = producer; }

    mlt_producer producer() const
        { return m_producer; }

    mlt_service service() const
        { return MLT_PRODUCER_SERVICE(m_producer); }

    mlt_properties properties() const
        { return MLT_PRODUCER_PROPERTIES(m_producer); }

    QSize size() const { return m_document->size(); }

    int duration() const {
        auto frames = m_document->main()->animation->last_frame.get() - m_document->main()->animation->first_frame.get() + 1.f;
        return toMltFps(frames);
    }

    int toMltFps(float frame) const {
        return qRound(frame / fps() * m_profile->frame_rate_num / m_profile->frame_rate_den);
    }

    float toGlaxnimateFps(float frame) const {
        return frame * fps() * m_profile->frame_rate_den / m_profile->frame_rate_num;
    }

    int firstFrame() const {
        return toMltFps(m_document->main()->animation->first_frame.get());
    }

    float fps() const {
        return m_document->main()->get_fps();
    }

    int getImage(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable)
    {
        int error = 0;
        auto pos = mlt_frame_original_position(frame);
        if (mlt_properties_get(properties(), "eof") && !::strcmp("loop", mlt_properties_get(properties(), "eof"))) {
            pos %= duration();
        }
        auto bg = mlt_properties_get_color(properties(), "background");
        auto background = QColor(bg.r, bg.g, bg.b, bg.a);
        pos += toMltFps(m_document->main()->animation->first_frame.get());
        auto image = m_document->render_image(toGlaxnimateFps(pos), {*width, *height}, background);

        *format = mlt_image_rgba;
        int size = mlt_image_format_size(*format, *width, *height, NULL);
        *buffer = static_cast<uint8_t*>(mlt_pool_alloc(size));
        memcpy(*buffer, image.constBits(), size);
        error = mlt_frame_set_image(frame, *buffer, size, mlt_pool_release);

        return error;
    }

    bool open(const char* fileName)
    {
        auto filename = QString::fromUtf8(fileName);
        auto importer = io::IoRegistry::instance().from_filename(filename, io::ImportExport::Import);
        if (!importer || !importer->can_open()) {
            mlt_log_error(service(), "Unknown importer\n");
            return false;
        }

        QFile file(filename);
        if (!file.open(QIODevice::ReadOnly)) {
            mlt_log_error(service(), "Could not open input file for reading\n");
            return false;
        }

        m_document.reset(new model::Document(filename));
        QVariantMap settings;
        if (!importer->open(file, filename, m_document.get(), settings)) {
            mlt_log_error(service(), "Error loading input file\n");
            return false;
        }

        return true;
    }
};

extern "C" {

static int get_image(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable)
{
    auto producer = static_cast<mlt_producer>(mlt_frame_pop_service(frame));
    auto glax = static_cast<Glaxnimate*>(producer->child);

    if (mlt_properties_get_int(glax->properties(), "refresh")) {
        mlt_properties_clear(glax->properties(), "refresh");
        glax->open(mlt_properties_get(glax->properties(), "resource"));
        if (glax->duration() > mlt_properties_get_int(glax->properties(), "length")) {
            mlt_properties_set_int(glax->properties(), "length", glax->duration());
        }
    }

    return glax->getImage(frame, buffer, format, width, height, writable);
}

static int get_frame(mlt_producer producer, mlt_frame_ptr frame, int index)
{
    *frame = mlt_frame_init(MLT_PRODUCER_SERVICE(producer));
    mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame );

    // Set frame properties
    mlt_properties_set_int(frame_properties, "progressive", 1);
    double force_ratio = mlt_properties_get_double(MLT_PRODUCER_PROPERTIES(producer), "force_aspect_ratio");
    if (force_ratio > 0.0)
        mlt_properties_set_double(frame_properties, "aspect_ratio", force_ratio);
    else
        mlt_properties_set_double(frame_properties, "aspect_ratio", 1.0);

    mlt_frame_set_position(*frame, mlt_producer_position(producer));
    mlt_frame_push_service(*frame, producer);
    mlt_frame_push_get_image(*frame, get_image);
    mlt_producer_prepare_next(producer);
    return 0;
}

static void producer_close(mlt_producer producer)
{
    delete static_cast<Glaxnimate*>(producer->child);
    producer->close = nullptr;
    mlt_producer_close(producer);
}

mlt_producer producer_glaxnimate_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
{
    // Allocate the producer
    Glaxnimate* glax = new Glaxnimate();
    mlt_producer producer = (mlt_producer) calloc(1, sizeof( *producer ));

    // If allocated and initializes
    if (glax && !mlt_producer_init(producer, glax) && glax->open(arg)) {
        glax->setProducer(producer);
        glax->m_profile = profile;
        producer->close = (mlt_destructor) producer_close;
        producer->get_frame = get_frame;

        auto properties = glax->properties();
        mlt_properties_set(properties, "resource", arg);
        mlt_properties_set(properties, "background", "#00000000");
        mlt_properties_set_int(properties, "aspect_ratio", 1);
        mlt_properties_set_int(properties, "progressive", 1);
        mlt_properties_set_int(properties, "seekable", 1);
        mlt_properties_set_int(properties, "meta.media.width", glax->size().width());
        mlt_properties_set_int(properties, "meta.media.height", glax->size().height());
        mlt_properties_set_int(properties, "meta.media.sample_aspect_num", 1);
        mlt_properties_set_int(properties, "meta.media.sample_aspect_den", 1);
        mlt_properties_set_double(properties, "meta.media.frame_rate", glax->fps());
        mlt_properties_set_int(properties, "out", glax->duration() - 1);
        mlt_properties_set_int(properties, "length", glax->duration());
        mlt_properties_set_int(properties, "first_frame", glax->firstFrame());
        mlt_properties_set(properties, "eof", "loop");
    }
    return producer;
}

static mlt_properties metadata(mlt_service_type type, const char *id, void *data)
{
    char file[PATH_MAX];
    const char *service_type = NULL;
    switch (type) {
        case mlt_service_producer_type:
            service_type = "producer";
            break;
        default:
            return NULL;
    }
    snprintf(file, PATH_MAX, "%s/glaxnimate/%s_%s.yml", mlt_environment("MLT_DATA"), service_type, id);
    return mlt_properties_parse_yaml(file);
}

MLT_REPOSITORY
{
    MLT_REGISTER(mlt_service_producer_type, "glaxnimate", producer_glaxnimate_init);
    MLT_REGISTER_METADATA(mlt_service_producer_type, "glaxnimate", metadata, NULL);
}

} // extern C
<commit_msg>glaxnimate: fix melt may fail without QApplication<commit_after>/*
 * producer_glaxnimate.cpp -- a Glaxnimate/Qt based producer for MLT
 * Copyright (C) 2022 Meltytech, LLC
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>
 */

#include <framework/mlt.h>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <QApplication>

#include "io/io_registry.hpp"
using namespace glaxnimate;

class Glaxnimate
{
private:
    mlt_producer m_producer = nullptr;
    std::unique_ptr<model::Document> m_document;

public:
    mlt_profile m_profile = nullptr;

    void setProducer( mlt_producer producer )
        { m_producer = producer; }

    mlt_producer producer() const
        { return m_producer; }

    mlt_service service() const
        { return MLT_PRODUCER_SERVICE(m_producer); }

    mlt_properties properties() const
        { return MLT_PRODUCER_PROPERTIES(m_producer); }

    QSize size() const { return m_document->size(); }

    int duration() const {
        auto frames = m_document->main()->animation->last_frame.get() - m_document->main()->animation->first_frame.get() + 1.f;
        return toMltFps(frames);
    }

    int toMltFps(float frame) const {
        return qRound(frame / fps() * m_profile->frame_rate_num / m_profile->frame_rate_den);
    }

    float toGlaxnimateFps(float frame) const {
        return frame * fps() * m_profile->frame_rate_den / m_profile->frame_rate_num;
    }

    int firstFrame() const {
        return toMltFps(m_document->main()->animation->first_frame.get());
    }

    float fps() const {
        return m_document->main()->get_fps();
    }

    int getImage(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable)
    {
        int error = 0;
        auto pos = mlt_frame_original_position(frame);
        if (mlt_properties_get(properties(), "eof") && !::strcmp("loop", mlt_properties_get(properties(), "eof"))) {
            pos %= duration();
        }
        auto bg = mlt_properties_get_color(properties(), "background");
        auto background = QColor(bg.r, bg.g, bg.b, bg.a);
        pos += toMltFps(m_document->main()->animation->first_frame.get());
        auto image = m_document->render_image(toGlaxnimateFps(pos), {*width, *height}, background);

        *format = mlt_image_rgba;
        int size = mlt_image_format_size(*format, *width, *height, NULL);
        *buffer = static_cast<uint8_t*>(mlt_pool_alloc(size));
        memcpy(*buffer, image.constBits(), size);
        error = mlt_frame_set_image(frame, *buffer, size, mlt_pool_release);

        return error;
    }

    bool open(const char* fileName)
    {
        auto filename = QString::fromUtf8(fileName);
        auto importer = io::IoRegistry::instance().from_filename(filename, io::ImportExport::Import);
        if (!importer || !importer->can_open()) {
            mlt_log_error(service(), "Unknown importer\n");
            return false;
        }

        QFile file(filename);
        if (!file.open(QIODevice::ReadOnly)) {
            mlt_log_error(service(), "Could not open input file for reading\n");
            return false;
        }

        m_document.reset(new model::Document(filename));
        QVariantMap settings;
        if (!importer->open(file, filename, m_document.get(), settings)) {
            mlt_log_error(service(), "Error loading input file\n");
            return false;
        }

        return true;
    }
};

static bool createQApplicationIfNeeded(mlt_service service)
{
    if (!qApp) {
#if defined(Q_OS_WIN) && defined(NODEPLOY)
        QCoreApplication::addLibraryPath(QString(mlt_environment("MLT_APPDIR"))+QStringLiteral("/bin"));
        QCoreApplication::addLibraryPath(QString(mlt_environment("MLT_APPDIR"))+QStringLiteral("/plugins"));
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
        if (getenv("DISPLAY") == 0) {
            mlt_log_error(service,
                "The MLT Qt module requires a X11 environment.\n"
                "Please either run melt from an X session or use a fake X server like xvfb:\n"
                "xvfb-run -a melt (...)\n" );
            return false;
        }
#endif
        if (!mlt_properties_get(mlt_global_properties(), "qt_argv"))
            mlt_properties_set(mlt_global_properties(), "qt_argv", "MLT");
        static int argc = 1;
        static char* argv[] = { mlt_properties_get(mlt_global_properties(), "qt_argv") };
        new QApplication(argc, argv);
        const char *localename = mlt_properties_get_lcnumeric(MLT_SERVICE_PROPERTIES(service));
        QLocale::setDefault(QLocale(localename));
    }
    return true;
}

extern "C" {

static int get_image(mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable)
{
    auto producer = static_cast<mlt_producer>(mlt_frame_pop_service(frame));
    auto glax = static_cast<Glaxnimate*>(producer->child);

    if (mlt_properties_get_int(glax->properties(), "refresh")) {
        mlt_properties_clear(glax->properties(), "refresh");
        glax->open(mlt_properties_get(glax->properties(), "resource"));
        if (glax->duration() > mlt_properties_get_int(glax->properties(), "length")) {
            mlt_properties_set_int(glax->properties(), "length", glax->duration());
        }
    }

    return glax->getImage(frame, buffer, format, width, height, writable);
}

static int get_frame(mlt_producer producer, mlt_frame_ptr frame, int index)
{
    *frame = mlt_frame_init(MLT_PRODUCER_SERVICE(producer));
    mlt_properties frame_properties = MLT_FRAME_PROPERTIES( *frame );

    // Set frame properties
    mlt_properties_set_int(frame_properties, "progressive", 1);
    double force_ratio = mlt_properties_get_double(MLT_PRODUCER_PROPERTIES(producer), "force_aspect_ratio");
    if (force_ratio > 0.0)
        mlt_properties_set_double(frame_properties, "aspect_ratio", force_ratio);
    else
        mlt_properties_set_double(frame_properties, "aspect_ratio", 1.0);

    mlt_frame_set_position(*frame, mlt_producer_position(producer));
    mlt_frame_push_service(*frame, producer);
    mlt_frame_push_get_image(*frame, get_image);
    mlt_producer_prepare_next(producer);
    return 0;
}

static void producer_close(mlt_producer producer)
{
    delete static_cast<Glaxnimate*>(producer->child);
    producer->close = nullptr;
    mlt_producer_close(producer);
}

mlt_producer producer_glaxnimate_init(mlt_profile profile, mlt_service_type type, const char *id, char *arg)
{
    // Allocate the producer
    Glaxnimate* glax = new Glaxnimate();
    mlt_producer producer = (mlt_producer) calloc(1, sizeof( *producer ));

    createQApplicationIfNeeded(MLT_PRODUCER_SERVICE(producer));

    // If allocated and initializes
    if (glax && !mlt_producer_init(producer, glax) && glax->open(arg)) {
        glax->setProducer(producer);
        glax->m_profile = profile;
        producer->close = (mlt_destructor) producer_close;
        producer->get_frame = get_frame;

        auto properties = glax->properties();
        mlt_properties_set(properties, "resource", arg);
        mlt_properties_set(properties, "background", "#00000000");
        mlt_properties_set_int(properties, "aspect_ratio", 1);
        mlt_properties_set_int(properties, "progressive", 1);
        mlt_properties_set_int(properties, "seekable", 1);
        mlt_properties_set_int(properties, "meta.media.width", glax->size().width());
        mlt_properties_set_int(properties, "meta.media.height", glax->size().height());
        mlt_properties_set_int(properties, "meta.media.sample_aspect_num", 1);
        mlt_properties_set_int(properties, "meta.media.sample_aspect_den", 1);
        mlt_properties_set_double(properties, "meta.media.frame_rate", glax->fps());
        mlt_properties_set_int(properties, "out", glax->duration() - 1);
        mlt_properties_set_int(properties, "length", glax->duration());
        mlt_properties_set_int(properties, "first_frame", glax->firstFrame());
        mlt_properties_set(properties, "eof", "loop");
    }
    return producer;
}

static mlt_properties metadata(mlt_service_type type, const char *id, void *data)
{
    char file[PATH_MAX];
    const char *service_type = NULL;
    switch (type) {
        case mlt_service_producer_type:
            service_type = "producer";
            break;
        default:
            return NULL;
    }
    snprintf(file, PATH_MAX, "%s/glaxnimate/%s_%s.yml", mlt_environment("MLT_DATA"), service_type, id);
    return mlt_properties_parse_yaml(file);
}

MLT_REPOSITORY
{
    MLT_REGISTER(mlt_service_producer_type, "glaxnimate", producer_glaxnimate_init);
    MLT_REGISTER_METADATA(mlt_service_producer_type, "glaxnimate", metadata, NULL);
}

} // extern C
<|endoftext|>


<commit_before>//
// Copyright 2019 Sergei Blagodarin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <yttrium/image.h>
#include <yttrium/storage/source.h>
#include "../formats.h"

#include <csetjmp>
#include <cstdio> // <jpeglib.h> requires FILE declaration.

#include <jpeglib.h> // TODO: Load JPEG without libjpeg.

#ifndef NDEBUG
#	include <iomanip>
#	include <iostream>
#endif

namespace
{
	struct JpegErrorHandler
	{
		jpeg_error_mgr _error_mgr;
		std::jmp_buf _jmp_buf;
	};

	[[noreturn]] void error_callback(jpeg_common_struct* cinfo) {
		std::longjmp(reinterpret_cast<JpegErrorHandler*>(cinfo->err)->_jmp_buf, 1);
	}

#ifndef NDEBUG
	enum : std::uint8_t {
		TEM = 0x01,       // Temporary.
		SOF0 = 0xc0,      // Start-of-Frame (baseline DCT).
		SOF2 = 0xc2,      // Start-of-Frame (progressive DCT).
		DHT = 0xc4,       // Define-Huffman-Tables.
		DAC = 0xcc,       // Define-Arithmetic-Coding.
		RST = 0xd0,       // Restart (0-7).
		RST_mask = 0xf8,  //
		RST_value = 0x07, //
		SOI = 0xd8,       // Start-of-Image.
		EOI = 0xd9,       // End-of-Image.
		SOS = 0xda,       // Start-of-Scan.
		DQT = 0xdb,       // Defile-Quantization-Tables.
		DNL = 0xdc,       // Define-Number-of-Lines.
		DRI = 0xdd,       // Define-Restart-Interval.
		DHP = 0xde,       //
		EXP = 0xdf,       //
		APP = 0xe0,       // Application (0-15).
		APP_mask = 0xf0,  //
		APP_value = 0x0f, //
		COM = 0xfe,       // Comment.
	};

	class JpegDecoder
	{
	public:
		bool decode(const std::uint8_t* data, std::size_t size)
		{
			if (!decode_jpeg(data, size))
			{
				std::cerr << "<ERROR>\n";
				return false;
			}
			// TODO: Convert the loaded image to BGRA.
			return true;
		}

	private:
		std::size_t skip_segment(const std::uint8_t* data, const std::size_t size)
		{
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size)
				return 0;
			std::cerr << "\t<" << segment_size << " bytes>\n";
			return segment_size;
		}

		std::size_t decode_app(int type, const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "APP" << type << "\n";
			return skip_segment(data, size);
		}

		std::size_t decode_com(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "COM\n";
			return skip_segment(data, size);
		}

		std::size_t decode_dht(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DHT\n";
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size || segment_size < 3)
				return 0;
			const auto type = data[2] >> 4;
			const auto id = data[2] & 0xf;
			if (type > 1 || id > 1)
				return 0;
			std::cerr << "\ttype=" << (type ? "ac" : "dc") << '\n';
			std::cerr << "\tid=" << id << '\n';
			return segment_size;
		}

		std::size_t decode_dqt(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DQT\n";
			if (size < 67)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size != 67)
				return 0;
			const auto id = data[2];
			if (id > 1)
				return 0;
			for (std::size_t i = 0; i < 64; ++i)
				_quantization_tables[id][_dezigzag_table[i]] = data[3 + i];
			std::cerr << "\tid=" << int{ id } << '\n';
			std::cerr << "\tqt=\n";
			for (int i = 0; i < 8; ++i)
			{
				std::cerr << '\t';
				for  (int j = 0; j < 8; ++j)
					std::cerr << '\t' << int{ _quantization_tables[id][i * 8 + j] };
				std::cerr << '\n';
			}
			return segment_size;
		}

		std::size_t decode_dri(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DRI\n";
			return skip_segment(data, size);
		}

		std::size_t decode_sof0(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "SOF0\n";
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size || segment_size < 8)
				return 0;
			const auto color_bits = data[2];
			const auto width = data[3] << 8 | data[4];
			const auto height = data[5] << 8 | data[6];
			const auto components = std::size_t{ data[7] };
			if (segment_size != 8 + 3 * components)
				return 0;
			std::cerr << "\tcolor_bits=" << int{ color_bits } << '\n';
			std::cerr << "\twidth=" << width << '\n';
			std::cerr << "\theight=" << height << '\n';
			std::cerr << "\tcomponents=" << components << '\n';
			for (std::size_t i = 0; i < components; ++i)
			{
				const auto id = data[8 + 3 * i];
				const auto h = data[8 + 3 * i + 1] >> 4;
				const auto v = data[8 + 3 * i + 1] & 0xf;
				const auto qt = data[8 + 3 * i + 2];
				std::cerr << "\t[" << int{ id } << "]\n";
				std::cerr << "\t\th=" << h << '\n';
				std::cerr << "\t\tv=" << v << '\n';
				std::cerr << "\t\tqt=" << int{ qt } << '\n';
			}
			return segment_size;
		}

		std::size_t decode_sos(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "SOS\n";
			if (size < 3)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size)
				return 0;
			const auto components = std::size_t{ data[2] };
			if (segment_size != 6 + 2 * components)
				return 0;
			for (std::size_t i = 0; i < components; ++i)
			{
				const auto id = data[3 + 2 * i];
				const auto dc = data[3 + 2 * i + 1] >> 4;
				const auto ac = data[3 + 2 * i + 1] & 0xf;
				std::cerr << "\t[" << int{ id } << "]\n";
				std::cerr << "\t\tdc=" << dc << '\n';
				std::cerr << "\t\tac=" << ac << '\n';
			}
			if (data[3 + 2 * components] != 0 || data[3 + 2 * components + 1] != 63 || data[3 + 2 * components + 2] != 0)
				return 0;
			const auto payload_size = decode_payload(data + segment_size, size - segment_size);
			if (!payload_size)
				return 0;
			return segment_size + payload_size;
		}

		std::size_t decode_payload(const std::uint8_t*, std::size_t)
		{
			std::cerr << "<NOT IMPLEMENTED>\n";
			return 0;
		}

		std::size_t decode_segment(std::uint8_t marker, const std::uint8_t* data, std::size_t size)
		{
			switch (marker)
			{
			case SOF0: return decode_sof0(data, size);
			case DHT: return decode_dht(data, size);
			case SOS: return decode_sos(data, size);
			case DQT: return decode_dqt(data, size);
			case DRI: return decode_dri(data, size);
			case COM: return decode_com(data, size);
			default:
				if ((marker & APP_mask) == APP)
					return decode_app(marker & APP_value, data, size);
				return 0;
			}
		}

		bool decode_jpeg(const std::uint8_t* data, std::size_t size)
		{
			if (size < 2 || data[0] != 0xff || data[1] != SOI)
				return false;
			data += 2;
			size -= 2;
			while (size > 0)
			{
				if (size < 2 || data[0] != 0xff)
					return false;
				const auto marker = data[1];
				if (marker == EOI)
					return true; // TODO: Return false if the buffer hasn't been decoded.
				data += 2;
				size -= 2;
				const auto segment_size = decode_segment(marker, data, size);
				if (!segment_size)
					return false; // TODO: Return true if the buffer has been decoded.
				data += segment_size;
				size -= segment_size;
			}
			return false;
		}

	private:
		std::uint8_t _quantization_tables[2][64];

		static const std::uint8_t _dezigzag_table[64];
	};

	const std::uint8_t JpegDecoder::_dezigzag_table[64]{
		0, 1, 8, 16, 9, 2, 3, 10,
		17, 24, 32, 25, 18, 11, 4, 5,
		12, 19, 26, 33, 40, 48, 41, 34,
		27, 20, 13, 6, 7, 14, 21, 28,
		35, 42, 49, 56, 57, 50, 43, 36,
		29, 22, 15, 23, 30, 37, 44, 51,
		58, 59, 52, 45, 38, 31, 39, 46,
		53, 60, 61, 54, 47, 55, 62, 63
	};
#endif
}

namespace Yttrium
{
	bool read_jpeg(const Source& source, ImageInfo& info, Buffer& buffer)
	{
#ifndef NDEBUG
		{
			const auto jpeg = source.to_buffer();
			JpegDecoder{}.decode(jpeg.begin(), jpeg.size());
		}
#endif

		auto source_buffer = source.to_buffer(); // Some JPEG libraries require non-const source buffer.
		if (source_buffer.size() > std::numeric_limits<unsigned long>::max())
			return false;

		JpegErrorHandler error_handler;
		error_handler._error_mgr.error_exit = ::error_callback;
		if (setjmp(error_handler._jmp_buf))
			return false;

		jpeg_decompress_struct decompressor;
		decompressor.err = ::jpeg_std_error(&error_handler._error_mgr);
		::jpeg_create_decompress(&decompressor);
		if (setjmp(error_handler._jmp_buf))
		{
			::jpeg_destroy_decompress(&decompressor);
			return false;
		}

		::jpeg_mem_src(&decompressor, &source_buffer[0], static_cast<unsigned long>(source_buffer.size()));

		::jpeg_read_header(&decompressor, TRUE);

		decompressor.out_color_space = JCS_RGB;

		::jpeg_calc_output_dimensions(&decompressor);

		info = { decompressor.output_width, decompressor.output_height, PixelFormat::Rgb24 };

		try
		{
			buffer.reset(info.frame_size());
		}
		catch (const std::bad_alloc&)
		{
			::jpeg_destroy_decompress(&decompressor);
			throw;
		}

		::jpeg_start_decompress(&decompressor);
		for (auto scanline = &buffer[0]; decompressor.output_scanline < decompressor.output_height; scanline += info.stride())
			::jpeg_read_scanlines(&decompressor, &scanline, 1);
		::jpeg_finish_decompress(&decompressor);

		if (setjmp(error_handler._jmp_buf))
			return false;

		::jpeg_destroy_decompress(&decompressor);

		return true;
	}
}
<commit_msg>Improve JPEG analysis<commit_after>//
// Copyright 2019 Sergei Blagodarin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <yttrium/image.h>
#include <yttrium/storage/source.h>
#include "../formats.h"

#include <csetjmp>
#include <cstdio> // <jpeglib.h> requires FILE declaration.

#include <jpeglib.h> // TODO: Load JPEG without libjpeg.

#ifndef NDEBUG
#	include <iomanip>
#	include <iostream>
#endif

namespace
{
	struct JpegErrorHandler
	{
		jpeg_error_mgr _error_mgr;
		std::jmp_buf _jmp_buf;
	};

	[[noreturn]] void error_callback(jpeg_common_struct* cinfo) {
		std::longjmp(reinterpret_cast<JpegErrorHandler*>(cinfo->err)->_jmp_buf, 1);
	}

#ifndef NDEBUG
	enum : std::uint8_t {
		TEM = 0x01,       // Temporary.
		SOF0 = 0xc0,      // Start-of-Frame (baseline DCT).
		SOF2 = 0xc2,      // Start-of-Frame (progressive DCT).
		DHT = 0xc4,       // Define-Huffman-Tables.
		DAC = 0xcc,       // Define-Arithmetic-Coding.
		RST = 0xd0,       // Restart (0-7).
		RST_mask = 0xf8,  //
		RST_value = 0x07, //
		SOI = 0xd8,       // Start-of-Image.
		EOI = 0xd9,       // End-of-Image.
		SOS = 0xda,       // Start-of-Scan.
		DQT = 0xdb,       // Defile-Quantization-Tables.
		DNL = 0xdc,       // Define-Number-of-Lines.
		DRI = 0xdd,       // Define-Restart-Interval.
		DHP = 0xde,       //
		EXP = 0xdf,       //
		APP = 0xe0,       // Application (0-15).
		APP_mask = 0xf0,  //
		APP_value = 0x0f, //
		COM = 0xfe,       // Comment.
	};

	class JpegDecoder
	{
	public:
		bool decode(const std::uint8_t* data, std::size_t size)
		{
			if (!decode_jpeg(data, size))
			{
				std::cerr << "<ERROR>\n";
				return false;
			}
			// TODO: Convert the loaded image to BGRA.
			return true;
		}

	private:
		std::size_t skip_segment(const std::uint8_t* data, const std::size_t size)
		{
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size)
				return 0;
			std::cerr << "\t<" << segment_size << " bytes>\n";
			return segment_size;
		}

		std::size_t decode_app(int type, const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "APP" << type << ":\n";
			return skip_segment(data, size);
		}

		std::size_t decode_com(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "COM:\n";
			return skip_segment(data, size);
		}

		std::size_t decode_dht(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DHT:\n";
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size || segment_size < 19)
				return 0;
			const auto type = data[2] >> 4;
			const auto id = data[2] & 0xf;
			if (type > 1 || id > 1)
				return 0;
			const std::uint8_t* bits = data + 3;
			std::size_t length = 0;
			for (std::size_t i = 0; i < 16; ++i)
				length += bits[i];
			if (segment_size != 19 + length)
				return 0;
			std::cerr << "\ttype=" << (type ? "ac" : "dc") << '\n';
			std::cerr << "\tid=" << id << '\n';
			std::cerr << "\tbits";
			for (std::size_t i = 0; i < 16; ++i)
				std::cerr << (i ? ',' : '=') << int{ bits[i] };
			std::cerr << '\n';
			auto huffman_values = bits + 16;
			for (std::size_t i = 0; i < 16; ++i)
			{
				if (!bits[i])
					continue;
				std::cerr << '\t';
				for (std::size_t j = 0; j < bits[i]; ++j)
					std::cerr << (j ? ',' : '\t') << int{ huffman_values[j] };
				huffman_values += bits[i];
				std::cerr << '\n';
			}
			return segment_size;
		}

		std::size_t decode_dqt(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DQT:\n";
			if (size < 67)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size != 67)
				return 0;
			const auto id = data[2];
			if (id > 1)
				return 0;
			for (std::size_t i = 0; i < 64; ++i)
				_quantization_tables[id][_dezigzag_table[i]] = data[3 + i];
			std::cerr << "\tid=" << int{ id } << '\n';
			std::cerr << "\tqt:\n";
			for (int i = 0; i < 8; ++i)
			{
				std::cerr << '\t';
				for  (int j = 0; j < 8; ++j)
					std::cerr << '\t' << int{ _quantization_tables[id][i * 8 + j] };
				std::cerr << '\n';
			}
			return segment_size;
		}

		std::size_t decode_dri(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "DRI\n";
			return skip_segment(data, size);
		}

		std::size_t decode_sof0(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "SOF0:\n";
			if (size < 2)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size || segment_size < 8)
				return 0;
			const auto color_bits = data[2];
			const auto width = data[3] << 8 | data[4];
			const auto height = data[5] << 8 | data[6];
			const auto components = std::size_t{ data[7] };
			if (segment_size != 8 + 3 * components)
				return 0;
			std::cerr << "\tcolor_bits=" << int{ color_bits } << '\n';
			std::cerr << "\twidth=" << width << '\n';
			std::cerr << "\theight=" << height << '\n';
			std::cerr << "\tcomponents=" << components << '\n';
			for (std::size_t i = 0; i < components; ++i)
			{
				const auto id = data[8 + 3 * i];
				const auto h = data[8 + 3 * i + 1] >> 4;
				const auto v = data[8 + 3 * i + 1] & 0xf;
				const auto qt = data[8 + 3 * i + 2];
				std::cerr << "\t\t" << int{ id } << ":\n";
				std::cerr << "\t\t\th=" << h << '\n';
				std::cerr << "\t\t\tv=" << v << '\n';
				std::cerr << "\t\t\tqt=" << int{ qt } << '\n';
			}
			return segment_size;
		}

		std::size_t decode_sos(const std::uint8_t* data, const std::size_t size)
		{
			std::cerr << "SOS:\n";
			if (size < 3)
				return 0;
			const auto segment_size = static_cast<std::uint16_t>(data[0] << 8 | data[1]);
			if (segment_size > size)
				return 0;
			const auto components = std::size_t{ data[2] };
			if (segment_size != 6 + 2 * components)
				return 0;
			for (std::size_t i = 0; i < components; ++i)
			{
				const auto id = data[3 + 2 * i];
				const auto dc = data[3 + 2 * i + 1] >> 4;
				const auto ac = data[3 + 2 * i + 1] & 0xf;
				std::cerr << '\t' << int{ id } << ":\n";
				std::cerr << "\t\tdc=" << dc << '\n';
				std::cerr << "\t\tac=" << ac << '\n';
			}
			if (data[3 + 2 * components] != 0 || data[3 + 2 * components + 1] != 63 || data[3 + 2 * components + 2] != 0)
				return 0;
			const auto payload_size = decode_payload(data + segment_size, size - segment_size);
			if (!payload_size)
				return 0;
			return segment_size + payload_size;
		}

		std::size_t decode_payload(const std::uint8_t*, std::size_t)
		{
			std::cerr << "<NOT IMPLEMENTED>\n";
			return 0;
		}

		std::size_t decode_segment(std::uint8_t marker, const std::uint8_t* data, std::size_t size)
		{
			switch (marker)
			{
			case SOF0: return decode_sof0(data, size);
			case DHT: return decode_dht(data, size);
			case SOS: return decode_sos(data, size);
			case DQT: return decode_dqt(data, size);
			case DRI: return decode_dri(data, size);
			case COM: return decode_com(data, size);
			default:
				if ((marker & APP_mask) == APP)
					return decode_app(marker & APP_value, data, size);
				return 0;
			}
		}

		bool decode_jpeg(const std::uint8_t* data, std::size_t size)
		{
			if (size < 2 || data[0] != 0xff || data[1] != SOI)
				return false;
			data += 2;
			size -= 2;
			while (size > 0)
			{
				if (size < 2 || data[0] != 0xff)
					return false;
				const auto marker = data[1];
				if (marker == EOI)
					return true; // TODO: Return false if the buffer hasn't been decoded.
				data += 2;
				size -= 2;
				const auto segment_size = decode_segment(marker, data, size);
				if (!segment_size)
					return false; // TODO: Return true if the buffer has been decoded.
				data += segment_size;
				size -= segment_size;
			}
			return false;
		}

	private:
		std::uint8_t _quantization_tables[2][64];

		static const std::uint8_t _dezigzag_table[64];
	};

	const std::uint8_t JpegDecoder::_dezigzag_table[64]{
		0, 1, 8, 16, 9, 2, 3, 10,
		17, 24, 32, 25, 18, 11, 4, 5,
		12, 19, 26, 33, 40, 48, 41, 34,
		27, 20, 13, 6, 7, 14, 21, 28,
		35, 42, 49, 56, 57, 50, 43, 36,
		29, 22, 15, 23, 30, 37, 44, 51,
		58, 59, 52, 45, 38, 31, 39, 46,
		53, 60, 61, 54, 47, 55, 62, 63
	};
#endif
}

namespace Yttrium
{
	bool read_jpeg(const Source& source, ImageInfo& info, Buffer& buffer)
	{
#ifndef NDEBUG
		{
			const auto jpeg = source.to_buffer();
			JpegDecoder{}.decode(jpeg.begin(), jpeg.size());
		}
#endif

		auto source_buffer = source.to_buffer(); // Some JPEG libraries require non-const source buffer.
		if (source_buffer.size() > std::numeric_limits<unsigned long>::max())
			return false;

		JpegErrorHandler error_handler;
		error_handler._error_mgr.error_exit = ::error_callback;
		if (setjmp(error_handler._jmp_buf))
			return false;

		jpeg_decompress_struct decompressor;
		decompressor.err = ::jpeg_std_error(&error_handler._error_mgr);
		::jpeg_create_decompress(&decompressor);
		if (setjmp(error_handler._jmp_buf))
		{
			::jpeg_destroy_decompress(&decompressor);
			return false;
		}

		::jpeg_mem_src(&decompressor, &source_buffer[0], static_cast<unsigned long>(source_buffer.size()));

		::jpeg_read_header(&decompressor, TRUE);

		decompressor.out_color_space = JCS_RGB;

		::jpeg_calc_output_dimensions(&decompressor);

		info = { decompressor.output_width, decompressor.output_height, PixelFormat::Rgb24 };

		try
		{
			buffer.reset(info.frame_size());
		}
		catch (const std::bad_alloc&)
		{
			::jpeg_destroy_decompress(&decompressor);
			throw;
		}

		::jpeg_start_decompress(&decompressor);
		for (auto scanline = &buffer[0]; decompressor.output_scanline < decompressor.output_height; scanline += info.stride())
			::jpeg_read_scanlines(&decompressor, &scanline, 1);
		::jpeg_finish_decompress(&decompressor);

		if (setjmp(error_handler._jmp_buf))
			return false;

		::jpeg_destroy_decompress(&decompressor);

		return true;
	}
}
<|endoftext|>


<commit_before>//*****************************************************************************
// Copyright 2017-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#pragma once

#include <chrono>
#include <cstdint>
#include <set>

#define TBB_PREVIEW_GLOBAL_CONTROL 1
#define TBB_PREVIEW_FLOW_GRAPH_TRACE 1
#include <tbb/flow_graph.h>
#include <tbb/global_control.h>
#include <tbb/task_scheduler_init.h>
#include "ngraph/op/experimental/compiled_kernel.hpp"

#ifdef NGRAPH_MLIR_ENABLE
#include "contrib/mlir/compiler.hpp"
#endif

namespace mkldnn
{
    class primitive;
}

namespace ngraph
{
    namespace runtime
    {
        class AlignedBuffer;
    }
    class State;
}

namespace ngraph
{
    namespace runtime
    {
        namespace cpu
        {
            typedef std::chrono::high_resolution_clock Clock;
            typedef std::chrono::time_point<Clock> Timestamp;
            typedef std::chrono::microseconds Timescale;

            extern "C" {
            struct CPURuntimeContext
            {
                int64_t* op_durations;
                bool* p_en;
                bool first_iteration;
                // stores tensor pointers
                std::vector<void*> buffer_data;
                std::vector<mkldnn::primitive*> mkldnn_primitives;
                std::vector<AlignedBuffer*> memory_buffers;
                std::vector<char*> mkldnn_workspaces;
                tbb::flow::graph* G;
                tbb::global_control* c;
                State* const* states;
                std::set<size_t> breakpoints;
                size_t pc;
#ifdef NGRAPH_MLIR_ENABLE
                /// Maps CompiledKernel nodes to their MLIR compiler
                /// The MLIR compiler caches the compiled code on the first invocation,
                /// and may in the future support re-compilation
                std::unordered_map<ngraph::op::CompiledKernel*,
                                   ngraph::runtime::ngmlir::MLIRCompiler>
                    mlir_compilers;
#endif
            };
            }

            struct CPUExecutionContext
            {
                int arena;
            };

            typedef std::function<void(CPURuntimeContext*, CPUExecutionContext*)> CPUKernelFunctor;
        }
    }
}
<commit_msg>style-apply<commit_after>//*****************************************************************************
// Copyright 2017-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#pragma once

#include <chrono>
#include <cstdint>
#include <set>

#define TBB_PREVIEW_GLOBAL_CONTROL 1
#define TBB_PREVIEW_FLOW_GRAPH_TRACE 1
#include <tbb/flow_graph.h>
#include <tbb/global_control.h>
#include <tbb/task_scheduler_init.h>
#include "ngraph/op/experimental/compiled_kernel.hpp"

#ifdef NGRAPH_MLIR_ENABLE
#include "contrib/mlir/compiler.hpp"
#endif

namespace mkldnn
{
    class primitive;
}

namespace ngraph
{
    namespace runtime
    {
        class AlignedBuffer;
    }
    class State;
}

namespace ngraph
{
    namespace runtime
    {
        namespace cpu
        {
            typedef std::chrono::high_resolution_clock Clock;
            typedef std::chrono::time_point<Clock> Timestamp;
            typedef std::chrono::microseconds Timescale;

            extern "C" {
            struct CPURuntimeContext
            {
                int64_t* op_durations;
                bool* p_en;
                bool first_iteration;
                // stores tensor pointers
                std::vector<void*> buffer_data;
                std::vector<mkldnn::primitive*> mkldnn_primitives;
                std::vector<AlignedBuffer*> memory_buffers;
                std::vector<char*> mkldnn_workspaces;
                tbb::flow::graph* G;
                tbb::global_control* c;
                State* const* states;
                std::set<size_t> breakpoints;
                size_t pc;
#ifdef NGRAPH_MLIR_ENABLE
                /// Maps CompiledKernel nodes to their MLIR compiler
                /// The MLIR compiler caches the compiled code on the first invocation,
                /// and may in the future support re-compilation
                std::unordered_map<ngraph::op::CompiledKernel*,
                                   ngraph::runtime::ngmlir::MLIRCompiler>
                    mlir_compilers;
#endif
            };
            }

            struct CPUExecutionContext
            {
                int arena;
            };

            typedef std::function<void(CPURuntimeContext*, CPUExecutionContext*)> CPUKernelFunctor;
        }
    }
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "elements/element.h"

#include <cassert>
#include <iostream>

#include "elements/package.h"

namespace elements {

void Element::serialize(Element::Json &a_json)
{
  a_json["id"] = m_id;
  a_json["name"] = m_name;
  a_json["type"] = type();
  auto &node = a_json["node"];
  node["position"]["x"] = m_position.x;
  node["position"]["y"] = m_position.y;
  node["iconify"] = m_isIconified;
  auto &sockets = a_json["sockets"];
  auto &inputs = sockets["inputs"];
  inputs["min"] = m_minInputs;
  inputs["max"] = m_maxInputs;
  auto &outputs = sockets["outputs"];
  outputs["min"] = m_minOutputs;
  outputs["max"] = m_maxOutputs;
}

void Element::deserialize(Json const &a_json)
{
  std::cout << __PRETTY_FUNCTION__ << '>' << std::endl;

  auto const tempId = a_json["id"].get<size_t>();
  auto const tempName = a_json["name"].get<std::string>();
  auto const tempPosition = a_json["position"];
  auto const tempIconify = a_json["iconify"].get<bool>();
  auto const tempPositionX = tempPosition["x"].get<double>();
  auto const tempPositionY = tempPosition["y"].get<double>();
  auto const tempInputs = a_json["inputs"];
  auto const tempMinInputs = tempInputs["min"].get<uint8_t>();
  auto const tempMaxInputs = tempInputs["max"].get<uint8_t>();
  auto const tempInputsSockets = tempInputs["sockets"];
  auto const tempOutputs = a_json["outputs"];
  auto const tempMinOutputs = tempOutputs["min"].get<uint8_t>();
  auto const tempMaxOutputs = tempOutputs["max"].get<uint8_t>();
  auto const tempOutputsSockets = tempOutputs["sockets"];

  assert(id() == tempId);
  setName(tempName);
  setPosition(tempPositionX, tempPositionY);
  clearInputs();
  clearOutputs();
  setMinInputs(tempMinInputs);
  setMaxInputs(tempMaxInputs);
  setMinOutputs(tempMinOutputs);
  setMaxOutputs(tempMaxOutputs);
  iconify(tempIconify);

  auto add_socket = [&](Json const &a_socket, bool const a_input, uint8_t &a_socketCount) {
    auto const socketId = a_socket["socket"].get<uint8_t>();
    auto const socketStringType = a_socket["type"].get<std::string>();
    auto const socketName = a_socket["name"].get<std::string>();

    assert(a_socketCount == socketId);

    ValueType const socketType = [](std::string_view const a_type) {
      if (a_type == "bool")
        return ValueType::eBool;
      else if (a_type == "int")
        return ValueType::eInt;
      else if (a_type == "float")
        return ValueType::eFloat;
      assert(false && "Wrong socket type");
    }(socketStringType);

    a_input ? addInput(socketType, socketName) : addOutput(socketType, socketName);
    a_socketCount++;
  };

  uint8_t inputsCount{}, outputsCount{};
  for (auto &&socket : tempInputsSockets) add_socket(socket, true, inputsCount);
  for (auto &&socket : tempOutputsSockets) add_socket(socket, false, outputsCount);

  std::cout << __PRETTY_FUNCTION__ << '<' << std::endl;
}

bool Element::addInput(Element::ValueType const a_type, std::string const a_name)
{
  if (m_inputs.size() + 1 > m_maxInputs) return false;

  Input input{};
  input.name = a_name;
  input.type = a_type;
  m_inputs.emplace_back(input);

  return true;
}

void Element::clearInputs()
{
  m_inputs.clear();
}

bool Element::addOutput(Element::ValueType const a_type, std::string const a_name)
{
  if (m_outputs.size() + 1 > m_maxOutputs) return false;

  Output output{};
  output.name = a_name;
  output.type = a_type;
  m_outputs.emplace_back(output);

  return true;
}

void Element::clearOutputs()
{
  m_outputs.clear();
}

bool Element::connect(size_t const a_sourceId, uint8_t const a_outputId, uint8_t const a_inputId)
{
  return m_package->connect(a_sourceId, a_outputId, m_id, a_inputId);
}

void Element::setMinInputs(uint8_t const a_min)
{
  if (a_min > m_maxInputs) return;
  m_minInputs = a_min;
}

void Element::setMaxInputs(uint8_t const a_max)
{
  if (a_max < m_minInputs) return;
  m_maxInputs = a_max;
}

void Element::setMinOutputs(uint8_t const a_min)
{
  if (a_min > m_maxOutputs) return;
  m_minOutputs = a_min;
}

void Element::setMaxOutputs(uint8_t const a_max)
{
  if (a_max < m_minOutputs) return;
  m_maxOutputs = a_max;
}

} // namespace elements
<commit_msg>Silence GCC on MinGW<commit_after>// MIT License
//
// Copyright (c) 2017 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "elements/element.h"

#include <cassert>
#include <iostream>

#include "elements/package.h"

namespace elements {

void Element::serialize(Element::Json &a_json)
{
  a_json["id"] = m_id;
  a_json["name"] = m_name;
  a_json["type"] = type();
  auto &node = a_json["node"];
  node["position"]["x"] = m_position.x;
  node["position"]["y"] = m_position.y;
  node["iconify"] = m_isIconified;
  auto &sockets = a_json["sockets"];
  auto &inputs = sockets["inputs"];
  inputs["min"] = m_minInputs;
  inputs["max"] = m_maxInputs;
  auto &outputs = sockets["outputs"];
  outputs["min"] = m_minOutputs;
  outputs["max"] = m_maxOutputs;
}

void Element::deserialize(Json const &a_json)
{
  std::cout << __PRETTY_FUNCTION__ << '>' << std::endl;

  auto const tempId = a_json["id"].get<size_t>();
  auto const tempName = a_json["name"].get<std::string>();
  auto const tempPosition = a_json["position"];
  auto const tempIconify = a_json["iconify"].get<bool>();
  auto const tempPositionX = tempPosition["x"].get<double>();
  auto const tempPositionY = tempPosition["y"].get<double>();
  auto const tempInputs = a_json["inputs"];
  auto const tempMinInputs = tempInputs["min"].get<uint8_t>();
  auto const tempMaxInputs = tempInputs["max"].get<uint8_t>();
  auto const tempInputsSockets = tempInputs["sockets"];
  auto const tempOutputs = a_json["outputs"];
  auto const tempMinOutputs = tempOutputs["min"].get<uint8_t>();
  auto const tempMaxOutputs = tempOutputs["max"].get<uint8_t>();
  auto const tempOutputsSockets = tempOutputs["sockets"];

  assert(id() == tempId);
  setName(tempName);
  setPosition(tempPositionX, tempPositionY);
  clearInputs();
  clearOutputs();
  setMinInputs(tempMinInputs);
  setMaxInputs(tempMaxInputs);
  setMinOutputs(tempMinOutputs);
  setMaxOutputs(tempMaxOutputs);
  iconify(tempIconify);

  auto add_socket = [&](Json const &a_socket, bool const a_input, uint8_t &a_socketCount) {
    auto const socketId = a_socket["socket"].get<uint8_t>();
    auto const socketStringType = a_socket["type"].get<std::string>();
    auto const socketName = a_socket["name"].get<std::string>();

    assert(a_socketCount == socketId);

    ValueType const socketType = [](std::string_view const a_type) {
      if (a_type == "bool")
        return ValueType::eBool;
      else if (a_type == "int")
        return ValueType::eInt;
      else if (a_type == "float")
        return ValueType::eFloat;
      assert(false && "Wrong socket type");
      return ValueType::eBool;
    }(socketStringType);

    a_input ? addInput(socketType, socketName) : addOutput(socketType, socketName);
    a_socketCount++;
  };

  uint8_t inputsCount{}, outputsCount{};
  for (auto &&socket : tempInputsSockets) add_socket(socket, true, inputsCount);
  for (auto &&socket : tempOutputsSockets) add_socket(socket, false, outputsCount);

  std::cout << __PRETTY_FUNCTION__ << '<' << std::endl;
}

bool Element::addInput(Element::ValueType const a_type, std::string const a_name)
{
  if (m_inputs.size() + 1 > m_maxInputs) return false;

  Input input{};
  input.name = a_name;
  input.type = a_type;
  m_inputs.emplace_back(input);

  return true;
}

void Element::clearInputs()
{
  m_inputs.clear();
}

bool Element::addOutput(Element::ValueType const a_type, std::string const a_name)
{
  if (m_outputs.size() + 1 > m_maxOutputs) return false;

  Output output{};
  output.name = a_name;
  output.type = a_type;
  m_outputs.emplace_back(output);

  return true;
}

void Element::clearOutputs()
{
  m_outputs.clear();
}

bool Element::connect(size_t const a_sourceId, uint8_t const a_outputId, uint8_t const a_inputId)
{
  return m_package->connect(a_sourceId, a_outputId, m_id, a_inputId);
}

void Element::setMinInputs(uint8_t const a_min)
{
  if (a_min > m_maxInputs) return;
  m_minInputs = a_min;
}

void Element::setMaxInputs(uint8_t const a_max)
{
  if (a_max < m_minInputs) return;
  m_maxInputs = a_max;
}

void Element::setMinOutputs(uint8_t const a_min)
{
  if (a_min > m_maxOutputs) return;
  m_minOutputs = a_min;
}

void Element::setMaxOutputs(uint8_t const a_max)
{
  if (a_max < m_minOutputs) return;
  m_maxOutputs = a_max;
}

} // namespace elements
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Bernhard Firner and Rutgers University
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * or visit http://www.gnu.org/licenses/gpl-2.0.html
 */

/*******************************************************************************
 * Helper classes that make it easier for world models to support standing
 * queries.
 ******************************************************************************/

#ifndef __STANDING_QUERY_HPP__
#define __STANDING_QUERY_HPP__

#include <algorithm>
#include <list>
#include <map>
#include <mutex>
#include <set>
#include <string>
#include <vector>

#include <owl/world_model_protocol.hpp>

//TODO In the future C++11 support for regex should be used over these POSIX
//regex c headers.
#include <sys/types.h>
#include <regex.h>

/**
 * Standing queries are used when the same query would be repeated many times.
 * The standing query call returns an object that can be used to retrieve
 * any updates to the query since the last time it was checked. If this object
 * is destroyed then it ends the standing query.
 */
class StandingQuery {
  public:
    typedef std::map<world_model::URI, std::vector<world_model::Attribute>> world_state;
  private:
    //Need to lock this mutex before changing the current state
    std::mutex data_mutex;
    //Place where the world model will store data for this standing query.
    world_state cur_state;
    //Remember which URIs and attributes match this query
    //For attributes remember which of the desired attributes they matched
    std::map<world_model::URI, bool> uri_accepted;
    std::map<world_model::URI, std::set<size_t>> uri_matches;
    //Remember accepted attributes so that the standing query can notify
    //the subscriber when identifiers and attributes are expired or deleted
    //The data_mutex must be locked before modifying this structure
    std::map<world_model::URI, std::set<std::u16string>> current_matches;
    ///This contains empty sets for entries without matches
    std::map<std::u16string, std::set<size_t>> attribute_accepted;
    world_model::URI uri_pattern;
    std::vector<std::u16string> desired_attributes;
    regex_t uri_regex;
    std::map<std::u16string, regex_t> attr_regex;
    bool get_data;
    bool regex_valid;

    ///Mutex for the origin_attributes map
    static std::mutex origin_attr_mutex;
    ///Attributes that different origin's will offer
    static std::map<std::u16string, std::set<std::u16string>> origin_attributes;

    //No copying or assignment. Deleting the copy constructor prevents passing
    //by value which would cause trouble with the compiled regex and the mutex.
    StandingQuery& operator=(const StandingQuery&) = delete;
    StandingQuery(const StandingQuery&) = delete;

    //Partial matches (some attributes matched, but not all)
    //Partial matches are stored so that when a complete match is made they
    //can be sent and also so that a match can be quickly rechecked if
    //attributes are deleted or expired.
    world_state partial;
  public:
    /**
     * Update the list of attributes provided by origins.
     */
    static void addOriginAttributes(std::u16string& origin, std::set<std::u16string>& attributes);

    StandingQuery(const world_model::URI& uri,
        const std::vector<std::u16string>& desired_attributes, bool get_data = true);

    ///Free memory from regular expressions
    ~StandingQuery();

    ///r-value copy constructor
    StandingQuery(StandingQuery&& other);

    ///r-value assignment
    StandingQuery& operator=(StandingQuery&& other);

    /**
     * Return true if this origin has data that this standing query might
     * be interested in and false otherwise.
     */
    bool interestingOrigin(std::u16string& origin);

    /**
     * Return a subset of the world state that this query is interested in.
     * Also remember partial matches so that later calls to showInterested
     * do not need to provide the entire world state. This call can
     * quickly check if any data is interesting by seeing if the origin
     * itself is interesting, but will skip this if the world state
     * contains data from multiple origins.
     */
    world_state showInterested(world_state& ws, bool multiple_origins = false);

    /**
     * Return a subset of the world state that this query is interested in.
     * This is similar to showInterested but enforced exact string matches
     * for transient names and does not store transients as partial results.
     * This call can * quickly check if any data is interesting by seeing if
     * the origin itself is interesting, but will skip this if the world state
     * contains data from multiple origins.
     */
    world_state showInterestedTransient(world_state& ws, bool multiple_origins = false);

    /**
     * Return a subset of the world state that would be modified if the
     * supplied URI is expired or deleted.
     */
    void expireURI(world_model::URI uri, world_model::grail_time);

    /**
     * Return a subset of the world state that would be modified if the
     * supplied URI attributes are expired or deleted.
     */
    void expireURIAttributes(world_model::URI uri,
        const std::vector<world_model::Attribute>& entries,
        world_model::grail_time);

    /**
     * Insert data in a thread safe way
     * Data is not checked to see if it matches the given
     * query first so the caller must check that first, on their own
     * or with the showInterested function call.
     */
    void insertData(world_state& ws);

    ///Clear the current data and return what it stored. Thread safe.
    world_state getData();
};

class QueryAccessor {
  private:
    /**
     * Need to remember the source list to remove the iterator
     * when this object is destroyed.
     */
    std::list<StandingQuery>* source;
    std::mutex* list_mutex;
    ///List iterators are safe to changes in the underlying list
    std::list<StandingQuery>::iterator data;

    //No copying or assignment. Deleting the copy constructor prevents passing
    //by value would cause trouble when the destructor removes this iterator
    //from the source list.
    QueryAccessor& operator=(const QueryAccessor&) = delete;
    QueryAccessor(const QueryAccessor&) = delete;

  public:
    /**
     * Gets updates and clears the current state
     * This should be thread safe in the StandingQuery class
     */
    StandingQuery::world_state getUpdates();

    QueryAccessor(std::list<StandingQuery>* source, std::mutex* list_mutex,
        std::list<StandingQuery>::iterator data);

    ///Remove the iterator from the source list.
    ~QueryAccessor();

    ///r-value copy constructor
    QueryAccessor(QueryAccessor&& other);

    ///r-value assignment
    QueryAccessor& operator=(QueryAccessor&& other);
};

#endif //ifndef __STANDING_QUERY_HPP__

<commit_msg>Putting in scaffolding for mergine the StandingQuery and QueryAccessor classes.<commit_after>/*
 * Copyright (c) 2012 Bernhard Firner and Rutgers University
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * or visit http://www.gnu.org/licenses/gpl-2.0.html
 */

/*******************************************************************************
 * Helper classes that make it easier for world models to support standing
 * queries.
 ******************************************************************************/

#ifndef __STANDING_QUERY_HPP__
#define __STANDING_QUERY_HPP__

#include <algorithm>
#include <list>
#include <map>
#include <mutex>
#include <set>
#include <string>
#include <vector>

#include <owl/world_model_protocol.hpp>

//Lock-free queue for pushing and consuming data
#include <boost/lockfree/queue.hpp>

//TODO In the future C++11 support for regex should be used over these POSIX
//regex c headers.
#include <sys/types.h>
#include <regex.h>

/**
 * Standing queries are used when the same query would be repeated many times.
 * The standing query call returns an object that can be used to retrieve
 * any updates to the query since the last time it was checked. If this object
 * is destroyed then it ends the standing query.
 */
class StandingQuery {
  public:
    typedef std::map<world_model::URI, std::vector<world_model::Attribute>> world_state;
  private:
    //Need to lock this mutex before changing the current state
    std::mutex data_mutex;
    //Place where the world model will store data for this standing query.
    world_state cur_state;
    //Remember which URIs and attributes match this query
    //For attributes remember which of the desired attributes they matched
    std::map<world_model::URI, bool> uri_accepted;
    std::map<world_model::URI, std::set<size_t>> uri_matches;
    //Remember accepted attributes so that the standing query can notify
    //the subscriber when identifiers and attributes are expired or deleted
    //The data_mutex must be locked before modifying this structure
    std::map<world_model::URI, std::set<std::u16string>> current_matches;
    ///This contains empty sets for entries without matches
    std::map<std::u16string, std::set<size_t>> attribute_accepted;
    world_model::URI uri_pattern;
    std::vector<std::u16string> desired_attributes;
    regex_t uri_regex;
    std::map<std::u16string, regex_t> attr_regex;
    bool get_data;
    bool regex_valid;

    ///Mutex for the origin_attributes map
    static std::mutex origin_attr_mutex;
    ///Attributes that different origin's will offer
    static std::map<std::u16string, std::set<std::u16string>> origin_attributes;

    //No copying or assignment. Deleting the copy constructor prevents passing
    //by value which would cause trouble with the compiled regex and the mutex.
    StandingQuery& operator=(const StandingQuery&) = delete;
    StandingQuery(const StandingQuery&) = delete;

    //Partial matches (some attributes matched, but not all)
    //Partial matches are stored so that when a complete match is made they
    //can be sent and also so that a match can be quickly rechecked if
    //attributes are deleted or expired.
    world_state partial;
  public:
    /**
     * Update the list of attributes provided by origins.
     */
    static void addOriginAttributes(std::u16string& origin, std::set<std::u16string>& attributes);

    StandingQuery(const world_model::URI& uri,
        const std::vector<std::u16string>& desired_attributes, bool get_data = true);

    ///Free memory from regular expressions
    ~StandingQuery();

    ///r-value copy constructor
    StandingQuery(StandingQuery&& other);

    ///r-value assignment
    StandingQuery& operator=(StandingQuery&& other);

    /**
     * Return true if this origin has data that this standing query might
     * be interested in and false otherwise.
     */
    bool interestingOrigin(std::u16string& origin);

    /**
     * Return a subset of the world state that this query is interested in.
     * Also remember partial matches so that later calls to showInterested
     * do not need to provide the entire world state. This call can
     * quickly check if any data is interesting by seeing if the origin
     * itself is interesting, but will skip this if the world state
     * contains data from multiple origins.
     */
    world_state showInterested(world_state& ws, bool multiple_origins = false);

    /**
     * Return a subset of the world state that this query is interested in.
     * This is similar to showInterested but enforced exact string matches
     * for transient names and does not store transients as partial results.
     * This call can * quickly check if any data is interesting by seeing if
     * the origin itself is interesting, but will skip this if the world state
     * contains data from multiple origins.
     */
    world_state showInterestedTransient(world_state& ws, bool multiple_origins = false);

    /**
     * Return a subset of the world state that would be modified if the
     * supplied URI is expired or deleted.
     */
    void expireURI(world_model::URI uri, world_model::grail_time);

    /**
     * Return a subset of the world state that would be modified if the
     * supplied URI attributes are expired or deleted.
     */
    void expireURIAttributes(world_model::URI uri,
        const std::vector<world_model::Attribute>& entries,
        world_model::grail_time);

    /**
     * Insert data in a thread safe way
     * Data is not checked to see if it matches the given
     * query first so the caller must check that first, on their own
     * or with the showInterested function call.
     */
    void insertData(world_state& ws);

    ///Clear the current data and return what it stored. Thread safe.
    world_state getData();
};

//TODO Merge into standing query class, make standing query functions static
class QueryAccessor {
  private:
    ///Incoming data from solvers, disseminated by the pushThread function
    static boost::lockfree::queue<world_state> incoming_data;

    std::mutex subscription_mutex;
    static std::set<QueryAccessor*> subscriptions;

    /**
     * Need to remember the source list to remove the iterator
     * when this object is destroyed.
     */
    std::list<StandingQuery>* source;
    std::mutex* list_mutex;
    ///List iterators are safe to changes in the underlying list
    std::list<StandingQuery>::iterator data;

    //No copying or assignment. Deleting the copy constructor prevents passing
    //by value would cause trouble when the destructor removes this iterator
    //from the source list.
    QueryAccessor& operator=(const QueryAccessor&) = delete;
    QueryAccessor(const QueryAccessor&) = delete;

  public:
    /**
     * Gets updates and clears the current state
     * This should be thread safe in the StandingQuery class
     */
    StandingQuery::world_state getUpdates();

    /**
     * TODO Create a new standing query, adding itself to the list of
     * subscriptions.
     */
    QueryAccessor(const world_model::URI& uri,
        const std::vector<std::u16string>& desired_attributes, bool get_data = true);

    ///Remove this accessor from the subscription list
    ~QueryAccessor();

    ///r-value copy constructor
    QueryAccessor(QueryAccessor&& other);

    ///r-value assignment
    QueryAccessor& operator=(QueryAccessor&& other);

    /**
     * Function that moves incoming data to the queues of class instances
     * from the incoming data queue.
     */
    static void pushThread();

    /**
     * Expire the supplied URI at the given time.
     */
    static bool expireURI(world_model::URI uri, world_model::grail_time);

    /**
     * Expire the given URI's specified attributes at the given time.
     */
    static bool expireURIAttributes(world_model::URI uri,
        const std::vector<world_model::Attribute>& entries,
        world_model::grail_time);

    /**
     * Push new data from a solver to any interested standing queries.
     */
    static bool pushData(world_state& ws);
};

#endif //ifndef __STANDING_QUERY_HPP__

<|endoftext|>


<commit_before><commit_msg>Fix for PointsPolygons with out of order indice lists.<commit_after><|endoftext|>


<commit_before>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

// It is important to use OrientedImages
#include "itkOrientedImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

// The following three should be used in every CLI application
#include "tubeMessage.h"
#include "tubeCLIFilterWatcher.h"
#include "tubeCLIProgressReporter.h"
#include "itkTimeProbesCollectorBase.h"

// Includes specific to this CLI application
#include "itkImageRegionIteratorWithIndex.h"

// Must do a forward declaraction of DoIt before including
// tubeCLIHelperFunctions
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] );

// Must include CLP before including tubeCLIHleperFunctions
#include "MergeCLP.h"

// Includes tube::ParseArgsAndCallDoIt function
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // The timeCollector is used to perform basic profiling of the components
  //   of your algorithm.
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter    progressReporter( "Merge",
                                                 CLPProcessInformation );
  progressReporter.Start();

  typedef pixelT                                        PixelType;
  typedef itk::Image< PixelType,  dimensionT >          ImageType;
  typedef itk::ImageFileReader< ImageType >             ReaderType;

  timeCollector.Start("Load data");

  typename ReaderType::Pointer reader1 = ReaderType::New();
  reader1->SetFileName( inputVolume1.c_str() );
  try
    {
    reader1->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop("Load data");

  typename ImageType::Pointer curImage1 = reader1->GetOutput();
  typename ImageType::Pointer outImage = ImageType::New();
  outImage->CopyInformation( curImage1 );
  typename ImageType::PointType origin = curImage1->GetOrigin();
  typename ImageType::SpacingType spacing = curImage1->GetSpacing();

  typename ImageType::PointType pointX;
  typename ImageType::IndexType indexX;

  typename ImageType::IndexType minX1Org;
  minX1Org = curImage1->GetLargestPossibleRegion().GetIndex();
  typename ImageType::SizeType size1 = curImage1->
                                         GetLargestPossibleRegion().
                                         GetSize();
  typename ImageType::IndexType maxX1Org;
  for( unsigned int i=0; i<dimensionT; i++ )
    {
    maxX1Org[i] = minX1Org[i] + size1[i] - 1;
    }

  bool useBoundary = false;
  if( boundary.size() == dimensionT)
    {
    useBoundary = true;
    }

  double progress = 0.1;
  progressReporter.Report( progress );
  typename ImageType::IndexType minXOut;
  typename ImageType::IndexType maxXOut;
  typename ImageType::SizeType  sizeOut;
  minXOut = minX1Org;
  maxXOut = maxX1Org;
  for( unsigned int imageNum=0; imageNum<inputVolume2.size(); imageNum++ )
    {
    timeCollector.Start("Load data");
    typename ReaderType::Pointer reader2 = ReaderType::New();
    reader2->SetFileName( inputVolume2[imageNum].c_str() );
    try
      {
      reader2->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Stop("Load data");
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    timeCollector.Stop("Load data");

    progress += 1.0/(double)inputVolume2.size() * 0.4;
    progressReporter.Report( progress );

    typename ImageType::Pointer curImage2 = reader2->GetOutput();

    typename ImageType::IndexType minX2;
    typename ImageType::IndexType minX2Org;
    minX2Org = curImage2->GetLargestPossibleRegion().GetIndex();
    curImage2->TransformIndexToPhysicalPoint( minX2Org, pointX );
    curImage1->TransformPhysicalPointToIndex( pointX, minX2 );
    typename ImageType::SizeType size2 = curImage2->
                                           GetLargestPossibleRegion().
                                           GetSize();
    typename ImageType::IndexType maxX2;
    typename ImageType::IndexType maxX2Org;
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      maxX2Org[i] = minX2Org[i] + size2[i] - 1;
      }
    curImage2->TransformIndexToPhysicalPoint( maxX2Org, pointX );
    curImage1->TransformPhysicalPointToIndex( pointX, maxX2 );

    for( unsigned int i=0; i<dimensionT; i++ )
      {
      if( minX2[i] < minXOut[i] )
        {
        minXOut[i] = minX2[i];
        }
      if( maxX2[i] < minXOut[i] )
        {
        minXOut[i] = maxX2[i];
        }
      }
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      if( minX2[i] > maxXOut[i] )
        {
        maxXOut[i] = minX2[i];
        }
      if( maxX2[i] > maxXOut[i] )
        {
        maxXOut[i] = maxX2[i];
        }
      }

    for( unsigned int i=0; i<dimensionT; i++ )
      {
      sizeOut[i] = maxXOut[i] - minXOut[i] + 1;
      }
    }

  typename ImageType::RegionType regionOut = outImage->
                                               GetLargestPossibleRegion();
  regionOut.SetSize( sizeOut );
  regionOut.SetIndex( minXOut );
  outImage->SetRegions( regionOut );
  outImage->Allocate();
  outImage->FillBuffer( background );

  if( useBoundary )
    {
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      minX1Org[i] += boundary[i];
      maxX1Org[i] -= boundary[i];
      }
    }

  itk::ImageRegionIteratorWithIndex< ImageType > iter( curImage1,
    curImage1->GetLargestPossibleRegion() );
  while( !iter.IsAtEnd() )
    {
    indexX = iter.GetIndex();
    bool useTf1 = true;
    if( !firstImageSpecial && useBoundary )
      {
      for( unsigned int i=0; i<dimensionT; i++ )
        {
        if( indexX[i]<minX1Org[i] || indexX[i]>maxX1Org[i] )
          {
          useTf1 = false;
          break;
          }
        }
      }
    if( useTf1 )
      {
      outImage->SetPixel( indexX, iter.Get() );
      }
    ++iter;
    }
  progress += 0.1;
  progressReporter.Report( progress );

  for( unsigned int imageNum=0; imageNum<inputVolume2.size(); imageNum++ )
    {
    timeCollector.Start("Load data");
    typename ReaderType::Pointer reader2 = ReaderType::New();
    reader2->SetFileName( inputVolume2[imageNum].c_str() );
    try
      {
      reader2->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Stop("Load data");
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    typename ImageType::Pointer curImage2 = reader2->GetOutput();
    timeCollector.Stop("Load data");

    typename ImageType::IndexType minX2Org;
    minX2Org = curImage2->GetLargestPossibleRegion().GetIndex();
    typename ImageType::SizeType size2 = curImage2->
                                           GetLargestPossibleRegion().
                                           GetSize();
    typename ImageType::IndexType maxX2Org;
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      maxX2Org[i] = minX2Org[i] + size2[i] - 1;
      }
    if( useBoundary )
      {
      for( unsigned int i=0; i<dimensionT; i++ )
        {
        minX2Org[i] += boundary[i];
        maxX2Org[i] -= boundary[i];
        }
      }

    progress += 1.0/(double)inputVolume2.size() * 0.2;
    progressReporter.Report( progress );

    itk::ImageRegionIteratorWithIndex< ImageType > iter2( curImage2,
      curImage2->GetLargestPossibleRegion() );
    iter2.GoToBegin();
    typename ImageType::IndexType indexX2;
    while( !iter2.IsAtEnd() )
      {
      indexX2 = iter2.GetIndex();
      bool useTf2 = true;
      if( useBoundary )
        {
        for( unsigned int i=0; i<dimensionT; i++ )
          {
          if( indexX2[i]<minX2Org[i] || indexX2[i]>maxX2Org[i] )
            {
            useTf2 = false;
            break;
            }
          }
        }
      if( useTf2 )
        {
        double tf2 = iter2.Get();
        curImage2->TransformIndexToPhysicalPoint( indexX2, pointX );
        if( outImage->TransformPhysicalPointToIndex( pointX, indexX ) )
          {
          if( average )
            {
            double tf1 = outImage->GetPixel( indexX );
            if( tf1 != background )
              {
              tf1 = ( tf2 + tf1 ) / 2.0;
              }
            else
              {
              tf1 = tf2;
              }
            outImage->SetPixel( indexX, tf1 );
            }
          else
            {
            outImage->SetPixel( indexX, tf2 );
            }
          }
        }
      ++iter2;
      }
    progress += 1.0/(double)inputVolume2.size() * 0.19;
    progressReporter.Report( progress );
    }

  timeCollector.Start("Save data");
  typedef itk::ImageFileWriter< ImageType  >   ImageWriterType;
  typename ImageWriterType::Pointer writer = ImageWriterType::New();
  writer->SetFileName( outputVolume.c_str() );
  writer->SetInput( outImage );
  writer->SetUseCompression( true );
  try
    {
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Writing volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  timeCollector.Stop("Save data");
  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End( );

  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char **argv )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( inputVolume1, argc, argv );
}
<commit_msg>BUG: Possible uninitialized variable (if only merging one image).<commit_after>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

// It is important to use OrientedImages
#include "itkOrientedImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

// The following three should be used in every CLI application
#include "tubeMessage.h"
#include "tubeCLIFilterWatcher.h"
#include "tubeCLIProgressReporter.h"
#include "itkTimeProbesCollectorBase.h"

// Includes specific to this CLI application
#include "itkImageRegionIteratorWithIndex.h"

// Must do a forward declaraction of DoIt before including
// tubeCLIHelperFunctions
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] );

// Must include CLP before including tubeCLIHleperFunctions
#include "MergeCLP.h"

// Includes tube::ParseArgsAndCallDoIt function
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // The timeCollector is used to perform basic profiling of the components
  //   of your algorithm.
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter    progressReporter( "Merge",
                                                 CLPProcessInformation );
  progressReporter.Start();

  typedef pixelT                                        PixelType;
  typedef itk::Image< PixelType,  dimensionT >          ImageType;
  typedef itk::ImageFileReader< ImageType >             ReaderType;

  timeCollector.Start("Load data");

  typename ReaderType::Pointer reader1 = ReaderType::New();
  reader1->SetFileName( inputVolume1.c_str() );
  try
    {
    reader1->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop("Load data");

  typename ImageType::Pointer curImage1 = reader1->GetOutput();
  typename ImageType::Pointer outImage = ImageType::New();
  outImage->CopyInformation( curImage1 );
  typename ImageType::PointType origin = curImage1->GetOrigin();
  typename ImageType::SpacingType spacing = curImage1->GetSpacing();

  typename ImageType::PointType pointX;
  typename ImageType::IndexType indexX;

  typename ImageType::IndexType minX1Org;
  minX1Org = curImage1->GetLargestPossibleRegion().GetIndex();
  typename ImageType::SizeType size1 = curImage1->
                                         GetLargestPossibleRegion().
                                         GetSize();
  typename ImageType::IndexType maxX1Org;
  for( unsigned int i=0; i<dimensionT; i++ )
    {
    maxX1Org[i] = minX1Org[i] + size1[i] - 1;
    }

  bool useBoundary = false;
  if( boundary.size() == dimensionT)
    {
    useBoundary = true;
    }

  double progress = 0.1;
  progressReporter.Report( progress );
  typename ImageType::IndexType minXOut;
  typename ImageType::IndexType maxXOut;
  typename ImageType::SizeType  sizeOut;
  minXOut = minX1Org;
  maxXOut = maxX1Org;
  for( unsigned int i=0; i<dimensionT; i++ )
    {
    sizeOut[i] = maxXOut[i] - minXOut[i] + 1;
    }
  for( unsigned int imageNum=0; imageNum<inputVolume2.size(); imageNum++ )
    {
    timeCollector.Start("Load data");
    typename ReaderType::Pointer reader2 = ReaderType::New();
    reader2->SetFileName( inputVolume2[imageNum].c_str() );
    try
      {
      reader2->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Stop("Load data");
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    timeCollector.Stop("Load data");

    progress += 1.0/(double)inputVolume2.size() * 0.4;
    progressReporter.Report( progress );

    typename ImageType::Pointer curImage2 = reader2->GetOutput();

    typename ImageType::IndexType minX2;
    typename ImageType::IndexType minX2Org;
    minX2Org = curImage2->GetLargestPossibleRegion().GetIndex();
    curImage2->TransformIndexToPhysicalPoint( minX2Org, pointX );
    curImage1->TransformPhysicalPointToIndex( pointX, minX2 );
    typename ImageType::SizeType size2 = curImage2->
                                           GetLargestPossibleRegion().
                                           GetSize();
    typename ImageType::IndexType maxX2;
    typename ImageType::IndexType maxX2Org;
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      maxX2Org[i] = minX2Org[i] + size2[i] - 1;
      }
    curImage2->TransformIndexToPhysicalPoint( maxX2Org, pointX );
    curImage1->TransformPhysicalPointToIndex( pointX, maxX2 );

    for( unsigned int i=0; i<dimensionT; i++ )
      {
      if( minX2[i] < minXOut[i] )
        {
        minXOut[i] = minX2[i];
        }
      if( maxX2[i] < minXOut[i] )
        {
        minXOut[i] = maxX2[i];
        }
      }
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      if( minX2[i] > maxXOut[i] )
        {
        maxXOut[i] = minX2[i];
        }
      if( maxX2[i] > maxXOut[i] )
        {
        maxXOut[i] = maxX2[i];
        }
      }

    for( unsigned int i=0; i<dimensionT; i++ )
      {
      sizeOut[i] = maxXOut[i] - minXOut[i] + 1;
      }
    }

  typename ImageType::RegionType regionOut = outImage->
                                               GetLargestPossibleRegion();
  regionOut.SetSize( sizeOut );
  regionOut.SetIndex( minXOut );
  outImage->SetRegions( regionOut );
  outImage->Allocate();
  outImage->FillBuffer( background );

  if( useBoundary )
    {
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      minX1Org[i] += boundary[i];
      maxX1Org[i] -= boundary[i];
      }
    }

  itk::ImageRegionIteratorWithIndex< ImageType > iter( curImage1,
    curImage1->GetLargestPossibleRegion() );
  while( !iter.IsAtEnd() )
    {
    indexX = iter.GetIndex();
    bool useTf1 = true;
    if( !firstImageSpecial && useBoundary )
      {
      for( unsigned int i=0; i<dimensionT; i++ )
        {
        if( indexX[i]<minX1Org[i] || indexX[i]>maxX1Org[i] )
          {
          useTf1 = false;
          break;
          }
        }
      }
    if( useTf1 )
      {
      outImage->SetPixel( indexX, iter.Get() );
      }
    ++iter;
    }
  progress += 0.1;
  progressReporter.Report( progress );

  for( unsigned int imageNum=0; imageNum<inputVolume2.size(); imageNum++ )
    {
    timeCollector.Start("Load data");
    typename ReaderType::Pointer reader2 = ReaderType::New();
    reader2->SetFileName( inputVolume2[imageNum].c_str() );
    try
      {
      reader2->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Stop("Load data");
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    typename ImageType::Pointer curImage2 = reader2->GetOutput();
    timeCollector.Stop("Load data");

    typename ImageType::IndexType minX2Org;
    minX2Org = curImage2->GetLargestPossibleRegion().GetIndex();
    typename ImageType::SizeType size2 = curImage2->
                                           GetLargestPossibleRegion().
                                           GetSize();
    typename ImageType::IndexType maxX2Org;
    for( unsigned int i=0; i<dimensionT; i++ )
      {
      maxX2Org[i] = minX2Org[i] + size2[i] - 1;
      }
    if( useBoundary )
      {
      for( unsigned int i=0; i<dimensionT; i++ )
        {
        minX2Org[i] += boundary[i];
        maxX2Org[i] -= boundary[i];
        }
      }

    progress += 1.0/(double)inputVolume2.size() * 0.2;
    progressReporter.Report( progress );

    itk::ImageRegionIteratorWithIndex< ImageType > iter2( curImage2,
      curImage2->GetLargestPossibleRegion() );
    iter2.GoToBegin();
    typename ImageType::IndexType indexX2;
    while( !iter2.IsAtEnd() )
      {
      indexX2 = iter2.GetIndex();
      bool useTf2 = true;
      if( useBoundary )
        {
        for( unsigned int i=0; i<dimensionT; i++ )
          {
          if( indexX2[i]<minX2Org[i] || indexX2[i]>maxX2Org[i] )
            {
            useTf2 = false;
            break;
            }
          }
        }
      if( useTf2 )
        {
        double tf2 = iter2.Get();
        curImage2->TransformIndexToPhysicalPoint( indexX2, pointX );
        if( outImage->TransformPhysicalPointToIndex( pointX, indexX ) )
          {
          if( average )
            {
            double tf1 = outImage->GetPixel( indexX );
            if( tf1 != background )
              {
              tf1 = ( tf2 + tf1 ) / 2.0;
              }
            else
              {
              tf1 = tf2;
              }
            outImage->SetPixel( indexX, tf1 );
            }
          else
            {
            outImage->SetPixel( indexX, tf2 );
            }
          }
        }
      ++iter2;
      }
    progress += 1.0/(double)inputVolume2.size() * 0.19;
    progressReporter.Report( progress );
    }

  timeCollector.Start("Save data");
  typedef itk::ImageFileWriter< ImageType  >   ImageWriterType;
  typename ImageWriterType::Pointer writer = ImageWriterType::New();
  writer->SetFileName( outputVolume.c_str() );
  writer->SetInput( outImage );
  writer->SetUseCompression( true );
  try
    {
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Writing volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  timeCollector.Stop("Save data");
  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End( );

  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char **argv )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( inputVolume1, argc, argv );
}
<|endoftext|>


<commit_before>/*
 Copyright 2016 Nervana Systems Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#pragma once

#include "manifest.hpp"
#include "buffer.hpp"
#include "batch_loader.hpp"

/* BatchFileLoader
 *
 * Loads blocks of files from a manifest into a Buffer.
 *
 * TODO: rename to BatchFileLoader since there is no temporal blocking
 * being done here, only a batch of file loads
 */
class BatchFileLoader : public BatchLoader {
public:
    BatchFileLoader(Manifest* manifest);

    void loadBlock(BufferPair& dest, uint block_num, uint block_size);
    void loadFile(Buffer* buff, const string& filename);

private:
    off_t getSize(const string& filename);

    const Manifest* _manifest;
};
<commit_msg>remove completed TODO<commit_after>/*
 Copyright 2016 Nervana Systems Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#pragma once

#include "manifest.hpp"
#include "buffer.hpp"
#include "batch_loader.hpp"

/* BatchFileLoader
 *
 * Loads blocks of files from a manifest into a Buffer.
 *
 */
class BatchFileLoader : public BatchLoader {
public:
    BatchFileLoader(Manifest* manifest);

    void loadBlock(BufferPair& dest, uint block_num, uint block_size);
    void loadFile(Buffer* buff, const string& filename);

private:
    off_t getSize(const string& filename);

    const Manifest* _manifest;
};
<|endoftext|>