<commit_before>/**
 * message.cpp
 *
 *  Created on: 11 окт. 2015 г.
 *      Author: zmij
 */

#include <pushkin/l10n/message.hpp>
#include <pushkin/l10n/message_io.hpp>
#include <pushkin/l10n/message_util.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <sstream>
#include <map>
#include <algorithm>

namespace psst {
namespace l10n {

::std::locale::id domain_name_facet::id;
::std::locale::id context_name_facet::id;
::std::locale::id locale_name_facet::id;

namespace detail {

format::format(localized_message const& msg)
    : fmt_{ new formatted_message{ msg } }
{
}

format::format(localized_message&& msg)
    : fmt_{ new formatted_message{ ::std::move(msg) } }
{
}

format::format(formatted_message_ptr&& fmt)
    : fmt_{ ::std::move(fmt) }
{
}

message_args::message_args(message_args const& rhs)
    : args_{}
{
    args_.reserve(rhs.args_.size());
    ::std::transform(rhs.args_.begin(), rhs.args_.end(),
        ::std::back_inserter(args_),
         [](arg_holder const& arg)
         {
            return arg->clone();
         });
}

message_args::message_args(message_args&& rhs)
    : args_{::std::move(rhs.args_)}
{
}

}  /* namespace detail */

namespace {
    const std::map< message::message_type, std::string > TYPE_TO_STRING {
        { message::message_type::empty, "" },
        { message::message_type::simple, "L10N" },
        { message::message_type::plural, "L10NN" },
        { message::message_type::context, "L10NC" },
        { message::message_type::context_plural, "L10NNC" },
    }; // TYPE_TO_STRING
    const std::map< std::string, message::message_type > STRING_TO_TYPE {
        { "L10N", message::message_type::simple },
        { "L10NN", message::message_type::plural },
        { "L10NC", message::message_type::context },
        { "L10NNC", message::message_type::context_plural },
    }; // STRING_TO_TYPE

    const ::std::string DEFAULT_DOMAIN = "";
} // namespace

// Generated output operator
std::ostream&
operator << (std::ostream& out, message::message_type val)
{
    std::ostream::sentry s (out);
    if (s) {
        auto f = TYPE_TO_STRING.find(val);
        if (f != TYPE_TO_STRING.end()) {
            out << f->second;
        } else {
            out << "Unknown type " << (int)val;
        }
    }
    return out;
}
// Generated input operator
std::istream&
operator >> (std::istream& in, message::message_type& val)
{
    std::istream::sentry s (in);
    if (!s) return in;

    std::string name;
    if (in >> name) {
        auto f = STRING_TO_TYPE.find(name);
        if (f != STRING_TO_TYPE.end()) {
            val = f->second;
        } else {
            val = message::message_type::empty;
            in.setstate(std::ios_base::failbit);
        }
    }

    return in;
}

message::message() : type_(message_type::empty), n_(0)
{
}

message::message(optional_string const& domain)
    : type_(message_type::empty), domain_(domain), n_(0)
{
}

message::message(std::string const& id, optional_string const& domain)
    : type_(message_type::simple), msgid_(id), msgstr_(id), domain_(domain), n_(0)
{
}

message::message(id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::simple), msgid_(id_n_str.first), msgstr_(id_n_str.second), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& context_str,
        std::string const& id, optional_string const& domain)
    : type_(message_type::context), msgid_(id), msgstr_(id), context_(context_str), domain_(domain), n_(0)
{
}

message::message(std::string const& context_str,
        id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::context), msgid_(id_n_str.first), msgstr_(id_n_str.second), context_(context_str), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& singular,
        std::string const& plural_str,
        int n, optional_string const& domain)
    : type_(message_type::plural), msgid_(singular), msgstr_(singular), plural_(plural_str), domain_(domain), n_(n)
{
}

message::message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        int n, optional_string const& domain)
    : type_(message_type::context_plural), msgid_(singular), msgstr_(singular), context_(context),
      plural_(plural), domain_(domain), n_(n)
{
}

void
message::swap(message& rhs) noexcept
{
    using std::swap;
    swap(type_, rhs.type_);
    swap(msgid_, rhs.msgid_);
    swap(msgstr_, rhs.msgstr_);
    swap(plural_, rhs.plural_);
    swap(context_, rhs.context_);
    swap(n_, rhs.n_);
    swap(domain_, rhs.domain_);
    swap(args_, rhs.args_);
}

::std::string const&
message::plural() const
{
    if (!plural_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't contain a plural form" };
    return *plural_;
    }

::std::string const&
message::context() const
{
    if (!context_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't have context" };
    return *context_;
    }

::std::string const&
message::domain() const
{
    if (!domain_.is_initialized())
        return DEFAULT_DOMAIN;
    return *domain_;
}

void
message::domain( std::string const& domain)
{
    domain_ = domain;
}

void
message::set_plural()
{
    switch (type_) {
        case message_type::simple:
        case message_type::plural:
            type_ = message_type::plural; break;
        case message_type::context:
        case message_type::context_plural:
            type_ = message_type::context_plural; break;
        default:
            throw ::std::runtime_error{"Cannot convert message to a plural form"};
    }

    plural_ = msgid_;
}

void
message::set_plural(int n)
{
    set_plural();
    n_ = n;
}

message::localized_message
message::translate(int n) const
{
    switch (type_) {
        case message_type::empty:
            return localized_message();
        case message_type::simple:
            return localized_message(msgid_);
        case message_type::context:
            return localized_message(context_.value(), msgid_);
        case message_type::plural:
            return localized_message(msgid_, plural_.value(), n);
        case message_type::context_plural:
            return localized_message(context_.value(), msgid_, plural_.value(), n);
        default:
            throw std::runtime_error("Unknown message type");
    }
}

detail::format
message::format(int n, bool feed_plural) const
{
    detail::format fmt{translate(n)};
    if (has_plural() && feed_plural)
        fmt % n;
    fmt % args_;
    return fmt;
}

void
message::write(std::ostream& os) const
{
    namespace locn = boost::locale;
    if (domain_.is_initialized()) {
        os << locn::as::domain(domain_.value());
    }
    os << format();
}

void
message::collect(message_list& messages) const
{
    for (auto const& arg : args_) {
        arg->collect(messages);
    }
}

message
message::create_message(::std::string const& id, get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& context,
            std::string const& id,
            get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{context, id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            } else {
                f(msg, nm);
            }
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

message
message::create_message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{context, singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            }
            if (ph.uses > 1)
                f(msg, nm);
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

std::ostream&
operator << (std::ostream& out, message const& val)
{
    std::ostream::sentry s(out);
    if (s) {
        val.write(out);
    }
    return out;
}

::std::istream&
operator >> (::std::istream& is, message& val)
{
    ::std::istream::sentry s(is);
    if(!s) return is;

    ::std::string msgstr;

    char c;
    while(is.get(c))
        msgstr.push_back(c);

    message::id_str_pair id_n_str{
        (val.id().empty() ? msgstr : val.id()), msgstr
    };

    message::optional_string domain;
    message::optional_string context;
    auto loc = is.getloc();
    if (::std::has_facet<domain_name_facet>(loc)) {
        domain = ::std::use_facet<domain_name_facet>(loc).domain();
    }
    if (::std::has_facet<context_name_facet>(loc)) {
        context = ::std::use_facet<context_name_facet>(loc).context();
    }

    if (context.is_initialized()) {
        val = message{*context, id_n_str, domain};
    } else {
        val = message{id_n_str, domain};
    }

    if(val.msgstr().find("{1}") != std::string::npos)
        val.set_plural();

    return is;
}

} /* namespace l10n */
} /* namespace psst */
<commit_msg>AWM-8253 tank_dump a bit faster<commit_after>/**
 * message.cpp
 *
 *  Created on: 11 окт. 2015 г.
 *      Author: zmij
 */

#include <pushkin/l10n/message.hpp>
#include <pushkin/l10n/message_io.hpp>
#include <pushkin/l10n/message_util.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <sstream>
#include <map>
#include <algorithm>

namespace psst {
namespace l10n {

::std::locale::id domain_name_facet::id;
::std::locale::id context_name_facet::id;
::std::locale::id locale_name_facet::id;

namespace detail {

format::format(localized_message const& msg)
    : fmt_{ new formatted_message{ msg } }
{
}

format::format(localized_message&& msg)
    : fmt_{ new formatted_message{ ::std::move(msg) } }
{
}

format::format(formatted_message_ptr&& fmt)
    : fmt_{ ::std::move(fmt) }
{
}

message_args::message_args(message_args const& rhs)
    : args_{}
{
    args_.reserve(rhs.args_.size());
    ::std::transform(rhs.args_.begin(), rhs.args_.end(),
        ::std::back_inserter(args_),
         [](arg_holder const& arg)
         {
            return arg->clone();
         });
}

message_args::message_args(message_args&& rhs)
    : args_{::std::move(rhs.args_)}
{
}

}  /* namespace detail */

namespace {
    const std::map< message::message_type, std::string > TYPE_TO_STRING {
        { message::message_type::empty, "" },
        { message::message_type::simple, "L10N" },
        { message::message_type::plural, "L10NN" },
        { message::message_type::context, "L10NC" },
        { message::message_type::context_plural, "L10NNC" },
    }; // TYPE_TO_STRING
    const std::map< std::string, message::message_type > STRING_TO_TYPE {
        { "L10N", message::message_type::simple },
        { "L10NN", message::message_type::plural },
        { "L10NC", message::message_type::context },
        { "L10NNC", message::message_type::context_plural },
    }; // STRING_TO_TYPE

    const ::std::string DEFAULT_DOMAIN = "";
} // namespace

// Generated output operator
std::ostream&
operator << (std::ostream& out, message::message_type val)
{
    std::ostream::sentry s (out);
    if (s) {
        auto f = TYPE_TO_STRING.find(val);
        if (f != TYPE_TO_STRING.end()) {
            out << f->second;
        } else {
            out << "Unknown type " << (int)val;
        }
    }
    return out;
}
// Generated input operator
std::istream&
operator >> (std::istream& in, message::message_type& val)
{
    std::istream::sentry s (in);
    if (!s) return in;

    std::string name;
    if (in >> name) {
        auto f = STRING_TO_TYPE.find(name);
        if (f != STRING_TO_TYPE.end()) {
            val = f->second;
        } else {
            val = message::message_type::empty;
            in.setstate(std::ios_base::failbit);
        }
    }

    return in;
}

message::message() : type_(message_type::empty), n_(0)
{
}

message::message(optional_string const& domain)
    : type_(message_type::empty), domain_(domain), n_(0)
{
}

message::message(std::string const& id, optional_string const& domain)
    : type_(message_type::simple), msgid_(id), msgstr_(id), domain_(domain), n_(0)
{
}

message::message(id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::simple), msgid_(id_n_str.first), msgstr_(id_n_str.second), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& context_str,
        std::string const& id, optional_string const& domain)
    : type_(message_type::context), msgid_(id), msgstr_(id), context_(context_str), domain_(domain), n_(0)
{
}

message::message(std::string const& context_str,
        id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::context), msgid_(id_n_str.first), msgstr_(id_n_str.second), context_(context_str), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& singular,
        std::string const& plural_str,
        int n, optional_string const& domain)
    : type_(message_type::plural), msgid_(singular), msgstr_(singular), plural_(plural_str), domain_(domain), n_(n)
{
}

message::message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        int n, optional_string const& domain)
    : type_(message_type::context_plural), msgid_(singular), msgstr_(singular), context_(context),
      plural_(plural), domain_(domain), n_(n)
{
}

void
message::swap(message& rhs) noexcept
{
    using std::swap;
    swap(type_, rhs.type_);
    swap(msgid_, rhs.msgid_);
    swap(msgstr_, rhs.msgstr_);
    swap(plural_, rhs.plural_);
    swap(context_, rhs.context_);
    swap(n_, rhs.n_);
    swap(domain_, rhs.domain_);
    swap(args_, rhs.args_);
}

::std::string const&
message::plural() const
{
    if (!plural_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't contain a plural form" };
    return *plural_;
    }

::std::string const&
message::context() const
{
    if (!context_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't have context" };
    return *context_;
    }

::std::string const&
message::domain() const
{
    if (!domain_.is_initialized())
        return DEFAULT_DOMAIN;
    return *domain_;
}

void
message::domain( std::string const& domain)
{
    domain_ = domain;
}

void
message::set_plural()
{
    switch (type_) {
        case message_type::simple:
        case message_type::plural:
            type_ = message_type::plural; break;
        case message_type::context:
        case message_type::context_plural:
            type_ = message_type::context_plural; break;
        default:
            throw ::std::runtime_error{"Cannot convert message to a plural form"};
    }

    plural_ = msgid_;
}

void
message::set_plural(int n)
{
    set_plural();
    n_ = n;
}

message::localized_message
message::translate(int n) const
{
    switch (type_) {
        case message_type::empty:
            return localized_message();
        case message_type::simple:
            return localized_message(msgid_);
        case message_type::context:
            return localized_message(context_.value(), msgid_);
        case message_type::plural:
            return localized_message(msgid_, plural_.value(), n);
        case message_type::context_plural:
            return localized_message(context_.value(), msgid_, plural_.value(), n);
        default:
            throw std::runtime_error("Unknown message type");
    }
}

detail::format
message::format(int n, bool feed_plural) const
{
    detail::format fmt{translate(n)};
    if (has_plural() && feed_plural)
        fmt % n;
    fmt % args_;
    return fmt;
}

void
message::write(std::ostream& os) const
{
    namespace locn = boost::locale;
    if (domain_.is_initialized()) {
        os << locn::as::domain(domain_.value());
    }
    if(has_format_args()) {
        os << format();
    } else {
        os << translate(n_);
    }
}

void
message::collect(message_list& messages) const
{
    for (auto const& arg : args_) {
        arg->collect(messages);
    }
}

message
message::create_message(::std::string const& id, get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& context,
            std::string const& id,
            get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{context, id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            } else {
                f(msg, nm);
            }
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

message
message::create_message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{context, singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            }
            if (ph.uses > 1)
                f(msg, nm);
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

std::ostream&
operator << (std::ostream& out, message const& val)
{
    std::ostream::sentry s(out);
    if (s) {
        val.write(out);
    }
    return out;
}

::std::istream&
operator >> (::std::istream& is, message& val)
{
    ::std::istream::sentry s(is);
    if(!s) return is;

    ::std::string msgstr;

    char c;
    while(is.get(c))
        msgstr.push_back(c);

    message::id_str_pair id_n_str{
        (val.id().empty() ? msgstr : val.id()), msgstr
    };

    message::optional_string domain;
    message::optional_string context;
    auto loc = is.getloc();
    if (::std::has_facet<domain_name_facet>(loc)) {
        domain = ::std::use_facet<domain_name_facet>(loc).domain();
    }
    if (::std::has_facet<context_name_facet>(loc)) {
        context = ::std::use_facet<context_name_facet>(loc).context();
    }

    if (context.is_initialized()) {
        val = message{*context, id_n_str, domain};
    } else {
        val = message{id_n_str, domain};
    }

    if(val.msgstr().find("{1}") != std::string::npos)
        val.set_plural();

    return is;
}

} /* namespace l10n */
} /* namespace psst */
<|endoftext|>


<commit_before>/*
Copyright (c) 2012, Ronie Martinez
ronmarti18@gmail.com
All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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 Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301  USA
*/

#include "qpsdplugin.h"
#include <QRgb>
#include <QColor>

qpsdPlugn::qpsdPlugn(QObject *parent) :
    QImageIOPlugin(parent)
{
}

qpsdPlugn::~qpsdPlugn()
{

}

QStringList qpsdPlugn::keys() const
{
    return QStringList() << "psd";//TODO: add PSB (Photoshop Big) support
}

QImageIOPlugin::Capabilities qpsdPlugn::capabilities(
    QIODevice *device, const QByteArray &format) const
{
    if (format == "psd")
        return Capabilities(CanRead);//TODO: add CanWrite support
    if (!(format.isEmpty() && device->isOpen()))
        return 0;

    Capabilities cap;
    if (device->isReadable() && qpsdHandler::canRead(device))
        cap |= CanRead;
    // if (device->isWritable())
    //     cap |= CanWrite;
    return cap;
}

QImageIOHandler *qpsdPlugn::create(
    QIODevice *device, const QByteArray &format) const
{
    QImageIOHandler *handler = new qpsdHandler;
    handler->setDevice(device);
    handler->setFormat(format);
    return handler;
}

//Q_EXPORT_STATIC_PLUGIN(qpsdPlugn)
Q_EXPORT_PLUGIN2(qpsd, qpsdPlugn)

qpsdHandler::qpsdHandler()
{

}

qpsdHandler::~qpsdHandler()
{

}

bool qpsdHandler::canRead() const
{
    if (canRead(device())) {
        setFormat("psd");
        return true;
    }
    return false;
}

bool qpsdHandler::canRead(QIODevice *device)
{
    return device->peek(4) == QByteArray("\x38\x42\x50\x53"); //8BPS
}

bool qpsdHandler::read(QImage *image)
{
    QDataStream input(device());
    quint32 signature, height, width, colorModeDataLength, imageResourcesLength, layerAndMaskInformationLength;
    quint16 version, channels, depth, colorMode, compression;
    QByteArray colorData;
    input.setByteOrder(QDataStream::BigEndian);
    input >> signature >> version ;
    input.skipRawData(6);//reserved bytes should be 6-byte in size
    input >> channels >> height >> width >> depth >> colorMode;
    input >> colorModeDataLength;
    if(colorModeDataLength != 0)
    {
        quint8 byte;
        for(quint32 i=0; i<colorModeDataLength; ++i)
        {
            input >> byte;
            colorData.append(byte);
        }
    }
    input >> imageResourcesLength;
    input.skipRawData(imageResourcesLength);
    input >> layerAndMaskInformationLength;
    input.skipRawData(layerAndMaskInformationLength);
    input >> compression;

    if (input.status() != QDataStream::Ok || signature != 0x38425053 || version != 0x0001)
        return false;

    QByteArray decompressed;
    switch(compression)
    {
    case 0: /*RAW IMAGE DATA - UNIMPLEMENTED*/
        break;
    case 1: /*RLE COMPRESSED DATA*/
        // The RLE-compressed data is proceeded by a 2-byte data count for each row in the data,
        // which we're going to just skip.
        input.skipRawData(height*channels*2);

        quint8 byte,count;
        decompressed.clear();

        /*Code based on PackBits implementation which is primarily used by Photoshop for RLE encoding/decoding*/
        while(!input.atEnd())
        {
            input >> byte;
            if(byte > 128)
            {
                count=256-byte;
                input >>  byte;
                for(quint8 i=0;i<=count;i++)
                {
                    decompressed.append(byte);

                }
            }
            else if(byte < 128)
            {
                count=byte+1;
                for(quint8 i=0;i<count;i++)
                {
                    input >> byte;
                    decompressed.append(byte);
                }
            }
        }
        break;
    case 2:/*ZIP WITHOUT PREDICTION - UNIMPLEMENTED*/
        break;
    case 3:/*ZIP WITH PREDICTION - UNIMPLEMENTED*/
        break;
    }

    int totalBytes = width * height;

    //FIXME: find better alternative
    switch(colorMode)
    {
    case 0: //for bitmap
        if(decompressed.size() != (channels * totalBytes)/8)
        {
            return false;
        }
        break;
    default: //for non-bitmap
        if(decompressed.size() != channels * totalBytes)
        {
            return false;
        }
        break;
    }

    switch(colorMode)
    {
    case 0: /*BITMAP*/
        {
            //FIXME: image loads to "result" properly but becomes different when
            //it passes the operator =
            QImage result((uchar*)decompressed.data(),width, height, QImage::Format_Mono);
            //output produced is inverted - black becomes white, white becomes black
            result.invertPixels();
            *image = result;
        }

        break;
    case 1: /*GRAYSCALE - FOR TESTING*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 1:
                QImage result(width, height, QImage::Format_Indexed8);
                const int IndexCount = 256;
                for(int i = 0; i < IndexCount; ++i){
                    result.setColor(i, qRgb(i, i, i));
                }

                quint8 *data = (quint8*)decompressed.constData();
                for(quint32 i=0; i < height; ++i)
                {
                    for(quint32 j=0; j < width; ++j)
                    {
                        result.setPixel(j,i, *data);
                        ++data;
                    }
                }

                *image = result;
                break;
            }
        }

        break;
    case 2: /*INDEXED*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 1:
                QImage result(width, height, QImage::Format_Indexed8);
                int indexCount = colorData.size() / 3;
                Q_ASSERT(indexCount == 256);
                quint8 *red = (quint8*)colorData.constData();
                quint8 *green = red + indexCount;
                quint8 *blue = green + indexCount;
                for(int i=0; i < indexCount; ++i){
                    /*
                     * reference https://github.com/OpenImageIO/oiio/blob/master/src/psd.imageio/psdinput.cpp
                     * function bool PSDInput::indexed_to_rgb (char *dst)
                     */
                    result.setColor(i, qRgb(*red, *green, *blue));
                    ++red; ++green; ++blue;
                }

                quint8 *data = (quint8*)decompressed.constData();
                for(quint32 i=0; i < height; ++i)
                {
                    for(quint32 j=0; j < width; ++j)
                    {
                        result.setPixel(j,i,*data);
                        ++data;
                    }
                }
                *image=result;
                break;
            }
        }
        break;
    case 3: /*RGB*/
        switch(depth)
        {
        case 1:
            break;
        case 8:
            switch(channels)
            {
            case 1:
                break;
            case 3:
            {
                QImage result(width, height, QImage::Format_RGB32);
                quint8 *red = (quint8*)decompressed.constData();
                quint8 *green = red + totalBytes;
                quint8 *blue = green + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = qRgb(*red, *green, *blue);
                        ++p; ++red; ++green; ++blue;
                    }
                }

                *image = result;
            }
                break;
            case 4:
            {
                QImage result(width, height, QImage::Format_ARGB32);
                quint8 *red = (quint8*)decompressed.constData();
                quint8 *green = red + totalBytes;
                quint8 *blue = green + totalBytes;
                quint8 *alpha = blue + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = qRgba(*red, *green, *blue, *alpha);
                        ++p; ++red; ++green; ++blue; ++alpha;
                    }
                }

                *image = result;
            }
                break;
            case 5:
                qDebug("5 channels of rgb mode");
                return false;
            }

            break;
        case 16:
            break;
        }
        break;
    case 4: /*CMYK*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 4:
            {
                QImage result(width, height, QImage::Format_RGB32);
                quint8 *cyan = (quint8*)decompressed.constData();
                quint8 *magenta = cyan + totalBytes;
                quint8 *yellow = magenta + totalBytes;
                quint8 *key = yellow + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = QColor::fromCmyk(255-*cyan, 255-*magenta,
                                              255-*yellow, 255-*key).rgb();
                        ++p; ++cyan; ++magenta; ++yellow; ++key;
                    }
                }
                *image = result;
            }
                break;
            case 5:
            {
                QImage result(width, height, QImage::Format_ARGB32);
                quint8 *alpha = (quint8*)decompressed.constData();
                quint8 *cyan = alpha + totalBytes;
                quint8 *magenta = cyan + totalBytes;
                quint8 *yellow = magenta + totalBytes;
                quint8 *key = yellow + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = QColor::fromCmyk(255-*cyan, 255-*magenta,
                                              255-*yellow, 255-*key,
                                              *alpha).rgba();
                        ++p; ++alpha; ++cyan; ++magenta; ++yellow; ++key;
                    }
                }
                *image = result;
            }
                break;
            }
        }
        break;
    case 7: /*MULTICHANNEL - UNIMPLEMENTED*/
        break;
    case 8: /*DUOTONE - UNIMPLEMENTED*/
        break;
    case 9: /*LAB - UNIMPLEMENTED*/
        break;
    }

    return input.status() == QDataStream::Ok;
}

bool qpsdHandler::supportsOption(ImageOption option) const
{
    return option == Size;
}

QVariant qpsdHandler::option(ImageOption option) const
{
    if (option == Size) {
        QByteArray bytes = device()->peek(26);
        QDataStream input(bytes);
        quint32 signature, height, width;
        quint16 version, channels, depth, colorMode;
        input.setByteOrder(QDataStream::BigEndian);
        input >> signature >> version ;
        input.skipRawData(6);//reserved bytes should be 6-byte in size
        input >> channels >> height >> width >> depth >> colorMode;
        if (input.status() == QDataStream::Ok && signature == 0x38425053 && version == 0x0001)
            return QSize(width, height);
    }
    return QVariant();
}
<commit_msg>Fix bitmap mode support<commit_after>/*
Copyright (c) 2012, Ronie Martinez
ronmarti18@gmail.com
All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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 Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301  USA
*/

#include "qpsdplugin.h"
#include <QRgb>
#include <QColor>

qpsdPlugn::qpsdPlugn(QObject *parent) :
    QImageIOPlugin(parent)
{
}

qpsdPlugn::~qpsdPlugn()
{

}

QStringList qpsdPlugn::keys() const
{
    return QStringList() << "psd";//TODO: add PSB (Photoshop Big) support
}

QImageIOPlugin::Capabilities qpsdPlugn::capabilities(
    QIODevice *device, const QByteArray &format) const
{
    if (format == "psd")
        return Capabilities(CanRead);//TODO: add CanWrite support
    if (!(format.isEmpty() && device->isOpen()))
        return 0;

    Capabilities cap;
    if (device->isReadable() && qpsdHandler::canRead(device))
        cap |= CanRead;
    // if (device->isWritable())
    //     cap |= CanWrite;
    return cap;
}

QImageIOHandler *qpsdPlugn::create(
    QIODevice *device, const QByteArray &format) const
{
    QImageIOHandler *handler = new qpsdHandler;
    handler->setDevice(device);
    handler->setFormat(format);
    return handler;
}

//Q_EXPORT_STATIC_PLUGIN(qpsdPlugn)
Q_EXPORT_PLUGIN2(qpsd, qpsdPlugn)

qpsdHandler::qpsdHandler()
{

}

qpsdHandler::~qpsdHandler()
{

}

bool qpsdHandler::canRead() const
{
    if (canRead(device())) {
        setFormat("psd");
        return true;
    }
    return false;
}

bool qpsdHandler::canRead(QIODevice *device)
{
    return device->peek(4) == QByteArray("\x38\x42\x50\x53"); //8BPS
}

bool qpsdHandler::read(QImage *image)
{
    QDataStream input(device());
    quint32 signature, height, width, colorModeDataLength, imageResourcesLength, layerAndMaskInformationLength;
    quint16 version, channels, depth, colorMode, compression;
    QByteArray colorData;
    input.setByteOrder(QDataStream::BigEndian);
    input >> signature >> version ;
    input.skipRawData(6);//reserved bytes should be 6-byte in size
    input >> channels >> height >> width >> depth >> colorMode;
    input >> colorModeDataLength;
    if(colorModeDataLength != 0)
    {
        quint8 byte;
        for(quint32 i=0; i<colorModeDataLength; ++i)
        {
            input >> byte;
            colorData.append(byte);
        }
    }
    input >> imageResourcesLength;
    input.skipRawData(imageResourcesLength);
    input >> layerAndMaskInformationLength;
    input.skipRawData(layerAndMaskInformationLength);
    input >> compression;

    if (input.status() != QDataStream::Ok || signature != 0x38425053 || version != 0x0001)
        return false;

    QByteArray decompressed;
    switch(compression)
    {
    case 0: /*RAW IMAGE DATA - UNIMPLEMENTED*/
        break;
    case 1: /*RLE COMPRESSED DATA*/
        // The RLE-compressed data is proceeded by a 2-byte data count for each row in the data,
        // which we're going to just skip.
        input.skipRawData(height*channels*2);

        quint8 byte,count;
        decompressed.clear();

        /*Code based on PackBits implementation which is primarily used by Photoshop for RLE encoding/decoding*/
        while(!input.atEnd())
        {
            input >> byte;
            if(byte > 128)
            {
                count=256-byte;
                input >>  byte;
                for(quint8 i=0;i<=count;i++)
                {
                    decompressed.append(byte);

                }
            }
            else if(byte < 128)
            {
                count=byte+1;
                for(quint8 i=0;i<count;i++)
                {
                    input >> byte;
                    decompressed.append(byte);
                }
            }
        }
        break;
    case 2:/*ZIP WITHOUT PREDICTION - UNIMPLEMENTED*/
        break;
    case 3:/*ZIP WITH PREDICTION - UNIMPLEMENTED*/
        break;
    }

    int totalBytes = width * height;

    //FIXME: find better alternative
    switch(colorMode)
    {
    case 0: //for bitmap
        if(decompressed.size() != (channels * totalBytes)/8)
        {
            return false;
        }
        break;
    default: //for non-bitmap
        if(decompressed.size() != channels * totalBytes)
        {
            return false;
        }
        break;
    }

    switch(colorMode)
    {
    case 0: /*BITMAP*/
        {
            QString head = QString("P4\n%1 %2\n").arg(width).arg(height);
            QByteArray buffer(head.toAscii());
            buffer.append(decompressed);
            QImage result = QImage::fromData(buffer);
            if(result.isNull())
                return false;
            else
                *image = result;
        }

        break;
    case 1: /*GRAYSCALE - FOR TESTING*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 1:
                QImage result(width, height, QImage::Format_Indexed8);
                const int IndexCount = 256;
                for(int i = 0; i < IndexCount; ++i){
                    result.setColor(i, qRgb(i, i, i));
                }

                quint8 *data = (quint8*)decompressed.constData();
                for(quint32 i=0; i < height; ++i)
                {
                    for(quint32 j=0; j < width; ++j)
                    {
                        result.setPixel(j,i, *data);
                        ++data;
                    }
                }

                *image = result;
                break;
            }
        }

        break;
    case 2: /*INDEXED*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 1:
                QImage result(width, height, QImage::Format_Indexed8);
                int indexCount = colorData.size() / 3;
                Q_ASSERT(indexCount == 256);
                quint8 *red = (quint8*)colorData.constData();
                quint8 *green = red + indexCount;
                quint8 *blue = green + indexCount;
                for(int i=0; i < indexCount; ++i){
                    /*
                     * reference https://github.com/OpenImageIO/oiio/blob/master/src/psd.imageio/psdinput.cpp
                     * function bool PSDInput::indexed_to_rgb (char *dst)
                     */
                    result.setColor(i, qRgb(*red, *green, *blue));
                    ++red; ++green; ++blue;
                }

                quint8 *data = (quint8*)decompressed.constData();
                for(quint32 i=0; i < height; ++i)
                {
                    for(quint32 j=0; j < width; ++j)
                    {
                        result.setPixel(j,i,*data);
                        ++data;
                    }
                }
                *image=result;
                break;
            }
        }
        break;
    case 3: /*RGB*/
        switch(depth)
        {
        case 1:
            break;
        case 8:
            switch(channels)
            {
            case 1:
                break;
            case 3:
            {
                QImage result(width, height, QImage::Format_RGB32);
                quint8 *red = (quint8*)decompressed.constData();
                quint8 *green = red + totalBytes;
                quint8 *blue = green + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = qRgb(*red, *green, *blue);
                        ++p; ++red; ++green; ++blue;
                    }
                }

                *image = result;
            }
                break;
            case 4:
            {
                QImage result(width, height, QImage::Format_ARGB32);
                quint8 *red = (quint8*)decompressed.constData();
                quint8 *green = red + totalBytes;
                quint8 *blue = green + totalBytes;
                quint8 *alpha = blue + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = qRgba(*red, *green, *blue, *alpha);
                        ++p; ++red; ++green; ++blue; ++alpha;
                    }
                }

                *image = result;
            }
                break;
            case 5:
                qDebug("5 channels of rgb mode");
                return false;
            }

            break;
        case 16:
            break;
        }
        break;
    case 4: /*CMYK*/
        switch(depth)
        {
        case 8:
            switch(channels)
            {
            case 4:
            {
                QImage result(width, height, QImage::Format_RGB32);
                quint8 *cyan = (quint8*)decompressed.constData();
                quint8 *magenta = cyan + totalBytes;
                quint8 *yellow = magenta + totalBytes;
                quint8 *key = yellow + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = QColor::fromCmyk(255-*cyan, 255-*magenta,
                                              255-*yellow, 255-*key).rgb();
                        ++p; ++cyan; ++magenta; ++yellow; ++key;
                    }
                }
                *image = result;
            }
                break;
            case 5:
            {
                QImage result(width, height, QImage::Format_ARGB32);
                quint8 *alpha = (quint8*)decompressed.constData();
                quint8 *cyan = alpha + totalBytes;
                quint8 *magenta = cyan + totalBytes;
                quint8 *yellow = magenta + totalBytes;
                quint8 *key = yellow + totalBytes;
                QRgb  *p, *end;
                for (quint32 y = 0; y < height; ++y) {
                    p = (QRgb *)result.scanLine(y);
                    end = p + width;
                    while (p < end) {
                        *p = QColor::fromCmyk(255-*cyan, 255-*magenta,
                                              255-*yellow, 255-*key,
                                              *alpha).rgba();
                        ++p; ++alpha; ++cyan; ++magenta; ++yellow; ++key;
                    }
                }
                *image = result;
            }
                break;
            }
        }
        break;
    case 7: /*MULTICHANNEL - UNIMPLEMENTED*/
        break;
    case 8: /*DUOTONE - UNIMPLEMENTED*/
        break;
    case 9: /*LAB - UNIMPLEMENTED*/
        break;
    }

    return input.status() == QDataStream::Ok;
}

bool qpsdHandler::supportsOption(ImageOption option) const
{
    return option == Size;
}

QVariant qpsdHandler::option(ImageOption option) const
{
    if (option == Size) {
        QByteArray bytes = device()->peek(26);
        QDataStream input(bytes);
        quint32 signature, height, width;
        quint16 version, channels, depth, colorMode;
        input.setByteOrder(QDataStream::BigEndian);
        input >> signature >> version ;
        input.skipRawData(6);//reserved bytes should be 6-byte in size
        input >> channels >> height >> width >> depth >> colorMode;
        if (input.status() == QDataStream::Ok && signature == 0x38425053 && version == 0x0001)
            return QSize(width, height);
    }
    return QVariant();
}
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/slobrok/server/rpc_mapping_monitor.h>
#include <vespa/fnet/transport_debugger.h>
#include <vespa/fnet/transport_thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/vespalib/util/require.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <map>

using namespace vespalib;
using namespace slobrok;
using vespalib::make_string_short::fmt;

// simple rpc server implementing the required slobrok call-back API
struct Server : FRT_Invokable {
    fnet::frt::StandaloneFRT frt;
    std::vector<vespalib::string> names;
    size_t inject_fail_cnt;
    FNET_Connection *last_conn;
    void set_last_conn(FNET_Connection *conn) {
        if (last_conn) {
            last_conn->SubRef();
        }
        last_conn = conn;
        if (last_conn) {
            last_conn->AddRef();
        }
    }
    Server(fnet::TimeTools::SP time_tools) : frt(TransportConfig().time_tools(time_tools)), names(),
                                             inject_fail_cnt(0), last_conn(nullptr)
    {
        FRT_ReflectionBuilder rb(&frt.supervisor());
        rb.DefineMethod("slobrok.callback.listNamesServed", "", "S", FRT_METHOD(Server::rpc_listNamesServed), this);
        rb.DefineMethod("slobrok.callback.notifyUnregistered", "s", "", FRT_METHOD(Server::rpc_notifyUnregistered), this);
        REQUIRE(frt.supervisor().Listen(0));
    }
    ~Server() { set_last_conn(nullptr); }
    vespalib::string spec() const { return fmt("tcp/%d", frt.supervisor().GetListenPort()); }
    FNET_Transport &transport() { return *frt.supervisor().GetTransport(); }
    void rpc_listNamesServed(FRT_RPCRequest *req) {
        set_last_conn(req->GetConnection());
        if (inject_fail_cnt > 0) {
            req->SetError(FRTE_RPC_METHOD_FAILED, "fail injected by unit test");
            --inject_fail_cnt;
        } else {
            FRT_Values &dst = *req->GetReturn();
            FRT_StringValue *names_out = dst.AddStringArray(names.size());
            for (size_t i = 0; i < names.size(); ++i) {
                dst.SetString(&names_out[i], names[i].c_str());
            }
        }
    }
    void rpc_notifyUnregistered(FRT_RPCRequest *) {}
};

enum class State { ANY, UP, DOWN };

// Run-Length-Encoded historic state samples for a single service mapping
struct States {
    struct Entry {
        State state;
        size_t cnt;
    };
    std::vector<Entry> hist;
    State state() const { return hist.back().state; }
    States() : hist({{State::ANY, 0}}) {}
    void sample(State state) {
        if (state == hist.back().state) {
            ++hist.back().cnt;
        } else {
            hist.push_back(Entry{state, 1});
        }
    }
    size_t samples(State state = State::ANY) const {
        size_t n = 0;
        for (const auto &entry: hist) {
            if ((entry.state == state) || (state == State::ANY)) {
                n += entry.cnt;
            }
        }
        return n;
    }
};

// history of which call-backs we have gotten so far
struct History : MappingMonitorOwner {
    std::map<ServiceMapping, States> map;
    void up(const ServiceMapping &mapping) override { map[mapping].sample(State::UP); }
    void down(const ServiceMapping &mapping) override { map[mapping].sample(State::DOWN); }
};

struct RpcMappingMonitorTest : public ::testing::Test {
    fnet::TransportDebugger debugger;
    fnet::frt::StandaloneFRT my_frt;
    Server a;
    Server b;
    History hist;
    std::unique_ptr<RpcMappingMonitor> monitor;
    ServiceMapping foo_a;
    ServiceMapping bar_a;
    ServiceMapping baz_b;
    RpcMappingMonitorTest()
      : debugger(),
        my_frt(TransportConfig().time_tools(debugger.time_tools())),
        a(debugger.time_tools()),
        b(debugger.time_tools()),
        hist(),
        monitor(),
        foo_a("foo", a.spec()),
        bar_a("bar", a.spec()),
        baz_b("baz", b.spec())
    {
        debugger.attach({*my_frt.supervisor().GetTransport(), a.transport(), b.transport()});
        monitor = std::make_unique<RpcMappingMonitor>(my_frt.supervisor(), hist);
        a.names.push_back(foo_a.name);
        a.names.push_back(bar_a.name);
        b.names.push_back(baz_b.name);
    }
    ~RpcMappingMonitorTest() {
        monitor.reset();
        debugger.detach();
    }
};

TEST_F(RpcMappingMonitorTest, services_can_be_monitored) {
    monitor->start(foo_a, false);
    monitor->start(bar_a, false);
    monitor->start(baz_b, false);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() >= 3) &&
                        (hist.map[bar_a].samples() >= 3) &&
                        (hist.map[baz_b].samples() >= 3)); }));
    EXPECT_EQ(hist.map[foo_a].samples(State::DOWN), 0);
    EXPECT_EQ(hist.map[bar_a].samples(State::DOWN), 0);
    EXPECT_EQ(hist.map[baz_b].samples(State::DOWN), 0);
}

TEST_F(RpcMappingMonitorTest, hurry_means_faster) {
    monitor->start(foo_a, false);
    monitor->start(baz_b, true);
    auto t0 = debugger.time();
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[baz_b].samples() > 0)); }));
    EXPECT_EQ(hist.map[foo_a].samples(), 0);
    auto t1 = debugger.time();
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() > 0)); }));
    auto t2 = debugger.time();
    fprintf(stderr, "hurry: ~%zu ms, normal: ~%zu ms\n", count_ms(t1-t0), count_ms(t2-t0));
    EXPECT_GT((t2 - t0), 10 * (t1 - t0));
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
    EXPECT_EQ(hist.map[baz_b].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, stop_means_stop) {
    monitor->start(foo_a, false);
    monitor->start(baz_b, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[baz_b].samples() == 1)); }));
    monitor->stop(baz_b);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() == 3)); }));
    EXPECT_EQ(hist.map[baz_b].samples(), 1);
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
    EXPECT_EQ(hist.map[baz_b].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, health_checks_may_fail) {
    ServiceMapping bad_spec("foo", "this spec is invalid");
    ServiceMapping failed_ping("foo", a.spec());
    ServiceMapping missing_name("foo", b.spec());
    a.inject_fail_cnt = 2;
    monitor->start(bad_spec, true);
    monitor->start(failed_ping, true);
    monitor->start(missing_name, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[failed_ping].state() == State::UP); }));
    EXPECT_EQ(hist.map[bad_spec].state(), State::DOWN);
    EXPECT_EQ(hist.map[missing_name].state(), State::DOWN);
    EXPECT_EQ(hist.map[failed_ping].samples(State::DOWN), 2);
    EXPECT_EQ(hist.map[bad_spec].samples(State::UP), 0);
    EXPECT_EQ(hist.map[missing_name].samples(State::UP), 0);
}

TEST_F(RpcMappingMonitorTest, loss_of_idle_connection_is_detected_and_recovered) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::UP); }));
    ASSERT_TRUE(a.last_conn);
    a.last_conn->Owner()->Close(a.last_conn);
    a.set_last_conn(nullptr);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::DOWN); }));
    // down without new rpc check, will re-connect and come back up
    EXPECT_FALSE(a.last_conn);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::UP); }));
    EXPECT_EQ(hist.map[foo_a].samples(State::DOWN), 1);
}

TEST_F(RpcMappingMonitorTest, up_connection_is_reused) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto my_conn = a.last_conn;
    a.last_conn = nullptr;
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    EXPECT_EQ(a.last_conn, my_conn);
    my_conn->SubRef();
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, detect_ping_interval) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto t1 = debugger.time();
    a.set_last_conn(nullptr);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto t2 = debugger.time();
    fprintf(stderr, "ping interval: ~%zu ms\n", count_ms(t2-t1));
}

GTEST_MAIN_RUN_ALL_TESTS()
<commit_msg>Fix format strings.<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/slobrok/server/rpc_mapping_monitor.h>
#include <vespa/fnet/transport_debugger.h>
#include <vespa/fnet/transport_thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/vespalib/util/require.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <map>

using namespace vespalib;
using namespace slobrok;
using vespalib::make_string_short::fmt;

// simple rpc server implementing the required slobrok call-back API
struct Server : FRT_Invokable {
    fnet::frt::StandaloneFRT frt;
    std::vector<vespalib::string> names;
    size_t inject_fail_cnt;
    FNET_Connection *last_conn;
    void set_last_conn(FNET_Connection *conn) {
        if (last_conn) {
            last_conn->SubRef();
        }
        last_conn = conn;
        if (last_conn) {
            last_conn->AddRef();
        }
    }
    Server(fnet::TimeTools::SP time_tools) : frt(TransportConfig().time_tools(time_tools)), names(),
                                             inject_fail_cnt(0), last_conn(nullptr)
    {
        FRT_ReflectionBuilder rb(&frt.supervisor());
        rb.DefineMethod("slobrok.callback.listNamesServed", "", "S", FRT_METHOD(Server::rpc_listNamesServed), this);
        rb.DefineMethod("slobrok.callback.notifyUnregistered", "s", "", FRT_METHOD(Server::rpc_notifyUnregistered), this);
        REQUIRE(frt.supervisor().Listen(0));
    }
    ~Server() { set_last_conn(nullptr); }
    vespalib::string spec() const { return fmt("tcp/%d", frt.supervisor().GetListenPort()); }
    FNET_Transport &transport() { return *frt.supervisor().GetTransport(); }
    void rpc_listNamesServed(FRT_RPCRequest *req) {
        set_last_conn(req->GetConnection());
        if (inject_fail_cnt > 0) {
            req->SetError(FRTE_RPC_METHOD_FAILED, "fail injected by unit test");
            --inject_fail_cnt;
        } else {
            FRT_Values &dst = *req->GetReturn();
            FRT_StringValue *names_out = dst.AddStringArray(names.size());
            for (size_t i = 0; i < names.size(); ++i) {
                dst.SetString(&names_out[i], names[i].c_str());
            }
        }
    }
    void rpc_notifyUnregistered(FRT_RPCRequest *) {}
};

enum class State { ANY, UP, DOWN };

// Run-Length-Encoded historic state samples for a single service mapping
struct States {
    struct Entry {
        State state;
        size_t cnt;
    };
    std::vector<Entry> hist;
    State state() const { return hist.back().state; }
    States() : hist({{State::ANY, 0}}) {}
    void sample(State state) {
        if (state == hist.back().state) {
            ++hist.back().cnt;
        } else {
            hist.push_back(Entry{state, 1});
        }
    }
    size_t samples(State state = State::ANY) const {
        size_t n = 0;
        for (const auto &entry: hist) {
            if ((entry.state == state) || (state == State::ANY)) {
                n += entry.cnt;
            }
        }
        return n;
    }
};

// history of which call-backs we have gotten so far
struct History : MappingMonitorOwner {
    std::map<ServiceMapping, States> map;
    void up(const ServiceMapping &mapping) override { map[mapping].sample(State::UP); }
    void down(const ServiceMapping &mapping) override { map[mapping].sample(State::DOWN); }
};

struct RpcMappingMonitorTest : public ::testing::Test {
    fnet::TransportDebugger debugger;
    fnet::frt::StandaloneFRT my_frt;
    Server a;
    Server b;
    History hist;
    std::unique_ptr<RpcMappingMonitor> monitor;
    ServiceMapping foo_a;
    ServiceMapping bar_a;
    ServiceMapping baz_b;
    RpcMappingMonitorTest()
      : debugger(),
        my_frt(TransportConfig().time_tools(debugger.time_tools())),
        a(debugger.time_tools()),
        b(debugger.time_tools()),
        hist(),
        monitor(),
        foo_a("foo", a.spec()),
        bar_a("bar", a.spec()),
        baz_b("baz", b.spec())
    {
        debugger.attach({*my_frt.supervisor().GetTransport(), a.transport(), b.transport()});
        monitor = std::make_unique<RpcMappingMonitor>(my_frt.supervisor(), hist);
        a.names.push_back(foo_a.name);
        a.names.push_back(bar_a.name);
        b.names.push_back(baz_b.name);
    }
    ~RpcMappingMonitorTest() {
        monitor.reset();
        debugger.detach();
    }
};

TEST_F(RpcMappingMonitorTest, services_can_be_monitored) {
    monitor->start(foo_a, false);
    monitor->start(bar_a, false);
    monitor->start(baz_b, false);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() >= 3) &&
                        (hist.map[bar_a].samples() >= 3) &&
                        (hist.map[baz_b].samples() >= 3)); }));
    EXPECT_EQ(hist.map[foo_a].samples(State::DOWN), 0);
    EXPECT_EQ(hist.map[bar_a].samples(State::DOWN), 0);
    EXPECT_EQ(hist.map[baz_b].samples(State::DOWN), 0);
}

TEST_F(RpcMappingMonitorTest, hurry_means_faster) {
    monitor->start(foo_a, false);
    monitor->start(baz_b, true);
    auto t0 = debugger.time();
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[baz_b].samples() > 0)); }));
    EXPECT_EQ(hist.map[foo_a].samples(), 0);
    auto t1 = debugger.time();
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() > 0)); }));
    auto t2 = debugger.time();
    fprintf(stderr, "hurry: ~%" PRIu64 " ms, normal: ~%" PRIu64 " ms\n", count_ms(t1-t0), count_ms(t2-t0));
    EXPECT_GT((t2 - t0), 10 * (t1 - t0));
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
    EXPECT_EQ(hist.map[baz_b].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, stop_means_stop) {
    monitor->start(foo_a, false);
    monitor->start(baz_b, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[baz_b].samples() == 1)); }));
    monitor->stop(baz_b);
    EXPECT_TRUE(debugger.step_until([&]() {
                return ((hist.map[foo_a].samples() == 3)); }));
    EXPECT_EQ(hist.map[baz_b].samples(), 1);
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
    EXPECT_EQ(hist.map[baz_b].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, health_checks_may_fail) {
    ServiceMapping bad_spec("foo", "this spec is invalid");
    ServiceMapping failed_ping("foo", a.spec());
    ServiceMapping missing_name("foo", b.spec());
    a.inject_fail_cnt = 2;
    monitor->start(bad_spec, true);
    monitor->start(failed_ping, true);
    monitor->start(missing_name, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[failed_ping].state() == State::UP); }));
    EXPECT_EQ(hist.map[bad_spec].state(), State::DOWN);
    EXPECT_EQ(hist.map[missing_name].state(), State::DOWN);
    EXPECT_EQ(hist.map[failed_ping].samples(State::DOWN), 2);
    EXPECT_EQ(hist.map[bad_spec].samples(State::UP), 0);
    EXPECT_EQ(hist.map[missing_name].samples(State::UP), 0);
}

TEST_F(RpcMappingMonitorTest, loss_of_idle_connection_is_detected_and_recovered) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::UP); }));
    ASSERT_TRUE(a.last_conn);
    a.last_conn->Owner()->Close(a.last_conn);
    a.set_last_conn(nullptr);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::DOWN); }));
    // down without new rpc check, will re-connect and come back up
    EXPECT_FALSE(a.last_conn);
    EXPECT_TRUE(debugger.step_until([&]() {
                return (hist.map[foo_a].state() == State::UP); }));
    EXPECT_EQ(hist.map[foo_a].samples(State::DOWN), 1);
}

TEST_F(RpcMappingMonitorTest, up_connection_is_reused) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto my_conn = a.last_conn;
    a.last_conn = nullptr;
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    EXPECT_EQ(a.last_conn, my_conn);
    my_conn->SubRef();
    EXPECT_EQ(hist.map[foo_a].state(), State::UP);
}

TEST_F(RpcMappingMonitorTest, detect_ping_interval) {
    monitor->start(foo_a, true);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto t1 = debugger.time();
    a.set_last_conn(nullptr);
    EXPECT_TRUE(debugger.step_until([&]() { return (a.last_conn); }));
    auto t2 = debugger.time();
    fprintf(stderr, "ping interval: ~%" PRIu64 " ms\n", count_ms(t2-t1));
}

GTEST_MAIN_RUN_ALL_TESTS()
<|endoftext|>


<commit_before>#include <pangolin/python/PyInterpreter.h>
#include <pangolin/python/PyUniqueObj.h>

#include <Python.h>
#include <pangolin/python/PyModulePangolin.h>
#include <pangolin/python/PyInterpreter.h>
#include <pangolin/python/PyPangoIO.h>

namespace pangolin
{

PyInterpreter::PyInterpreter()
{
    Py_Initialize();

    InitPangoModule();

    PyRun_SimpleString(
        "import pangolin\n"
        "try:\n"
        "   import readline\n"
        "except ImportError:\n"
        "   import pyreadline as readline\n"
        "\n"
        "import rlcompleter\n"
        "pango_completer = rlcompleter.Completer()\n"
        "ui = pangolin.PangoVar('ui')\n"
    );

    PyObject* mod_sys = PyImport_ImportModule("sys");
    if(mod_sys) {
        PyModule_AddObject( mod_sys, "stdout", (PyObject*)new PyPangoIO(
                &PyPangoIO::Py_type, line_queue, ConsoleLineTypeStdout
        ) );
        PyModule_AddObject( mod_sys, "stderr", (PyObject*)new PyPangoIO(
                &PyPangoIO::Py_type, line_queue, ConsoleLineTypeStderr
        ) );
    }else{
        pango_print_error("Couldn't import module");
    }

}

PyInterpreter::~PyInterpreter()
{
    Py_Finalize();
}

std::string PyInterpreter::ToString(PyObject* py)
{
    PyUniqueObj pystr = PyObject_Repr(py);
    return std::string( PyString_AsString(pystr) );
}

void PyInterpreter::CheckPrintClearError()
{
    if(PyErr_Occurred()) {
        PyErr_Print();
        PyErr_Clear();
    }
}

PyUniqueObj PyInterpreter::EvalExec(const std::string& cmd)
{
    PyObject* globals = PyModule_GetDict(PyImport_AddModule("__main__"));
    PyObject* builtin = PyImport_AddModule("__builtin__");

    if(builtin) {
        PyUniqueObj compile = PyObject_GetAttrString(builtin, "compile");
        PyUniqueObj eval = PyObject_GetAttrString(builtin, "eval");

        if(compile && eval)
        {
            PyErr_Clear();
            PyUniqueObj compile_eval_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "eval" );
            if(compile_eval_args)
            {
                PyUniqueObj code = PyObject_Call(compile, compile_eval_args, 0);
                if(code) {
                    PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
                    if(eval_args) {
                        PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
                        CheckPrintClearError();
                        return ret;
                    }
                }
            }

            PyErr_Clear();
            PyUniqueObj compile_exec_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "exec" );
            if(compile_exec_args)
            {
                PyUniqueObj code = PyObject_Call(compile, compile_exec_args, 0);
                if(code) {
                    PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
                    if(eval_args) {
                        PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
                        CheckPrintClearError();
                        return ret;
                    }
                }
            }
        }
    }

    CheckPrintClearError();
    return PyUniqueObj();
}

std::vector<std::string> PyInterpreter::Complete(const std::string& cmd, int max_options)
{
    std::vector<std::string> ret;
    PyErr_Clear();

    PyObject* pymain = PyImport_AddModule("__main__");
    if(pymain) {
        PyObject* pycompleter = PyObject_GetAttrString(pymain,"pango_completer");
        if(pycompleter) {
            PyObject* pycomplete  = PyObject_GetAttrString(pycompleter,"complete");
            if(pycomplete) {
                for(int i=0; i < max_options; ++i) {
                    PyUniqueObj args = PyTuple_Pack( 2, PyString_FromString(cmd.c_str()), PyInt_FromSize_t(i) );
                    PyUniqueObj result = PyObject_CallObject(pycomplete, args);
                    if(result && PyString_Check(result) ) {
                        std::string res_str( PyString_AsString(result) );
                        if( res_str.find("__")==std::string::npos ||
                            cmd.find("__")!=std::string::npos ||
                            (cmd.size() > 0 && cmd[cmd.size()-1] == '_')
                        ) {
                            ret.push_back( res_str );
                        }
                    }else{
                        break;
                    }
                }
            }
        }
    }

    return ret;
}

void PyInterpreter::PushCommand(const std::string& cmd)
{
    PyUniqueObj obj = EvalExec(cmd);
    if(obj && obj != Py_None) {
        const std::string output = ToString(obj);
        line_queue.push(
            ConsoleLine(output, ConsoleLineTypeOutput)
        );
    }

    std::cout.flush();
    std::cerr.flush();
}

bool PyInterpreter::PullLine(ConsoleLine& line)
{
    if(line_queue.size()) {
        line = line_queue.front();
        line_queue.pop();
        return true;
    }else{
        return false;
    }
}

}
<commit_msg>Remove unnecessary iostream flush.<commit_after>#include <pangolin/python/PyInterpreter.h>
#include <pangolin/python/PyUniqueObj.h>

#include <Python.h>
#include <pangolin/python/PyModulePangolin.h>
#include <pangolin/python/PyInterpreter.h>
#include <pangolin/python/PyPangoIO.h>

namespace pangolin
{

PyInterpreter::PyInterpreter()
{
    Py_Initialize();

    InitPangoModule();

    PyRun_SimpleString(
        "import pangolin\n"
        "try:\n"
        "   import readline\n"
        "except ImportError:\n"
        "   import pyreadline as readline\n"
        "\n"
        "import rlcompleter\n"
        "pango_completer = rlcompleter.Completer()\n"
        "ui = pangolin.PangoVar('ui')\n"
    );

    PyObject* mod_sys = PyImport_ImportModule("sys");
    if(mod_sys) {
        PyModule_AddObject( mod_sys, "stdout", (PyObject*)new PyPangoIO(
                &PyPangoIO::Py_type, line_queue, ConsoleLineTypeStdout
        ) );
        PyModule_AddObject( mod_sys, "stderr", (PyObject*)new PyPangoIO(
                &PyPangoIO::Py_type, line_queue, ConsoleLineTypeStderr
        ) );
    }else{
        pango_print_error("Couldn't import module");
    }

}

PyInterpreter::~PyInterpreter()
{
    Py_Finalize();
}

std::string PyInterpreter::ToString(PyObject* py)
{
    PyUniqueObj pystr = PyObject_Repr(py);
    return std::string( PyString_AsString(pystr) );
}

void PyInterpreter::CheckPrintClearError()
{
    if(PyErr_Occurred()) {
        PyErr_Print();
        PyErr_Clear();
    }
}

PyUniqueObj PyInterpreter::EvalExec(const std::string& cmd)
{
    PyObject* globals = PyModule_GetDict(PyImport_AddModule("__main__"));
    PyObject* builtin = PyImport_AddModule("__builtin__");

    if(builtin) {
        PyUniqueObj compile = PyObject_GetAttrString(builtin, "compile");
        PyUniqueObj eval = PyObject_GetAttrString(builtin, "eval");

        if(compile && eval)
        {
            PyErr_Clear();
            PyUniqueObj compile_eval_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "eval" );
            if(compile_eval_args)
            {
                PyUniqueObj code = PyObject_Call(compile, compile_eval_args, 0);
                if(code) {
                    PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
                    if(eval_args) {
                        PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
                        CheckPrintClearError();
                        return ret;
                    }
                }
            }

            PyErr_Clear();
            PyUniqueObj compile_exec_args = Py_BuildValue("(sss)", cmd.c_str(), "<string>", "exec" );
            if(compile_exec_args)
            {
                PyUniqueObj code = PyObject_Call(compile, compile_exec_args, 0);
                if(code) {
                    PyUniqueObj eval_args = Py_BuildValue("(OOO)", *code, globals, globals );
                    if(eval_args) {
                        PyUniqueObj ret = PyObject_Call(eval, eval_args, 0);
                        CheckPrintClearError();
                        return ret;
                    }
                }
            }
        }
    }

    CheckPrintClearError();
    return PyUniqueObj();
}

std::vector<std::string> PyInterpreter::Complete(const std::string& cmd, int max_options)
{
    std::vector<std::string> ret;
    PyErr_Clear();

    PyObject* pymain = PyImport_AddModule("__main__");
    if(pymain) {
        PyObject* pycompleter = PyObject_GetAttrString(pymain,"pango_completer");
        if(pycompleter) {
            PyObject* pycomplete  = PyObject_GetAttrString(pycompleter,"complete");
            if(pycomplete) {
                for(int i=0; i < max_options; ++i) {
                    PyUniqueObj args = PyTuple_Pack( 2, PyString_FromString(cmd.c_str()), PyInt_FromSize_t(i) );
                    PyUniqueObj result = PyObject_CallObject(pycomplete, args);
                    if(result && PyString_Check(result) ) {
                        std::string res_str( PyString_AsString(result) );
                        if( res_str.find("__")==std::string::npos ||
                            cmd.find("__")!=std::string::npos ||
                            (cmd.size() > 0 && cmd[cmd.size()-1] == '_')
                        ) {
                            ret.push_back( res_str );
                        }
                    }else{
                        break;
                    }
                }
            }
        }
    }

    return ret;
}

void PyInterpreter::PushCommand(const std::string& cmd)
{
    PyUniqueObj obj = EvalExec(cmd);
    if(obj && obj != Py_None) {
        const std::string output = ToString(obj);
        line_queue.push(
            ConsoleLine(output, ConsoleLineTypeOutput)
        );
    }
}

bool PyInterpreter::PullLine(ConsoleLine& line)
{
    if(line_queue.size()) {
        line = line_queue.front();
        line_queue.pop();
        return true;
    }else{
        return false;
    }
}

}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    GaussianMinimumErrorClassifier.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

#include "OptionList.h"
#include "itkImage.h"
#include "itkReadMetaImage.h"
#include "itkWriteMetaImage.h"
#include "itkImageRegionIteratorWithIndex.h"

#include "vnl/vnl_matrix.h"

#include "itkImageListSampleAdaptor.h"
#include "itkSubsample.h"
#include "itkMembershipSample.h"
#include "itkMembershipSampleGenerator.h"
#include "itkGaussianDensityFunction.h"
#include "itkMeanCalculator.h"
#include "itkCovarianceCalculator.h"
#include "itkGenericClassifier.h"
#include "MaximumLikelihoodRatioDecisionRule.h"

void print_usage()
{
  std::cout << "GaussianMinimumErrorClassifier 1.0 (17. Dec. 2001)" << std::endl ;

  std::cout << "usage: GaussianMinimumErrorClassifier --training file"  << std::endl ;
  std::cout << "       --class-mask file" << std::endl ;
  std::cout << "       --target file"  << std::endl ;
  std::cout << "       --output file"  << std::endl ;

  std::cout << "" << std::endl ;

  std::cout << "--training file" << std::endl ;
  std::cout << "        image file name with intesnity values [meta image format]"
    << std::endl ;
  std::cout << "--class-mask file" << std::endl ;
  std::cout << "        image file name with class labels [meta image format]"
    << std::endl ;
  std::cout << "--target file" << std::endl ;
  std::cout << "        target image file name with intensity values [meta image format]"
    << std::endl ;
  std::cout << "--output file" << std::endl ;
  std::cout << "        output image file name that will have the class labels for pixels"
    << std::endl ;
  std::cout << "        in the target image file [meta image format]"  << std::endl ;

  std::cout << "" << std::endl ;

  std::cout << "example: GaussianMinimumErrorClassifier --training train.mhd" << std::endl ;
  std::cout << "         --class-mask class_mask.mhd" << std::endl ;
  std::cout << "         --target target.mhd" << std::endl ;
  std::cout << "         --output output.mhd" << std::endl ;
}

int main(int argc, char* argv[])
{
  namespace stat = itk::Statistics ;

  if (argc <= 1)
    {
      print_usage() ;
      exit(0) ;
    }

  OptionList options(argc, argv) ;

  std::string trainingFileName ;
  std::string classMaskFileName ;
  std::string targetFileName ;
  std::string outputFileName ;

  try
    {
      // get image file options
      options.GetStringOption("training", &trainingFileName, true) ;
      // get image file options
      options.GetStringOption("class-mask", &classMaskFileName, true) ;
      // get image file options
      options.GetStringOption("target", &targetFileName, true) ;
      // get image file options
      options.GetStringOption("output", &outputFileName, true) ;
    }
  catch(OptionList::RequiredOptionMissing e)
    {
      std::cout << "Error: The '" << e.OptionTag
                << "' option is required but missing."
                << std::endl ;
      return 1 ;
    }

  typedef itk::Image< short, 3 > ImageType ;
  typedef ImageType::Pointer ImagePointer ;

  ImagePointer training ;
  ImagePointer classMask ;
  ImagePointer target ;

  std::cout << "Loading image(s)..." << std::endl ;
  //      readMetaImageHeader(trainingFileName, trainingDimension, trainingSize) ;
  typedef itk::ReadMetaImage<ImageType> Reader ;
  Reader::Pointer reader = Reader::New() ;

  reader->SetFileName(trainingFileName.c_str()) ;
  reader->Update() ;
  training = reader->GetOutput() ;
  std::cout << "Training image loaded." << std::endl ;

  Reader::Pointer reader2 = Reader::New() ;
  reader2->SetFileName(classMaskFileName.c_str()) ;
  reader2->Update() ;
  classMask = reader2->GetOutput() ;
  std::cout << "Class mask loaded." << std::endl ;

  Reader::Pointer reader3 = Reader::New() ;
  reader3->SetFileName(targetFileName.c_str()) ;
  reader3->Update() ;
  target = reader3->GetOutput() ;
  std::cout << "Target image loaded." << std::endl ;

  /* ================================================== */
  std::cout << "Importing the images to samples..."
            << std::endl ;
  typedef stat::ImageListSampleAdaptor<ImageType, short, 1>
    ImageListSampleType;

  ImageListSampleType::Pointer sample =
    ImageListSampleType::New() ;

  ImageListSampleType::Pointer mask =
    ImageListSampleType::New() ;

  ImageListSampleType::Pointer targetSample =
    ImageListSampleType::New() ;

  sample->SetImage(training);
  mask->SetImage(classMask) ;
  targetSample->SetImage(target) ;
  /* ==================================================== */
  std::cout << "Creating the membership sample for training.." << std::endl ;
  typedef stat::MembershipSampleGenerator< ImageListSampleType,
    ImageListSampleType > MembershipSampleGeneratorType ;
  MembershipSampleGeneratorType::Pointer generator =
    MembershipSampleGeneratorType::New() ;

  generator->SetInput(sample) ;
  generator->SetClassMask(mask) ;
  generator->GenerateData() ;
  MembershipSampleGeneratorType::OutputPointer membershipSample =
    generator->GetOutput() ;
  unsigned int numberOfClasses = membershipSample->GetNumberOfClasses() ;
  /* =================================================== */
  std::cout << "Inducing the gaussian density function parameters and apriori probabilities..."
            << std::endl ;
  typedef ImageListSampleType::MeasurementVectorType
    MeasurementVectorType ;
  typedef stat::GaussianDensityFunction< MeasurementVectorType >
    DensityFunctionType ;
  typedef DensityFunctionType::Pointer DensityFunctionPointer ;
  std::vector< DensityFunctionPointer > densityFunctions ;
  densityFunctions.resize(numberOfClasses) ;

  typedef MembershipSampleGeneratorType::OutputType::ClassSampleType
    ClassSampleType ;
  typedef stat::MeanCalculator< ClassSampleType >
    MeanCalculatorType ;
  typedef stat::CovarianceCalculator< ClassSampleType >
    CovarianceCalculatorType ;
  MeanCalculatorType::Pointer meanCalculator = MeanCalculatorType::New() ;
  CovarianceCalculatorType::Pointer covarianceCalculator =
    CovarianceCalculatorType::New() ;
  vnl_vector< double > mean ;
  vnl_matrix< double > covariance ;

  typedef MaximumLikelihoodRatioDecisionRule DecisionRuleType ;
  DecisionRuleType::Pointer rule = DecisionRuleType::New() ;

  unsigned int sampleSize = 0 ;

  for (unsigned int i = 0 ; i < numberOfClasses ; i++)
    {
      meanCalculator->SetSample(membershipSample->GetClassSample(i)) ;
      meanCalculator->GenerateData() ;
      mean = meanCalculator->GetOutput() ;

      covarianceCalculator->SetSample(membershipSample->GetClassSample(i)) ;
      covarianceCalculator->SetMean(mean) ;
      covarianceCalculator->GenerateData() ;
      covariance = covarianceCalculator->GetOutput() ;

      densityFunctions[i] = DensityFunctionType::New() ;
      (densityFunctions[i])->SetMean(mean) ;
      (densityFunctions[i])->SetCovariance(covariance) ;
      std::cout << "gaussian [" << i << "]" << std::endl ;
      std::cout << "  mean = " << (densityFunctions[i])->GetMean()
                << std::endl ;
      std::cout << "  covariance = " << std::endl ;
      (densityFunctions[i])->GetCovariance().print(std::cout) ;

      // add the class sample size to the decision rule
      // for the a priori probability calculation
      std::cout << "  Sample size = " ;
      sampleSize = (membershipSample->GetClassSample(i))->GetSize(0) ;
      std::cout << sampleSize << std::endl ;
      rule->AddClassSampleSize(sampleSize) ;
    }
  /* =================================================== */
  std::cout << "Classifying..." << std::endl ;

  typedef stat::GenericClassifier< ImageListSampleType, DensityFunctionType, DecisionRuleType > ClassifierType ;

  ClassifierType::Pointer classifier = ClassifierType::New() ;
  classifier->SetSample(targetSample) ;
  for (unsigned int i = 0 ; i < numberOfClasses ; i++)
    {
      classifier->AddMembershipCalculator(densityFunctions[i]) ;
    }

  classifier->SetDecisionRule(rule) ;

  classifier->GenerateData() ;

  ClassifierType::OutputPointer result = classifier->GetOutput() ;

  /* ===================================================== */
  std::cout << "Creating a image with result class labels..." << std::endl ;
  typedef itk::WriteMetaImage< ImageType > Writer ;
  Writer::Pointer writer = Writer::New() ;

  ImagePointer output = ImageType::New() ;
  output->SetBufferedRegion(target->GetLargestPossibleRegion()) ;
  output->SetLargestPossibleRegion(target->GetLargestPossibleRegion()) ;
  output->Allocate() ;
  typedef itk::ImageRegionIteratorWithIndex< ImageType > ImageIteratorType ;
  ImageIteratorType i_iter(output, output->GetLargestPossibleRegion()) ;
  i_iter.GoToBegin() ;
  ClassifierType::OutputType::Iterator m_iter = result->Begin() ;
  while (!i_iter.IsAtEnd())
    {
      i_iter.Set((ImageType::PixelType)m_iter.GetClassLabel()) ;
      ++i_iter ;
      ++m_iter ;
    }

  writer->SetInput(output) ;
  writer->SetFileName(outputFileName.c_str()) ;
  writer->GenerateData() ;

  return 0 ;
}

<commit_msg>ENH: now using itkLookupTableClassifier instead of itkGenericClassifier for better performance.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    GaussianMinimumErrorClassifier.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

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

#include "OptionList.h"
#include "itkImage.h"
#include "itkReadMetaImage.h"
#include "itkWriteMetaImage.h"
#include "itkImageRegionIteratorWithIndex.h"

#include "vnl/vnl_matrix.h"

#include "itkImageListSampleAdaptor.h"
#include "itkSubsample.h"
#include "itkMembershipSample.h"
#include "itkMembershipSampleGenerator.h"
#include "itkGaussianDensityFunction.h"
#include "itkMeanCalculator.h"
#include "itkCovarianceCalculator.h"
#include "itkTableLookupClassifier.h"
#include "MaximumLikelihoodRatioDecisionRule.h"

void print_usage()
{
  std::cout << "GaussianMinimumErrorClassifier 1.0 (17. Dec. 2001)" << std::endl ;

  std::cout << "usage: GaussianMinimumErrorClassifier --training file"  << std::endl ;
  std::cout << "       --class-mask file" << std::endl ;
  std::cout << "       --target file"  << std::endl ;
  std::cout << "       --output file"  << std::endl ;

  std::cout << "" << std::endl ;

  std::cout << "--training file" << std::endl ;
  std::cout << "        image file name with intesnity values [meta image format]"
            << std::endl ;
  std::cout << "--class-mask file" << std::endl ;
  std::cout << "        image file name with class labels [meta image format]"
            << std::endl ;
  std::cout << "--target file" << std::endl ;
  std::cout << "        target image file name with intensity values [meta image format]"
            << std::endl ;
  std::cout << "--output file" << std::endl ;
  std::cout << "        output image file name that will have the class labels for pixels"
            << std::endl ;
  std::cout << "        in the target image file [meta image format]"  << std::endl ;

  std::cout << "" << std::endl ;

  std::cout << "example: GaussianMinimumErrorClassifier --training train.mhd" << std::endl ;
  std::cout << "         --class-mask class_mask.mhd" << std::endl ;
  std::cout << "         --target target.mhd" << std::endl ;
  std::cout << "         --output output.mhd" << std::endl ;
}

int main(int argc, char* argv[])
{
  namespace stat = itk::Statistics ;

  if (argc <= 1)
    {
      print_usage() ;
      exit(0) ;
    }

  OptionList options(argc, argv) ;

  std::string trainingFileName ;
  std::string classMaskFileName ;
  std::string targetFileName ;
  std::string outputFileName ;

  try
    {
      // get image file options
      options.GetStringOption("training", &trainingFileName, true) ;
      // get image file options
      options.GetStringOption("class-mask", &classMaskFileName, true) ;
      // get image file options
      options.GetStringOption("target", &targetFileName, true) ;
      // get image file options
      options.GetStringOption("output", &outputFileName, true) ;
    }
  catch(OptionList::RequiredOptionMissing e)
    {
      std::cout << "Error: The '" << e.OptionTag
                << "' option is required but missing."
                << std::endl ;
      return 1 ;
    }

  typedef itk::Image< short, 3 > ImageType ;
  typedef ImageType::Pointer ImagePointer ;

  ImagePointer training ;
  ImagePointer classMask ;
  ImagePointer target ;

  std::cout << "Loading image(s)..." << std::endl ;
  //      readMetaImageHeader(trainingFileName, trainingDimension, trainingSize) ;
  typedef itk::ReadMetaImage<ImageType> Reader ;
  Reader::Pointer reader = Reader::New() ;

  reader->SetFileName(trainingFileName.c_str()) ;
  reader->Update() ;
  training = reader->GetOutput() ;
  std::cout << "Training image loaded." << std::endl ;

  Reader::Pointer reader2 = Reader::New() ;
  reader2->SetFileName(classMaskFileName.c_str()) ;
  reader2->Update() ;
  classMask = reader2->GetOutput() ;
  std::cout << "Class mask loaded." << std::endl ;

  Reader::Pointer reader3 = Reader::New() ;
  reader3->SetFileName(targetFileName.c_str()) ;
  reader3->Update() ;
  target = reader3->GetOutput() ;
  std::cout << "Target image loaded." << std::endl ;

  /* ================================================== */
  std::cout << "Importing the images to samples..."
            << std::endl ;
  typedef stat::ImageListSampleAdaptor< ImageType, stat::ScalarAccessor< ImageType > >
    ImageListSampleType;

  ImageListSampleType::Pointer sample =
    ImageListSampleType::New() ;

  ImageListSampleType::Pointer mask =
    ImageListSampleType::New() ;

  ImageListSampleType::Pointer targetSample =
    ImageListSampleType::New() ;

  sample->SetImage(training);
  mask->SetImage(classMask) ;
  targetSample->SetImage(target) ;
  /* ==================================================== */
  std::cout << "Creating the membership sample for training.." << std::endl ;
  typedef stat::MembershipSampleGenerator< ImageListSampleType,
    ImageListSampleType > MembershipSampleGeneratorType ;
  MembershipSampleGeneratorType::Pointer generator =
    MembershipSampleGeneratorType::New() ;

  generator->SetInput(sample) ;
  generator->SetClassMask(mask) ;
  generator->SetNumberOfClasses(10) ;
  generator->GenerateData() ;
  MembershipSampleGeneratorType::OutputPointer membershipSample =
    generator->GetOutput() ;
  unsigned int numberOfClasses = membershipSample->GetNumberOfClasses() ;
  std::cout << "Generating class samples..."
            << std::endl ;
  membershipSample->GenerateClassSamples() ;

  /* =================================================== */
  std::cout << "Inducing the gaussian density function parameters and apriori probabilities..."
            << std::endl ;
  typedef ImageListSampleType::MeasurementVectorType
    MeasurementVectorType ;
  typedef stat::GaussianDensityFunction< MeasurementVectorType >
    DensityFunctionType ;
  typedef DensityFunctionType::Pointer DensityFunctionPointer ;
  std::vector< DensityFunctionPointer > densityFunctions ;
  densityFunctions.resize(numberOfClasses) ;

  typedef MembershipSampleGeneratorType::OutputType::ClassSampleType
    ClassSampleType ;
  typedef stat::MeanCalculator< ClassSampleType >
    MeanCalculatorType ;
  typedef stat::CovarianceCalculator< ClassSampleType >
    CovarianceCalculatorType ;
  MeanCalculatorType::Pointer meanCalculator = MeanCalculatorType::New() ;
  CovarianceCalculatorType::Pointer covarianceCalculator =
    CovarianceCalculatorType::New() ;
  vnl_vector< double > mean ;
  vnl_matrix< double > covariance ;

  typedef MaximumLikelihoodRatioDecisionRule DecisionRuleType ;
  DecisionRuleType::Pointer rule = DecisionRuleType::New() ;

  unsigned int sampleSize = 0 ;
  std::cout << "Inducing the gaussian density function parameters and apriori probabilities..." << std::endl ;
  std::cout << "number of classes = " << numberOfClasses << std::endl ;
  for (unsigned int i = 0 ; i < numberOfClasses ; i++)
    {
      std::cout << "gaussian [" << i << "]" << std::endl ;
      // add the class sample size to the decision rule
      // for the a priori probability calculation
      std::cout << "  Sample size = " ;
      sampleSize = membershipSample->GetClassSampleSize(i) ;
      std::cout << sampleSize << std::endl ;
      rule->AddClassSampleSize(sampleSize) ;

      ClassSampleType::Pointer subSample =
        membershipSample->GetClassSample(i) ;
      meanCalculator->SetSample(subSample) ;
      meanCalculator->GenerateData() ;
      mean = meanCalculator->GetOutput() ;

      covarianceCalculator->SetSample(subSample) ;
      covarianceCalculator->SetMean(mean) ;
      covarianceCalculator->GenerateData() ;
      covariance = covarianceCalculator->GetOutput() ;

      densityFunctions[i] = DensityFunctionType::New() ;
      (densityFunctions[i])->SetMean(mean) ;
      (densityFunctions[i])->SetCovariance(covariance) ;
      std::cout << "  mean = " << (densityFunctions[i])->GetMean()
                << std::endl ;
      std::cout << "  covariance = " << std::endl ;
      (densityFunctions[i])->GetCovariance().print(std::cout) ;

    }

  typedef itk::ImageRegionIteratorWithIndex< ImageType > ImageIteratorType ;
  ImageIteratorType t_iter(target, target->GetLargestPossibleRegion()) ;
  short temp ;
  while (!t_iter.IsAtEnd())
    {
      if (temp < t_iter.Get())
        {
          temp = t_iter.Get() ;
        }
      ++t_iter ;
    }
  std::cout << "Max value = " << temp << std::endl ;
  /* =================================================== */
  std::cout << "Classifying..." << std::endl ;

  typedef stat::TableLookupClassifier< ImageListSampleType, DensityFunctionType, DecisionRuleType > ClassifierType ;

  ClassifierType::Pointer classifier = ClassifierType::New() ;
  classifier->SetSample(targetSample) ;
  for (unsigned int i = 0 ; i < numberOfClasses ; i++)
    {
      classifier->AddMembershipCalculator(densityFunctions[i]) ;
    }

  classifier->SetDecisionRule(rule) ;
  ClassifierType::CachedMeasurementVectorType upper ;
  ClassifierType::CachedMeasurementVectorType lower ;
  upper[0] = temp ;
  lower[0] = 0 ;
  classifier->SetLookupTableLowerBound(lower) ;
  classifier->SetLookupTableUpperBound(upper) ;
  classifier->GenerateData() ;

  ClassifierType::OutputPointer result = classifier->GetOutput() ;

  /* ===================================================== */
  std::cout << "Creating a image with result class labels..." << std::endl ;
  typedef itk::WriteMetaImage< ImageType > Writer ;
  Writer::Pointer writer = Writer::New() ;

  ImagePointer output = ImageType::New() ;
  output->SetBufferedRegion(target->GetLargestPossibleRegion()) ;
  output->SetLargestPossibleRegion(target->GetLargestPossibleRegion()) ;
  output->Allocate() ;
  ImageIteratorType i_iter(output, output->GetLargestPossibleRegion()) ;
  i_iter.GoToBegin() ;
  ClassifierType::OutputType::Iterator m_iter = result->Begin() ;
  while (!i_iter.IsAtEnd())
    {
      i_iter.Set((ImageType::PixelType)m_iter.GetClassLabel()) ;
      ++i_iter ;
      ++m_iter ;
    }

  writer->SetInput(output) ;
  writer->SetFileName(outputFileName.c_str()) ;
  writer->GenerateData() ;

  return 0 ;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkImageDecoder.h"
#include "SkStream.h"

namespace skiagm {

/** Draw a CMYK encoded jpeg - libjpeg doesn't support CMYK->RGB
    conversion so this tests Skia's internal processing
*/
class CMYKJpegGM : public GM {
public:
    CMYKJpegGM() {

        // parameters to the "decode" call
        bool dither = false;
        SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;

        SkString filename(INHERITED::gResourcePath);
        if (!filename.endsWith("/") && !filename.endsWith("\\")) {
            filename.append("/");
        }

        filename.append("CMYK.jpg");

        SkFILEStream stream(filename.c_str());
        SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
        if (codec) {
            stream.rewind();
            codec->setDitherImage(dither);
            codec->decode(&stream, &fBitmap, prefConfig,
                          SkImageDecoder::kDecodePixels_Mode);
        }
    }

protected:
    virtual SkString onShortName() {
        return SkString("cmykjpeg");
    }

    virtual SkISize onISize() {
        return make_isize(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {

        canvas->translate(20*SK_Scalar1, 20*SK_Scalar1);
        canvas->drawBitmap(fBitmap, 0, 0);
    }

private:
    SkBitmap fBitmap;

    typedef GM INHERITED;
};

void forceLinking();

void forceLinking() {
    SkImageDecoder *creator = CreateJPEGImageDecoder();
    SkASSERT(creator);
}

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new CMYKJpegGM; }
static GMRegistry reg(MyFactory);

}
<commit_msg>Fix a memory leak in cmykjpeg GM.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkImageDecoder.h"
#include "SkStream.h"

namespace skiagm {

/** Draw a CMYK encoded jpeg - libjpeg doesn't support CMYK->RGB
    conversion so this tests Skia's internal processing
*/
class CMYKJpegGM : public GM {
public:
    CMYKJpegGM() {

        // parameters to the "decode" call
        bool dither = false;
        SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;

        SkString filename(INHERITED::gResourcePath);
        if (!filename.endsWith("/") && !filename.endsWith("\\")) {
            filename.append("/");
        }

        filename.append("CMYK.jpg");

        SkFILEStream stream(filename.c_str());
        SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
        if (codec) {
            stream.rewind();
            codec->setDitherImage(dither);
            codec->decode(&stream, &fBitmap, prefConfig,
                          SkImageDecoder::kDecodePixels_Mode);
            SkDELETE(codec);
        }
    }

protected:
    virtual SkString onShortName() {
        return SkString("cmykjpeg");
    }

    virtual SkISize onISize() {
        return make_isize(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {

        canvas->translate(20*SK_Scalar1, 20*SK_Scalar1);
        canvas->drawBitmap(fBitmap, 0, 0);
    }

private:
    SkBitmap fBitmap;

    typedef GM INHERITED;
};

void forceLinking();

void forceLinking() {
    SkImageDecoder *creator = CreateJPEGImageDecoder();
    SkASSERT(creator);
}

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new CMYKJpegGM; }
static GMRegistry reg(MyFactory);

}
<|endoftext|>