<commit_before>// Copyright (C) 2019 by Pedro Mendes, Rector and Visitors of the
// University of Virginia, University of Heidelberg, and University
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QDesktopServices>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlSimpleReader>

#include "CQNotes.h"
#include "copasi/CopasiDataModel/CDataModel.h"

#if defined(QT_USE_TEXTBROWSER)
# include <QTextBrowser>
#elif !defined(QT5_USE_WEBENGINE)
# include <QWebView>
# include <QWebFrame>
#else  // QT5_USE_WEBENGINE
# include <QWebEngineView>
# include <QWebEnginePage>

CQWebEnginePage::CQWebEnginePage(QObject* parent)
  : QWebEnginePage(parent)
{
}

bool
CQWebEnginePage::acceptNavigationRequest(const QUrl & url,
    QWebEnginePage::NavigationType type, bool isMainFrame)
{
  if (type == QWebEnginePage::NavigationTypeLinkClicked)
    {
      QDesktopServices::openUrl(url);
      return false;
    }

  return true;
}

#endif // QT_USE_TEXTBROWSER

#include "copasi/resourcesUI/CQIconResource.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "copasi/model/CModelValue.h"
#include "copasi/model/CReaction.h"
#include "copasi/model/CEvent.h"
#include "copasi/function/CFunction.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/report/CReportDefinition.h"
#include "copasi/core/CRootContainer.h"
#include "copasi/commandline/CConfigurationFile.h"

#include <copasi/UI/copasiui3window.h>
#include <copasi/UI/CQCopasiApplication.h>

CQValidatorXML::CQValidatorXML(QPlainTextEdit * parent, const char * name):
  CQValidator< QPlainTextEdit >(parent, &QPlainTextEdit::toPlainText, name),
  mIsFreeText(true),
  mNeedsWrap(false)
{}

// virtual
QValidator::State CQValidatorXML::validate(QString & input, int & pos) const
{
  QXmlSimpleReader Validator;
  QXmlInputSource Input;
  CQNotesContentHandler ContentHandler;

  Validator.setContentHandler(&ContentHandler);

  // We like to allow free text and therefore wrap the text to create valid XML.
  Input.setData("<Validate:XML xmlns:Validate=\"http://www.copasi.org/Validate\">" + input + "</Validate:XML>");

  if (Validator.parse(Input))
    {
      mIsFreeText = ContentHandler.isFreeText();
      mNeedsWrap = ContentHandler.needsWrap();
      return CQValidator< QPlainTextEdit >::validate(input, pos);
    }

  mIsFreeText = true;
  mNeedsWrap = false;
  setColor(Invalid);
  return Intermediate;
}

const bool & CQValidatorXML::isFreeText() const
{
  return mIsFreeText;
}

const bool & CQValidatorXML::needsWrap() const
{
  return mNeedsWrap;
}

CQNotesContentHandler::CQNotesContentHandler():
  QXmlDefaultHandler(),
  mIsFreeText(true),
  mNeedsWrap(true),
  mLevel(0)
{}

CQNotesContentHandler:: ~CQNotesContentHandler()
{}

// virtual
bool CQNotesContentHandler::startDocument()
{
  mIsFreeText = true;
  mNeedsWrap = true;
  mLevel = 0;
  return true;
}

// virtual
bool CQNotesContentHandler::startElement(const QString & namespaceURI,
    const QString & localName,
    const QString & qName,
    const QXmlAttributes & atts)
{
  if (namespaceURI != "http://www.copasi.org/Validate" ||
      qName != "Validate:XML")
    mIsFreeText = false;

  if (mLevel == 1 &&
      namespaceURI == "http://www.w3.org/1999/xhtml" &&
      (localName == "html" || localName == "body"))
    mNeedsWrap = false;

  mLevel++;

  return QXmlDefaultHandler::startElement(namespaceURI, localName, qName, atts);
}

// virtual
bool CQNotesContentHandler::endElement(const QString & namespaceURI,
                                       const QString & localName,
                                       const QString & qName)
{
  mLevel--;

  return QXmlDefaultHandler::endElement(namespaceURI, localName, qName);
}

const bool & CQNotesContentHandler::isFreeText() const
{
  return mIsFreeText;
}

bool CQNotesContentHandler::needsWrap() const
{
  return (mNeedsWrap && !mIsFreeText);
}

CQNotes::CQNotes(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mEditMode(false),
  mChanged(false),
  mpValidatorXML(NULL),
  mValidity(QValidator::Acceptable),
  mObjectCNToCopy()
  , mpWebView(NULL)

{
  setupUi(this);

  mpValidatorXML = new CQValidatorXML(mpEdit);

#if defined(QT_USE_TEXTBROWSER)
  mpWebView = new QTextBrowser(this);
  connect(mpWebView, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
#elif !defined(QT5_USE_WEBENGINE)
  mpWebView = new QWebView(this);
  static_cast<QWebView*>(mpWebView)->
  page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
  connect(mpWebView, SIGNAL(linkClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
#else
  mpWebView = new QWebEngineView(this);
  static_cast<QWebEngineView*>(mpWebView)->setPage(new CQWebEnginePage);
  connect(mpWebView, SIGNAL(urlChanged(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
#endif

  mpVerticalLayout->addWidget(mpWebView);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
}

CQNotes::~CQNotes()
{}

void CQNotes::slotBtnCopy()
{
  mObjectCNToCopy = mObjectCN;
}

// virtual
bool CQNotes::updateProtected(ListViews::ObjectType objectType, ListViews::Action action, const CCommonName & cn)
{
  if (mIgnoreUpdates || !isVisible())
    {
      return true;
    }

  switch (action)
    {
      case ListViews::CHANGE:

        if (cn == mObjectCN)
          {
            load();
          }

        break;

      case ListViews::DELETE:

        if (cn == mObjectCN || objectType == ListViews::ObjectType::MODEL)
          {
            mpObject = NULL;
            mObjectCN.clear();
          }

        break;

      default:
        break;
    }

  if (objectType == ListViews::ObjectType::MODEL &&
      action == ListViews::DELETE)
    {
      mEditMode = false;
    }

  return true;
}

// virtual
bool CQNotes::leaveProtected()
{
  if (mpObject != NULL)
    {
      save();
    }
  else
    {
      mObjectCN.clear();
    }

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  if (mObjectCNToCopy == "")
    {
      load();
    }
  else
    {
      CObjectInterface::ContainerList List;
      List.push_back(mpDataModel);

      // This will check the current data model and the root container for the object;
      mpObject = const_cast< CDataObject * >(CObjectInterface::DataObject(CObjectInterface::GetObjectFromCN(List, mObjectCNToCopy)));
      load();
      mpObject = const_cast< CDataObject * >(CObjectInterface::DataObject(CObjectInterface::GetObjectFromCN(List, mObjectCN)));
      save();
      mObjectCN.clear();
    }

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::slotValidateXML()
{
  QString Input = mpEdit->toPlainText();
  int pos = 0;

  mValidity = mpValidatorXML->validate(Input, pos);

  if (mpValidatorXML->isFreeText())
    {
      mEditMode = true;
      mpBtnToggleEdit->hide();
    }
  else
    {
      mpBtnToggleEdit->show();
    }

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::load()
{
  if (mpObject != NULL)
    {
      QString Notes;

      CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
      CReportDefinition * pReportDefinition = dynamic_cast< CReportDefinition * >(mpObject);

      if (pAnnotation != NULL)
        {
          Notes = FROM_UTF8(pAnnotation->getNotes());
        }
      else if (pReportDefinition != NULL)
        {
          Notes = FROM_UTF8(pReportDefinition->getComment());
        }

      // The notes are UTF8 encoded however the html does not specify an encoding
      // thus Qt uses locale settings.
#if defined(QT_USE_TEXTBROWSER)
      static_cast<QTextBrowser*>(mpWebView)->setHtml(Notes);
#elif !defined(QT5_USE_WEBENGINE)
      static_cast<QWebView*>(mpWebView)->setHtml(Notes);
#else
      static_cast<QWebEngineView*>(mpWebView)->setHtml(Notes);
#endif
      mpEdit->setPlainText(Notes);
      mLoadedText = mpEdit->toPlainText();

      mpValidatorXML->saved();
      slotValidateXML();

      if (!mpValidatorXML->isFreeText() && mEditMode)
        {
          slotToggleMode();
        }

      mValidity = QValidator::Acceptable;
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  if (mpObject == NULL ||
      mValidity != QValidator::Acceptable)
    return;

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = dynamic_cast<CReportDefinition *>(mpObject);

  std::string notes;

  if (pAnnotation != NULL)
    {
      notes = pAnnotation->getNotes();
    }
  else if (pReportDefinition != NULL)
    {
      notes = pReportDefinition->getComment();
    }

  QString currentPlainText = mpEdit->toPlainText();
  std::string plainText = TO_UTF8(mpEdit->toPlainText());

  if (plainText == notes)
    return;

  if (mLoadedText == currentPlainText)
    return;

  if (mpValidatorXML->needsWrap())
    {
      // We wrap the HTML in a body element if it does not contain a top level html or body element.
      plainText = "<body xmlns=\"http://www.w3.org/1999/xhtml\">" + plainText + "</body>";
    }

  CUndoData UndoData(CUndoData::Type::CHANGE, mpObject->toData());
  UndoData.addProperty(CData::Property::NOTES, notes, plainText);
  ListViews::addUndoMetaData(this, UndoData);

  slotNotifyChanges(mpDataModel->applyData(UndoData));
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QString scheme = url.scheme();

  if (scheme == "about" || scheme == "data")
    return;

  if (scheme == "copasi")
    {
      dynamic_cast<CQCopasiApplication*>(qApp)->getMainWindow()->slotHandleCopasiScheme(url);
      return;
    }

  QDesktopServices::openUrl(url);
  return;
}
<commit_msg>- issue 2874: disable opening links in QTextBrowser (anchorClicked will still be emitted)<commit_after>// Copyright (C) 2019 - 2020 by Pedro Mendes, Rector and Visitors of the
// University of Virginia, University of Heidelberg, and University
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QDesktopServices>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlSimpleReader>

#include "CQNotes.h"
#include "copasi/CopasiDataModel/CDataModel.h"

#if defined(QT_USE_TEXTBROWSER)
# include <QTextBrowser>
#elif !defined(QT5_USE_WEBENGINE)
# include <QWebView>
# include <QWebFrame>
#else  // QT5_USE_WEBENGINE
# include <QWebEngineView>
# include <QWebEnginePage>

CQWebEnginePage::CQWebEnginePage(QObject* parent)
  : QWebEnginePage(parent)
{
}

bool
CQWebEnginePage::acceptNavigationRequest(const QUrl & url,
    QWebEnginePage::NavigationType type, bool isMainFrame)
{
  if (type == QWebEnginePage::NavigationTypeLinkClicked)
    {
      QDesktopServices::openUrl(url);
      return false;
    }

  return true;
}

#endif // QT_USE_TEXTBROWSER

#include "copasi/resourcesUI/CQIconResource.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "copasi/model/CModelValue.h"
#include "copasi/model/CReaction.h"
#include "copasi/model/CEvent.h"
#include "copasi/function/CFunction.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/report/CReportDefinition.h"
#include "copasi/core/CRootContainer.h"
#include "copasi/commandline/CConfigurationFile.h"

#include <copasi/UI/copasiui3window.h>
#include <copasi/UI/CQCopasiApplication.h>

CQValidatorXML::CQValidatorXML(QPlainTextEdit * parent, const char * name):
  CQValidator< QPlainTextEdit >(parent, &QPlainTextEdit::toPlainText, name),
  mIsFreeText(true),
  mNeedsWrap(false)
{}

// virtual
QValidator::State CQValidatorXML::validate(QString & input, int & pos) const
{
  QXmlSimpleReader Validator;
  QXmlInputSource Input;
  CQNotesContentHandler ContentHandler;

  Validator.setContentHandler(&ContentHandler);

  // We like to allow free text and therefore wrap the text to create valid XML.
  Input.setData("<Validate:XML xmlns:Validate=\"http://www.copasi.org/Validate\">" + input + "</Validate:XML>");

  if (Validator.parse(Input))
    {
      mIsFreeText = ContentHandler.isFreeText();
      mNeedsWrap = ContentHandler.needsWrap();
      return CQValidator< QPlainTextEdit >::validate(input, pos);
    }

  mIsFreeText = true;
  mNeedsWrap = false;
  setColor(Invalid);
  return Intermediate;
}

const bool & CQValidatorXML::isFreeText() const
{
  return mIsFreeText;
}

const bool & CQValidatorXML::needsWrap() const
{
  return mNeedsWrap;
}

CQNotesContentHandler::CQNotesContentHandler():
  QXmlDefaultHandler(),
  mIsFreeText(true),
  mNeedsWrap(true),
  mLevel(0)
{}

CQNotesContentHandler:: ~CQNotesContentHandler()
{}

// virtual
bool CQNotesContentHandler::startDocument()
{
  mIsFreeText = true;
  mNeedsWrap = true;
  mLevel = 0;
  return true;
}

// virtual
bool CQNotesContentHandler::startElement(const QString & namespaceURI,
    const QString & localName,
    const QString & qName,
    const QXmlAttributes & atts)
{
  if (namespaceURI != "http://www.copasi.org/Validate" ||
      qName != "Validate:XML")
    mIsFreeText = false;

  if (mLevel == 1 &&
      namespaceURI == "http://www.w3.org/1999/xhtml" &&
      (localName == "html" || localName == "body"))
    mNeedsWrap = false;

  mLevel++;

  return QXmlDefaultHandler::startElement(namespaceURI, localName, qName, atts);
}

// virtual
bool CQNotesContentHandler::endElement(const QString & namespaceURI,
                                       const QString & localName,
                                       const QString & qName)
{
  mLevel--;

  return QXmlDefaultHandler::endElement(namespaceURI, localName, qName);
}

const bool & CQNotesContentHandler::isFreeText() const
{
  return mIsFreeText;
}

bool CQNotesContentHandler::needsWrap() const
{
  return (mNeedsWrap && !mIsFreeText);
}

CQNotes::CQNotes(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mEditMode(false),
  mChanged(false),
  mpValidatorXML(NULL),
  mValidity(QValidator::Acceptable),
  mObjectCNToCopy()
  , mpWebView(NULL)

{
  setupUi(this);

  mpValidatorXML = new CQValidatorXML(mpEdit);

#if defined(QT_USE_TEXTBROWSER)
  mpWebView = new QTextBrowser(this);
  connect(mpWebView, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
  static_cast< QTextBrowser * >(mpWebView)->setOpenLinks(false);

#elif !defined(QT5_USE_WEBENGINE)
  mpWebView = new QWebView(this);
  static_cast<QWebView*>(mpWebView)->
  page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
  connect(mpWebView, SIGNAL(linkClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
#else
  mpWebView = new QWebEngineView(this);
  static_cast<QWebEngineView*>(mpWebView)->setPage(new CQWebEnginePage);
  connect(mpWebView, SIGNAL(urlChanged(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
#endif

  mpVerticalLayout->addWidget(mpWebView);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
}

CQNotes::~CQNotes()
{}

void CQNotes::slotBtnCopy()
{
  mObjectCNToCopy = mObjectCN;
}

// virtual
bool CQNotes::updateProtected(ListViews::ObjectType objectType, ListViews::Action action, const CCommonName & cn)
{
  if (mIgnoreUpdates || !isVisible())
    {
      return true;
    }

  switch (action)
    {
      case ListViews::CHANGE:

        if (cn == mObjectCN)
          {
            load();
          }

        break;

      case ListViews::DELETE:

        if (cn == mObjectCN || objectType == ListViews::ObjectType::MODEL)
          {
            mpObject = NULL;
            mObjectCN.clear();
          }

        break;

      default:
        break;
    }

  if (objectType == ListViews::ObjectType::MODEL &&
      action == ListViews::DELETE)
    {
      mEditMode = false;
    }

  return true;
}

// virtual
bool CQNotes::leaveProtected()
{
  if (mpObject != NULL)
    {
      save();
    }
  else
    {
      mObjectCN.clear();
    }

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  if (mObjectCNToCopy == "")
    {
      load();
    }
  else
    {
      CObjectInterface::ContainerList List;
      List.push_back(mpDataModel);

      // This will check the current data model and the root container for the object;
      mpObject = const_cast< CDataObject * >(CObjectInterface::DataObject(CObjectInterface::GetObjectFromCN(List, mObjectCNToCopy)));
      load();
      mpObject = const_cast< CDataObject * >(CObjectInterface::DataObject(CObjectInterface::GetObjectFromCN(List, mObjectCN)));
      save();
      mObjectCN.clear();
    }

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::slotValidateXML()
{
  QString Input = mpEdit->toPlainText();
  int pos = 0;

  mValidity = mpValidatorXML->validate(Input, pos);

  if (mpValidatorXML->isFreeText())
    {
      mEditMode = true;
      mpBtnToggleEdit->hide();
    }
  else
    {
      mpBtnToggleEdit->show();
    }

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::load()
{
  if (mpObject != NULL)
    {
      QString Notes;

      CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
      CReportDefinition * pReportDefinition = dynamic_cast< CReportDefinition * >(mpObject);

      if (pAnnotation != NULL)
        {
          Notes = FROM_UTF8(pAnnotation->getNotes());
        }
      else if (pReportDefinition != NULL)
        {
          Notes = FROM_UTF8(pReportDefinition->getComment());
        }

      // The notes are UTF8 encoded however the html does not specify an encoding
      // thus Qt uses locale settings.
#if defined(QT_USE_TEXTBROWSER)
      static_cast<QTextBrowser*>(mpWebView)->setHtml(Notes);
#elif !defined(QT5_USE_WEBENGINE)
      static_cast<QWebView*>(mpWebView)->setHtml(Notes);
#else
      static_cast<QWebEngineView*>(mpWebView)->setHtml(Notes);
#endif
      mpEdit->setPlainText(Notes);
      mLoadedText = mpEdit->toPlainText();

      mpValidatorXML->saved();
      slotValidateXML();

      if (!mpValidatorXML->isFreeText() && mEditMode)
        {
          slotToggleMode();
        }

      mValidity = QValidator::Acceptable;
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  if (mpObject == NULL ||
      mValidity != QValidator::Acceptable)
    return;

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = dynamic_cast<CReportDefinition *>(mpObject);

  std::string notes;

  if (pAnnotation != NULL)
    {
      notes = pAnnotation->getNotes();
    }
  else if (pReportDefinition != NULL)
    {
      notes = pReportDefinition->getComment();
    }

  QString currentPlainText = mpEdit->toPlainText();
  std::string plainText = TO_UTF8(mpEdit->toPlainText());

  if (plainText == notes)
    return;

  if (mLoadedText == currentPlainText)
    return;

  if (mpValidatorXML->needsWrap())
    {
      // We wrap the HTML in a body element if it does not contain a top level html or body element.
      plainText = "<body xmlns=\"http://www.w3.org/1999/xhtml\">" + plainText + "</body>";
    }

  CUndoData UndoData(CUndoData::Type::CHANGE, mpObject->toData());
  UndoData.addProperty(CData::Property::NOTES, notes, plainText);
  ListViews::addUndoMetaData(this, UndoData);

  slotNotifyChanges(mpDataModel->applyData(UndoData));
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QString scheme = url.scheme();

  if (scheme == "about" || scheme == "data")
    return;

  if (scheme == "copasi")
    {
      dynamic_cast<CQCopasiApplication*>(qApp)->getMainWindow()->slotHandleCopasiScheme(url);
      return;
    }

  QDesktopServices::openUrl(url);
  return;
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkRawImageReaderViewer.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 "itkRawImageReaderViewer.h"
#include "FL/fl_ask.H"

RawImageReaderViewer
::RawImageReaderViewer()
{
  m_RawImageSource =  FileSourceType::New();
  m_RawImageSink   =  FileSinkType::New();

  m_RawReader      =  RawReaderType::New();
  m_RawWriter      =  RawReaderType::New();

  m_RawImageSource->SetImageIO( m_RawReader );
  m_RawImageSink->SetImageIO(   m_RawWriter );

  // size of BrainWeb images in the ftp repository
  m_NumberOfPixelsInX = 181;
  m_NumberOfPixelsInY = 217;
  m_NumberOfPixelsInZ = 181;

}

RawImageReaderViewer
::~RawImageReaderViewer()
{
}

void
RawImageReaderViewer
::SetDimensionX( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInX = numberOfPixels;
}

void
RawImageReaderViewer
::SetDimensionY( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInY = numberOfPixels;
}

void
RawImageReaderViewer
::SetDimensionZ( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInZ = numberOfPixels;
}

void
RawImageReaderViewer
::Quit(void)
{
  this->HideImage();
}

void
RawImageReaderViewer
::HideImage(void)
{
  m_Viewer.Hide();
}

void
RawImageReaderViewer
::ShowImage(void)
{
  m_Viewer.SetImage( m_RawImageSource->GetOutput() );
  m_Viewer.Show();
}

void
RawImageReaderViewer
::Load( void )
{

  const char * filename = fl_file_chooser("Image Filename","*.raw","");

  if( !filename )
    {
    return;
    }

    this->Load( filename );
}

void
RawImageReaderViewer
::Save( void )
{

  const char * filename = fl_file_chooser("Image Filename","*.raw","");

  if( !filename )
    {
    return;
    }

    this->Save( filename );
}

void
RawImageReaderViewer
::Load( const char * filename )
{

  m_RawImageSource->SetFileName( filename );
  m_RawReader->SetDimensions( 0, m_NumberOfPixelsInX );
  m_RawReader->SetDimensions( 1, m_NumberOfPixelsInY );
  m_RawReader->SetDimensions( 2, m_NumberOfPixelsInZ );

  // Attempt to read
  try
    {
    m_RawImageSource->Update();
    }
  catch( itk::ExceptionObject & e )
    {
    fl_alert( e.GetDescription() );
    }

}

void
RawImageReaderViewer
::Save( const char * filename )
{

  m_RawImageSink->SetFileName( filename );
  m_RawImageSink->SetInput( m_RawImageSource->GetOutput() );

  // Attempt to Write
  m_RawImageSink->Write();

}

<commit_msg>FIX: SetFileDimensionality( 3 ) was missing.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkRawImageReaderViewer.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 "itkRawImageReaderViewer.h"
#include "FL/fl_ask.H"

RawImageReaderViewer
::RawImageReaderViewer()
{
  m_RawImageSource =  FileSourceType::New();
  m_RawImageSink   =  FileSinkType::New();

  m_RawReader      =  RawReaderType::New();
  m_RawWriter      =  RawReaderType::New();

  m_RawImageSource->SetImageIO( m_RawReader );
  m_RawImageSink->SetImageIO(   m_RawWriter );

  // size of BrainWeb images in the ftp repository
  m_NumberOfPixelsInX = 181;
  m_NumberOfPixelsInY = 217;
  m_NumberOfPixelsInZ = 181;

}

RawImageReaderViewer
::~RawImageReaderViewer()
{
}

void
RawImageReaderViewer
::SetDimensionX( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInX = numberOfPixels;
}

void
RawImageReaderViewer
::SetDimensionY( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInY = numberOfPixels;
}

void
RawImageReaderViewer
::SetDimensionZ( unsigned int numberOfPixels )
{
  m_NumberOfPixelsInZ = numberOfPixels;
}

void
RawImageReaderViewer
::Quit(void)
{
  this->HideImage();
}

void
RawImageReaderViewer
::HideImage(void)
{
  m_Viewer.Hide();
}

void
RawImageReaderViewer
::ShowImage(void)
{
  m_Viewer.SetImage( m_RawImageSource->GetOutput() );
  m_Viewer.Show();
}

void
RawImageReaderViewer
::Load( void )
{

  const char * filename = fl_file_chooser("Image Filename","*.raw","");

  if( !filename )
    {
    return;
    }

    this->Load( filename );
}

void
RawImageReaderViewer
::Save( void )
{

  const char * filename = fl_file_chooser("Image Filename","*.raw","");

  if( !filename )
    {
    return;
    }

    this->Save( filename );
}

void
RawImageReaderViewer
::Load( const char * filename )
{

  m_RawImageSource->SetFileName( filename );
  m_RawReader->SetFileDimensionality( 3 );
  m_RawReader->SetDimensions( 0, m_NumberOfPixelsInX );
  m_RawReader->SetDimensions( 1, m_NumberOfPixelsInY );
  m_RawReader->SetDimensions( 2, m_NumberOfPixelsInZ );

  // Attempt to read
  try
    {
    m_RawImageSource->Update();
    }
  catch( itk::ExceptionObject & e )
    {
    fl_alert( e.GetDescription() );
    }

}

void
RawImageReaderViewer
::Save( const char * filename )
{

  m_RawImageSink->SetFileName( filename );
  m_RawImageSink->SetInput( m_RawImageSource->GetOutput() );

  // Attempt to Write
  m_RawImageSink->Write();

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>
#include <sys/stat.h>

#include "licenseplatecandidate.h"
#include "stateidentifier.h"
#include "utility.h"
#include "support/filesystem.h"
#include "ocr.h"

using namespace std;
using namespace cv;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

#ifdef __APPLE__
const int LEFT_ARROW_KEY = 2;
const int RIGHT_ARROW_KEY = 3;
const int SPACE_KEY = 32;
const int ENTER_KEY = 13;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 1;
const int UP_ARROW_KEY= 0;
const int DASHBOARD_COLUMNS = 9;

#else
const int LEFT_ARROW_KEY = 81;
const int RIGHT_ARROW_KEY = 83;
const int SPACE_KEY = 32;
const int ENTER_KEY = 10;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 84;
const int UP_ARROW_KEY= 82;
const int DASHBOARD_COLUMNS = 3;

#endif

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex);
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state);

int main( int argc, const char** argv )
{
  string country;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 4)
  {
    country = argv[1];
    inDir = argv[2];
    outDir = argv[3];
  }
  else
  {
    printf("Use:\n\t%s country indirectory outdirectory\n",argv[0]);
    printf("Ex: \n\t%s eu ./pics/ ./out\n",argv[0]);
    return 0;
  }

  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  cout << "Usage: " << endl;
  cout << "\tn		-- Next plate" << endl;
  cout << "\tp		-- Previous plate" << endl;
  cout << "\tW		-- Select image and save characters according to OCR results, then go to next image" << endl;
  cout << "\ts		-- Save characters" << endl;
  cout << "\t<- and ->	-- Cycle between images" << endl;
  cout << "\tEnt/space	-- Select plate" << endl;
  cout << endl;
  cout << "Within a plate" << endl;
  cout << "\t<- and ->		-- Cycle between characters" << endl;
  cout << "\t[0-9A-Z]		-- Identify a character (saves the image)" << endl;
  cout << "\tESC/Ent/Space	-- Back to plate selection" << endl;

  Config config(country);
  OCR ocr(&config);

  if (DirectoryExists(inDir.c_str()))
  {
    vector<string> files = getFilesInDir(inDir.c_str());

    sort( files.begin(), files.end(), stringCompare );

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        cout << fullpath << endl;
        frame = imread( fullpath.c_str() );
        resize(frame, frame, Size(config.ocrImageWidthPx, config.ocrImageHeightPx));

        imshow ("Original", frame);

	PipelineData pipeline_data(frame, Rect(0, 0, frame.cols, frame.rows), &config);
	cvtColor(frame, frame, CV_BGR2GRAY);
	pipeline_data.crop_gray = Mat(frame, Rect(0, 0, frame.cols, frame.rows));
        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        CharacterRegion regionizer(&pipeline_data);

        if (abs(regionizer.getTopLine().angle) > 4)
        {
          // Rotate image:
          Mat rotated(frame.size(), frame.type());
          Mat rot_mat( 2, 3, CV_32FC1 );
          Point center = Point( frame.cols/2, frame.rows/2 );

          rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 );
          warpAffine( frame, rotated, rot_mat, frame.size() );

          rotated.copyTo(frame);
	  pipeline_data.crop_gray = rotated;
        }

        CharacterSegmenter charSegmenter(&pipeline_data);

        //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);

        ocr.performOCR(&pipeline_data);
        ocr.postProcessor->analyze(statecodestr, 25);
        cout << "OCR results: " << ocr.postProcessor->bestChars << endl;

        vector<bool> selectedBoxes(pipeline_data.thresholds.size());
        for (int z = 0; z < pipeline_data.thresholds.size(); z++)
          selectedBoxes[z] = false;

        int curDashboardSelection = 0;

        vector<char> humanInputs(pipeline_data.charRegions.size());

        for (int z = 0; z < pipeline_data.charRegions.size(); z++)
          humanInputs[z] = ' ';

        showDashboard(pipeline_data.thresholds, selectedBoxes, 0);

        char waitkey = (char) waitKey(50);

        while (waitkey != 'n' && waitkey != 'p')	 // Next image
        {
          if (waitkey == LEFT_ARROW_KEY) // left arrow key
          {
            if (curDashboardSelection > 0)
              curDashboardSelection--;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
          {
            if (curDashboardSelection < pipeline_data.thresholds.size() - 1)
              curDashboardSelection++;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == DOWN_ARROW_KEY)
          {
            if (curDashboardSelection + DASHBOARD_COLUMNS <= pipeline_data.thresholds.size() - 1)
              curDashboardSelection += DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == UP_ARROW_KEY)
          {
            if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
              curDashboardSelection -= DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == ENTER_KEY)
          {
	    if (pipeline_data.charRegions.size() > 0)
	    {
	      vector<char> tempdata = showCharSelection(pipeline_data.thresholds[curDashboardSelection], pipeline_data.charRegions, statecodestr);
	      for (int c = 0; c < pipeline_data.charRegions.size(); c++)
		humanInputs[c] = tempdata[c];
	    }
	    else
	    {
	      cout << "No character regions available in this image" << endl;
	    }
          }
          else if (waitkey == SPACE_KEY)
          {
            selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == 's' || waitkey == 'S' || waitkey == 'W')
          {
            if (waitkey == 'W')
            {
              selectedBoxes[curDashboardSelection] = true;
              showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
              const std::string& ocr_str = ocr.postProcessor->bestChars;
              humanInputs.assign(ocr_str.begin(), ocr_str.end());
            }

            bool somethingSelected = false;
            bool chardataTagged = false;
            for (int c = 0; c < pipeline_data.thresholds.size(); c++)
            {
              if (selectedBoxes[c])
              {
                somethingSelected = true;
                break;
              }
            }
            for (int c = 0; c < pipeline_data.charRegions.size(); c++)
            {
              if (humanInputs[c] != ' ')
              {
                chardataTagged = true;
                break;
              }
            }
            // Save
            if (somethingSelected && chardataTagged)
            {
              for (int c = 0; c < pipeline_data.charRegions.size(); c++)
              {
                if (humanInputs[c] == ' ')
                  continue;

                for (int t = 0; t < pipeline_data.thresholds.size(); t++)
                {
                  if (selectedBoxes[t] == false)
                    continue;

                  stringstream filename;
                  Mat cropped = pipeline_data.thresholds[t](pipeline_data.charRegions[c]);
                  filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
                  imwrite(filename.str(), cropped);
                  cout << "Writing char image: " << filename.str() << endl;
                }
              }
            }
            else if (somethingSelected == false)
              cout << "Did not select any boxes" << endl;
            else if (chardataTagged == false)
              cout << "You have not tagged any characters" << endl;

            if (waitkey == 'W')
            {
              waitkey = 'n';
              continue;
            }
          }

          waitkey = (char) waitKey(50);
        }

        if (waitkey == 'p')
          i = i - 2;
        if (i < -1)
          i = -1;
      }
    }
  }
}

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
{
  vector<Mat> vecCopy;

  if (selectedIndex < 0)
    selectedIndex = 0;
  if (selectedIndex >= images.size())
    selectedIndex = images.size() -1;

  for (int i = 0; i < images.size(); i++)
  {
    Mat imgCopy(images[i].size(), images[i].type());
    images[i].copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
    if (i == selectedIndex)
    {
      rectangle(imgCopy, Point(1,1), Point(imgCopy.size().width - 1, imgCopy.size().height -1), Scalar(0, 255, 0), 1);
    }
    if (selectedImages[i])
    {
      rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1);
    }

    vecCopy.push_back(imgCopy);
  }

  Mat dashboard = drawImageDashboard(vecCopy, vecCopy[0].type(), DASHBOARD_COLUMNS);

  imshow("Selection dashboard", dashboard);
}

vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state)
{
  int curCharIdx = 0;

  vector<char> humanInputs(charRegions.size());
  for (int i = 0; i < charRegions.size(); i++)
    humanInputs[i] = (char) SPACE_KEY;

  char waitkey = (char) waitKey(50);
  while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
  {
    Mat imgCopy(image.size(), image.type());
    image.copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);

    rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);

    imshow("Character selector", imgCopy);

    if (waitkey == LEFT_ARROW_KEY)
      curCharIdx--;
    else if (waitkey == RIGHT_ARROW_KEY )
      curCharIdx++;
    else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
    {
      // Save the character to disk
      humanInputs[curCharIdx] = toupper((char) waitkey);
      curCharIdx++;

      if (curCharIdx >= charRegions.size())
      {
        waitkey = (char) ENTER_KEY;
        break;
      }
    }

    if (curCharIdx < 0)
      curCharIdx = 0;
    if (curCharIdx >= charRegions.size())
      curCharIdx = charRegions.size() -1;

    waitkey = (char) waitKey(50);
  }

  if (waitkey == ENTER_KEY)
  {
    // Save all the inputs
    for (int i = 0; i < charRegions.size(); i++)
    {
      if (humanInputs[i] != (char) SPACE_KEY)
        cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
    }
  }

  destroyWindow("Character selector");

  return humanInputs;
}
<commit_msg>Fixed classify chars with two-line enhancements<commit_after>/*
 * Copyright (c) 2014 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>
#include <stdio.h>
#include <sys/stat.h>

#include "licenseplatecandidate.h"
#include "stateidentifier.h"
#include "utility.h"
#include "support/filesystem.h"
#include "ocr.h"

using namespace std;
using namespace cv;

// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR

#ifdef __APPLE__
const int LEFT_ARROW_KEY = 2;
const int RIGHT_ARROW_KEY = 3;
const int SPACE_KEY = 32;
const int ENTER_KEY = 13;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 1;
const int UP_ARROW_KEY= 0;
const int DASHBOARD_COLUMNS = 9;

#else
const int LEFT_ARROW_KEY = 81;
const int RIGHT_ARROW_KEY = 83;
const int SPACE_KEY = 32;
const int ENTER_KEY = 10;
const int ESCAPE_KEY = 27;

const int DOWN_ARROW_KEY = 84;
const int UP_ARROW_KEY= 82;
const int DASHBOARD_COLUMNS = 3;

#endif

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex);
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state);

int main( int argc, const char** argv )
{
  string country;
  string inDir;
  string outDir;
  Mat frame;

  //Check if user specify image to process
  if(argc == 4)
  {
    country = argv[1];
    inDir = argv[2];
    outDir = argv[3];
  }
  else
  {
    printf("Use:\n\t%s country indirectory outdirectory\n",argv[0]);
    printf("Ex: \n\t%s eu ./pics/ ./out\n",argv[0]);
    return 0;
  }

  if (DirectoryExists(outDir.c_str()) == false)
  {
    printf("Output dir does not exist\n");
    return 0;
  }

  cout << "Usage: " << endl;
  cout << "\tn		-- Next plate" << endl;
  cout << "\tp		-- Previous plate" << endl;
  cout << "\tW		-- Select image and save characters according to OCR results, then go to next image" << endl;
  cout << "\ts		-- Save characters" << endl;
  cout << "\t<- and ->	-- Cycle between images" << endl;
  cout << "\tEnt/space	-- Select plate" << endl;
  cout << endl;
  cout << "Within a plate" << endl;
  cout << "\t<- and ->		-- Cycle between characters" << endl;
  cout << "\t[0-9A-Z]		-- Identify a character (saves the image)" << endl;
  cout << "\tESC/Ent/Space	-- Back to plate selection" << endl;

  Config config(country);
  OCR ocr(&config);

  if (DirectoryExists(inDir.c_str()))
  {
    vector<string> files = getFilesInDir(inDir.c_str());

    sort( files.begin(), files.end(), stringCompare );

    for (int i = 0; i< files.size(); i++)
    {
      if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
      {
        string fullpath = inDir + "/" + files[i];
        cout << fullpath << endl;
        frame = imread( fullpath.c_str() );
        resize(frame, frame, Size(config.ocrImageWidthPx, config.ocrImageHeightPx));

        imshow ("Original", frame);

	PipelineData pipeline_data(frame, Rect(0, 0, frame.cols, frame.rows), &config);
	cvtColor(frame, frame, CV_BGR2GRAY);
	pipeline_data.crop_gray = Mat(frame, Rect(0, 0, frame.cols, frame.rows));
        char statecode[3];
        statecode[0] = files[i][0];
        statecode[1] = files[i][1];
        statecode[2] = '\0';
        string statecodestr(statecode);

        CharacterRegion regionizer(&pipeline_data);

        if (abs(pipeline_data.textLines[0].angle) > 4)
        {
          // Rotate image:
          Mat rotated(frame.size(), frame.type());
          Mat rot_mat( 2, 3, CV_32FC1 );
          Point center = Point( frame.cols/2, frame.rows/2 );

          rot_mat = getRotationMatrix2D( center, pipeline_data.textLines[0].angle, 1.0 );
          warpAffine( frame, rotated, rot_mat, frame.size() );

          rotated.copyTo(frame);
	  pipeline_data.crop_gray = rotated;
        }

        CharacterSegmenter charSegmenter(&pipeline_data);

        //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);

        ocr.performOCR(&pipeline_data);
        ocr.postProcessor->analyze(statecodestr, 25);
        cout << "OCR results: " << ocr.postProcessor->bestChars << endl;

        vector<bool> selectedBoxes(pipeline_data.thresholds.size());
        for (int z = 0; z < pipeline_data.thresholds.size(); z++)
          selectedBoxes[z] = false;

        int curDashboardSelection = 0;

        vector<char> humanInputs(pipeline_data.charRegions.size());

        for (int z = 0; z < pipeline_data.charRegions.size(); z++)
          humanInputs[z] = ' ';

        showDashboard(pipeline_data.thresholds, selectedBoxes, 0);

        char waitkey = (char) waitKey(50);

        while (waitkey != 'n' && waitkey != 'p')	 // Next image
        {
          if (waitkey == LEFT_ARROW_KEY) // left arrow key
          {
            if (curDashboardSelection > 0)
              curDashboardSelection--;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
          {
            if (curDashboardSelection < pipeline_data.thresholds.size() - 1)
              curDashboardSelection++;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == DOWN_ARROW_KEY)
          {
            if (curDashboardSelection + DASHBOARD_COLUMNS <= pipeline_data.thresholds.size() - 1)
              curDashboardSelection += DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == UP_ARROW_KEY)
          {
            if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
              curDashboardSelection -= DASHBOARD_COLUMNS;
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == ENTER_KEY)
          {
	    if (pipeline_data.charRegions.size() > 0)
	    {
	      vector<char> tempdata = showCharSelection(pipeline_data.thresholds[curDashboardSelection], pipeline_data.charRegions, statecodestr);
	      for (int c = 0; c < pipeline_data.charRegions.size(); c++)
		humanInputs[c] = tempdata[c];
	    }
	    else
	    {
	      cout << "No character regions available in this image" << endl;
	    }
          }
          else if (waitkey == SPACE_KEY)
          {
            selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
            showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
          }
          else if (waitkey == 's' || waitkey == 'S' || waitkey == 'W')
          {
            if (waitkey == 'W')
            {
              selectedBoxes[curDashboardSelection] = true;
              showDashboard(pipeline_data.thresholds, selectedBoxes, curDashboardSelection);
              const std::string& ocr_str = ocr.postProcessor->bestChars;
              humanInputs.assign(ocr_str.begin(), ocr_str.end());
            }

            bool somethingSelected = false;
            bool chardataTagged = false;
            for (int c = 0; c < pipeline_data.thresholds.size(); c++)
            {
              if (selectedBoxes[c])
              {
                somethingSelected = true;
                break;
              }
            }
            for (int c = 0; c < pipeline_data.charRegions.size(); c++)
            {
              if (humanInputs[c] != ' ')
              {
                chardataTagged = true;
                break;
              }
            }
            // Save
            if (somethingSelected && chardataTagged)
            {
              for (int c = 0; c < pipeline_data.charRegions.size(); c++)
              {
                if (humanInputs[c] == ' ')
                  continue;

                for (int t = 0; t < pipeline_data.thresholds.size(); t++)
                {
                  if (selectedBoxes[t] == false)
                    continue;

                  stringstream filename;
                  Mat cropped = pipeline_data.thresholds[t](pipeline_data.charRegions[c]);
                  filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
                  imwrite(filename.str(), cropped);
                  cout << "Writing char image: " << filename.str() << endl;
                }
              }
            }
            else if (somethingSelected == false)
              cout << "Did not select any boxes" << endl;
            else if (chardataTagged == false)
              cout << "You have not tagged any characters" << endl;

            if (waitkey == 'W')
            {
              waitkey = 'n';
              continue;
            }
          }

          waitkey = (char) waitKey(50);
        }

        if (waitkey == 'p')
          i = i - 2;
        if (i < -1)
          i = -1;
      }
    }
  }
}

void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
{
  vector<Mat> vecCopy;

  if (selectedIndex < 0)
    selectedIndex = 0;
  if (selectedIndex >= images.size())
    selectedIndex = images.size() -1;

  for (int i = 0; i < images.size(); i++)
  {
    Mat imgCopy(images[i].size(), images[i].type());
    images[i].copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
    if (i == selectedIndex)
    {
      rectangle(imgCopy, Point(1,1), Point(imgCopy.size().width - 1, imgCopy.size().height -1), Scalar(0, 255, 0), 1);
    }
    if (selectedImages[i])
    {
      rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1);
    }

    vecCopy.push_back(imgCopy);
  }

  Mat dashboard = drawImageDashboard(vecCopy, vecCopy[0].type(), DASHBOARD_COLUMNS);

  imshow("Selection dashboard", dashboard);
}

vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state)
{
  int curCharIdx = 0;

  vector<char> humanInputs(charRegions.size());
  for (int i = 0; i < charRegions.size(); i++)
    humanInputs[i] = (char) SPACE_KEY;

  char waitkey = (char) waitKey(50);
  while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
  {
    Mat imgCopy(image.size(), image.type());
    image.copyTo(imgCopy);
    cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);

    rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);

    imshow("Character selector", imgCopy);

    if (waitkey == LEFT_ARROW_KEY)
      curCharIdx--;
    else if (waitkey == RIGHT_ARROW_KEY )
      curCharIdx++;
    else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
    {
      // Save the character to disk
      humanInputs[curCharIdx] = toupper((char) waitkey);
      curCharIdx++;

      if (curCharIdx >= charRegions.size())
      {
        waitkey = (char) ENTER_KEY;
        break;
      }
    }

    if (curCharIdx < 0)
      curCharIdx = 0;
    if (curCharIdx >= charRegions.size())
      curCharIdx = charRegions.size() -1;

    waitkey = (char) waitKey(50);
  }

  if (waitkey == ENTER_KEY)
  {
    // Save all the inputs
    for (int i = 0; i < charRegions.size(); i++)
    {
      if (humanInputs[i] != (char) SPACE_KEY)
        cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
    }
  }

  destroyWindow("Character selector");

  return humanInputs;
}
<|endoftext|>


<commit_before>/**
 * @file arma_config_check.hpp
 * @author Ryan Curtin
 *
 * Using the contents of arma_config.hpp, try to catch the condition where the
 * user has included mlpack with ARMA_64BIT_WORD enabled but mlpack was compiled
 * without ARMA_64BIT_WORD enabled.  This should help prevent a long, drawn-out
 * debugging process where nobody can figure out why the stack is getting
 * mangled.
 */
#ifndef __MLPACK_CORE_UTIL_ARMA_CHECK_HPP
#define __MLPACK_CORE_UTIL_ARMA_CHECK_HPP

#endif
<commit_msg>arma_config.hpp is auto-generated; don't keep it in the repo.<commit_after><|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtMultimedia module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtMultimedia/qaudio.h>
#include <QtMultimedia/qaudiodeviceinfo.h>
#include <QtMultimedia/qaudioengine.h>
#include <QtMultimedia/qaudioinput.h>

#include "qaudiodevicefactory_p.h"

QT_BEGIN_NAMESPACE

/*!
    \class QAudioInput
    \brief The QAudioInput class provides an interface for receiving audio data from an audio input device.

    \inmodule QtMultimedia
    \ingroup  multimedia
    \since 4.6

    You can construct an audio input with the system's
    \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input
    device}. It is also possible to create QAudioInput with a
    specific QAudioDeviceInfo. When you create the audio input, you
    should also send in the QAudioFormat to be used for the recording
    (see the QAudioFormat class description for details).

    To record to a file:

    QAudioInput lets you record audio with an audio input device. The
    default constructor of this class will use the systems default
    audio device, but you can also specify a QAudioDeviceInfo for a
    specific device. You also need to pass in the QAudioFormat in
    which you wish to record.

    Starting up the QAudioInput is simply a matter of calling start()
    with a QIODevice opened for writing. For instance, to record to a
    file, you can:

    \code
      QFile outputFile;   // class member.
      QAudioInput* audio; // class member.
    \endcode

    \code
    {
      outputFile.setFileName("/tmp/test.raw");
      outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate );

      QAudioFormat format;
      // set up the format you want, eg.
      format.setFrequency(8000);
      format.setChannels(1);
      format.setSampleSize(8);
      format.setCodec("audio/pcm");
      format.setByteOrder(QAudioFormat::LittleEndian);
      format.setSampleType(QAudioFormat::UnSignedInt);

      if (QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice());
      if (!info.isFormatSupported(format)) {
          qWarning()<<"default format not supported try to use nearest";
          format = info.nearestFormat(format);
      }

      audio = new QAudioInput(format, this);
      QTimer::singleShot(3000, this, SLOT(stopRecording()));
      audio->start(&outputFile);
      // Records audio for 3000ms
    }
    \endcode

    This will start recording if the format specified is supported by
    the input device (you can check this with
    QAudioDeviceInfo::isFormatSupported(). In case there are any
    snags, use the error() function to check what went wrong. We stop
    recording in the \c stopRecording() slot.

    \code
    void stopRecording()
    {
      audio->stop();
      outputFile->close();
      delete audio;
    }
    \endcode

    At any point in time, QAudioInput will be in one of four states:
    active, suspended, stopped, or idle. These states are specified by
    the QAudio::State enum. You can request a state change directly through
    suspend(), resume(), stop(), reset(), and start(). The current
    state is reported by state(). QAudioOutput will also signal you
    when the state changes (stateChanged()).

    QAudioInput provides several ways of measuring the time that has
    passed since the start() of the recording. The \c processedUSecs()
    function returns the length of the stream in microseconds written,
    i.e., it leaves out the times the audio input was suspended or idle.
    The elapsedUSecs() function returns the time elapsed since start() was called regardless of
    which states the QAudioInput has been in.

    If an error should occur, you can fetch its reason with error().
    The possible error reasons are described by the QAudio::Error
    enum. The QAudioInput will enter the \l{QAudio::}{StoppedState} when
    an error is encountered.  Connect to the stateChanged() signal to
    handle the error:

    \snippet doc/src/snippets/audio/main.cpp 0

    \sa QAudioOutput, QAudioDeviceInfo
*/

/*!
    Construct a new audio input and attach it to \a parent.
    The default audio input device is used with the output
    \a format parameters.
*/

QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
    QObject(parent)
{
    d = QAudioDeviceFactory::createDefaultInputDevice(format);
    connect(d, SIGNAL(notify()), SIGNAL(notify()));
    connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
}

/*!
    Construct a new audio input and attach it to \a parent.
    The device referenced by \a audioDevice is used with the input
    \a format parameters.
*/

QAudioInput::QAudioInput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent):
    QObject(parent)
{
    d = QAudioDeviceFactory::createInputDevice(audioDevice, format);
    connect(d, SIGNAL(notify()), SIGNAL(notify()));
    connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
}

/*!
    Destroy this audio input.
*/

QAudioInput::~QAudioInput()
{
    delete d;
}

/*!
     Uses the \a device as the QIODevice to transfer data.
     Passing a QIODevice allows the data to be transfered without any extra code.
     All that is required is to open the QIODevice.

     If able to successfully get audio data from the systems audio device the
     state() is set to either QAudio::ActiveState or QAudio::IdleState,
     error() is set to QAudio::NoError and the stateChanged() signal is emitted.

     If a problem occurs during this process the error() is set to QAudio::OpenError,
     state() is set to QAudio::StoppedState and stateChanged() signal is emitted.

     \sa QIODevice
*/

void QAudioInput::start(QIODevice* device)
{
    d->start(device);
}

/*!
    Returns a pointer to the QIODevice being used to handle the data
    transfer. This QIODevice can be used to read() audio data
    directly.

    If able to access the systems audio device the state() is set to
    QAudio::IdleState, error() is set to QAudio::NoError
    and the stateChanged() signal is emitted.

    If a problem occurs during this process the error() is set to QAudio::OpenError,
    state() is set to QAudio::StoppedState and stateChanged() signal is emitted.

    \sa QIODevice
*/

QIODevice* QAudioInput::start()
{
    return d->start(0);
}

/*!
    Returns the QAudioFormat being used.
*/

QAudioFormat QAudioInput::format() const
{
    return d->format();
}

/*!
    Stops the audio input, detaching from the system resource.

    Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
    emit stateChanged() signal.
*/

void QAudioInput::stop()
{
    d->stop();
}

/*!
    Drops all audio data in the buffers, resets buffers to zero.
*/

void QAudioInput::reset()
{
    d->reset();
}

/*!
    Stops processing audio data, preserving buffered audio data.

    Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
    emit stateChanged() signal.
*/

void QAudioInput::suspend()
{
    d->suspend();
}

/*!
    Resumes processing audio data after a suspend().

    Sets error() to QAudio::NoError.
    Sets state() to QAudio::ActiveState if you previously called start(QIODevice*).
    Sets state() to QAudio::IdleState if you previously called start().
    emits stateChanged() signal.
*/

void QAudioInput::resume()
{
     d->resume();
}

/*!
    Sets the audio buffer size to \a value milliseconds.

    Note: This function can be called anytime before start(), calls to this
    are ignored after start(). It should not be assumed that the buffer size
    set is the actual buffer size used, calling bufferSize() anytime after start()
    will return the actual buffer size being used.

*/

void QAudioInput::setBufferSize(int value)
{
    d->setBufferSize(value);
}

/*!
    Returns the audio buffer size in milliseconds.

    If called before start(), returns platform default value.
    If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
    If called after start(), returns the actual buffer size being used. This may not be what was set previously
    by setBufferSize().

*/

int QAudioInput::bufferSize() const
{
    return d->bufferSize();
}

/*!
    Returns the amount of audio data available to read in bytes.

    NOTE: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
    state, otherwise returns zero.
*/

int QAudioInput::bytesReady() const
{
    /*
    -If not ActiveState|IdleState, return 0
    -return amount of audio data available to read
    */
    return d->bytesReady();
}

/*!
    Returns the period size in bytes.

    Note: This is the recommended read size in bytes.
*/

int QAudioInput::periodSize() const
{
    return d->periodSize();
}

/*!
    Sets the interval for notify() signal to be emitted.
    This is based on the \a ms of audio data processed
    not on actual real-time.
    The minimum resolution of the timer is platform specific and values
    should be checked with notifyInterval() to confirm actual value
    being used.
*/

void QAudioInput::setNotifyInterval(int ms)
{
    d->setNotifyInterval(ms);
}

/*!
    Returns the notify interval in milliseconds.
*/

int QAudioInput::notifyInterval() const
{
    return d->notifyInterval();
}

/*!
    Returns the amount of audio data processed since start()
    was called in microseconds.
*/

qint64 QAudioInput::processedUSecs() const
{
    return d->processedUSecs();
}

/*!
    Returns the microseconds since start() was called, including time in Idle and
    Suspend states.
*/

qint64 QAudioInput::elapsedUSecs() const
{
    return d->elapsedUSecs();
}

/*!
    Returns the error state.
*/

QAudio::Error QAudioInput::error() const
{
    return d->error();
}

/*!
    Returns the state of audio processing.
*/

QAudio::State QAudioInput::state() const
{
    return d->state();
}

/*!
    \fn QAudioInput::stateChanged(QAudio::State state)
    This signal is emitted when the device \a state has changed.
*/

/*!
    \fn QAudioInput::notify()
    This signal is emitted when x ms of audio data has been processed
    the interval set by setNotifyInterval(x).
*/

QT_END_NAMESPACE

<commit_msg>Documentation fix.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtMultimedia module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtMultimedia/qaudio.h>
#include <QtMultimedia/qaudiodeviceinfo.h>
#include <QtMultimedia/qaudioengine.h>
#include <QtMultimedia/qaudioinput.h>

#include "qaudiodevicefactory_p.h"

QT_BEGIN_NAMESPACE

/*!
    \class QAudioInput
    \brief The QAudioInput class provides an interface for receiving audio data from an audio input device.

    \inmodule QtMultimedia
    \ingroup  multimedia
    \since 4.6

    You can construct an audio input with the system's
    \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input
    device}. It is also possible to create QAudioInput with a
    specific QAudioDeviceInfo. When you create the audio input, you
    should also send in the QAudioFormat to be used for the recording
    (see the QAudioFormat class description for details).

    To record to a file:

    QAudioInput lets you record audio with an audio input device. The
    default constructor of this class will use the systems default
    audio device, but you can also specify a QAudioDeviceInfo for a
    specific device. You also need to pass in the QAudioFormat in
    which you wish to record.

    Starting up the QAudioInput is simply a matter of calling start()
    with a QIODevice opened for writing. For instance, to record to a
    file, you can:

    \code
      QFile outputFile;   // class member.
      QAudioInput* audio; // class member.
    \endcode

    \code
    {
      outputFile.setFileName("/tmp/test.raw");
      outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate );

      QAudioFormat format;
      // set up the format you want, eg.
      format.setFrequency(8000);
      format.setChannels(1);
      format.setSampleSize(8);
      format.setCodec("audio/pcm");
      format.setByteOrder(QAudioFormat::LittleEndian);
      format.setSampleType(QAudioFormat::UnSignedInt);

      QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
      if (!info.isFormatSupported(format)) {
          qWarning()<<"default format not supported try to use nearest";
          format = info.nearestFormat(format);
      }

      audio = new QAudioInput(format, this);
      QTimer::singleShot(3000, this, SLOT(stopRecording()));
      audio->start(&outputFile);
      // Records audio for 3000ms
    }
    \endcode

    This will start recording if the format specified is supported by
    the input device (you can check this with
    QAudioDeviceInfo::isFormatSupported(). In case there are any
    snags, use the error() function to check what went wrong. We stop
    recording in the \c stopRecording() slot.

    \code
    void stopRecording()
    {
      audio->stop();
      outputFile->close();
      delete audio;
    }
    \endcode

    At any point in time, QAudioInput will be in one of four states:
    active, suspended, stopped, or idle. These states are specified by
    the QAudio::State enum. You can request a state change directly through
    suspend(), resume(), stop(), reset(), and start(). The current
    state is reported by state(). QAudioOutput will also signal you
    when the state changes (stateChanged()).

    QAudioInput provides several ways of measuring the time that has
    passed since the start() of the recording. The \c processedUSecs()
    function returns the length of the stream in microseconds written,
    i.e., it leaves out the times the audio input was suspended or idle.
    The elapsedUSecs() function returns the time elapsed since start() was called regardless of
    which states the QAudioInput has been in.

    If an error should occur, you can fetch its reason with error().
    The possible error reasons are described by the QAudio::Error
    enum. The QAudioInput will enter the \l{QAudio::}{StoppedState} when
    an error is encountered.  Connect to the stateChanged() signal to
    handle the error:

    \snippet doc/src/snippets/audio/main.cpp 0

    \sa QAudioOutput, QAudioDeviceInfo
*/

/*!
    Construct a new audio input and attach it to \a parent.
    The default audio input device is used with the output
    \a format parameters.
*/

QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
    QObject(parent)
{
    d = QAudioDeviceFactory::createDefaultInputDevice(format);
    connect(d, SIGNAL(notify()), SIGNAL(notify()));
    connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
}

/*!
    Construct a new audio input and attach it to \a parent.
    The device referenced by \a audioDevice is used with the input
    \a format parameters.
*/

QAudioInput::QAudioInput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent):
    QObject(parent)
{
    d = QAudioDeviceFactory::createInputDevice(audioDevice, format);
    connect(d, SIGNAL(notify()), SIGNAL(notify()));
    connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
}

/*!
    Destroy this audio input.
*/

QAudioInput::~QAudioInput()
{
    delete d;
}

/*!
     Uses the \a device as the QIODevice to transfer data.
     Passing a QIODevice allows the data to be transfered without any extra code.
     All that is required is to open the QIODevice.

     If able to successfully get audio data from the systems audio device the
     state() is set to either QAudio::ActiveState or QAudio::IdleState,
     error() is set to QAudio::NoError and the stateChanged() signal is emitted.

     If a problem occurs during this process the error() is set to QAudio::OpenError,
     state() is set to QAudio::StoppedState and stateChanged() signal is emitted.

     \sa QIODevice
*/

void QAudioInput::start(QIODevice* device)
{
    d->start(device);
}

/*!
    Returns a pointer to the QIODevice being used to handle the data
    transfer. This QIODevice can be used to read() audio data
    directly.

    If able to access the systems audio device the state() is set to
    QAudio::IdleState, error() is set to QAudio::NoError
    and the stateChanged() signal is emitted.

    If a problem occurs during this process the error() is set to QAudio::OpenError,
    state() is set to QAudio::StoppedState and stateChanged() signal is emitted.

    \sa QIODevice
*/

QIODevice* QAudioInput::start()
{
    return d->start(0);
}

/*!
    Returns the QAudioFormat being used.
*/

QAudioFormat QAudioInput::format() const
{
    return d->format();
}

/*!
    Stops the audio input, detaching from the system resource.

    Sets error() to QAudio::NoError, state() to QAudio::StoppedState and
    emit stateChanged() signal.
*/

void QAudioInput::stop()
{
    d->stop();
}

/*!
    Drops all audio data in the buffers, resets buffers to zero.
*/

void QAudioInput::reset()
{
    d->reset();
}

/*!
    Stops processing audio data, preserving buffered audio data.

    Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and
    emit stateChanged() signal.
*/

void QAudioInput::suspend()
{
    d->suspend();
}

/*!
    Resumes processing audio data after a suspend().

    Sets error() to QAudio::NoError.
    Sets state() to QAudio::ActiveState if you previously called start(QIODevice*).
    Sets state() to QAudio::IdleState if you previously called start().
    emits stateChanged() signal.
*/

void QAudioInput::resume()
{
     d->resume();
}

/*!
    Sets the audio buffer size to \a value milliseconds.

    Note: This function can be called anytime before start(), calls to this
    are ignored after start(). It should not be assumed that the buffer size
    set is the actual buffer size used, calling bufferSize() anytime after start()
    will return the actual buffer size being used.

*/

void QAudioInput::setBufferSize(int value)
{
    d->setBufferSize(value);
}

/*!
    Returns the audio buffer size in milliseconds.

    If called before start(), returns platform default value.
    If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
    If called after start(), returns the actual buffer size being used. This may not be what was set previously
    by setBufferSize().

*/

int QAudioInput::bufferSize() const
{
    return d->bufferSize();
}

/*!
    Returns the amount of audio data available to read in bytes.

    NOTE: returned value is only valid while in QAudio::ActiveState or QAudio::IdleState
    state, otherwise returns zero.
*/

int QAudioInput::bytesReady() const
{
    /*
    -If not ActiveState|IdleState, return 0
    -return amount of audio data available to read
    */
    return d->bytesReady();
}

/*!
    Returns the period size in bytes.

    Note: This is the recommended read size in bytes.
*/

int QAudioInput::periodSize() const
{
    return d->periodSize();
}

/*!
    Sets the interval for notify() signal to be emitted.
    This is based on the \a ms of audio data processed
    not on actual real-time.
    The minimum resolution of the timer is platform specific and values
    should be checked with notifyInterval() to confirm actual value
    being used.
*/

void QAudioInput::setNotifyInterval(int ms)
{
    d->setNotifyInterval(ms);
}

/*!
    Returns the notify interval in milliseconds.
*/

int QAudioInput::notifyInterval() const
{
    return d->notifyInterval();
}

/*!
    Returns the amount of audio data processed since start()
    was called in microseconds.
*/

qint64 QAudioInput::processedUSecs() const
{
    return d->processedUSecs();
}

/*!
    Returns the microseconds since start() was called, including time in Idle and
    Suspend states.
*/

qint64 QAudioInput::elapsedUSecs() const
{
    return d->elapsedUSecs();
}

/*!
    Returns the error state.
*/

QAudio::Error QAudioInput::error() const
{
    return d->error();
}

/*!
    Returns the state of audio processing.
*/

QAudio::State QAudioInput::state() const
{
    return d->state();
}

/*!
    \fn QAudioInput::stateChanged(QAudio::State state)
    This signal is emitted when the device \a state has changed.
*/

/*!
    \fn QAudioInput::notify()
    This signal is emitted when x ms of audio data has been processed
    the interval set by setNotifyInterval(x).
*/

QT_END_NAMESPACE

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/config.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/box2d.hpp>

// stl
#include <cmath>

// agg
#include "agg_image_filters.h"
#include "agg_trans_bilinear.h"
#include "agg_span_interpolator_linear.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_span_allocator.h"
#include "agg_image_accessors.h"
#include "agg_renderer_scanline.h"

namespace mapnik {

static inline void resample_raster(raster &target, raster const& source,
                                   proj_transform const& prj_trans,
                                   double offset_x, double offset_y,
                                   double filter_factor,
                                   std::string scaling_method_name)
{
    if (prj_trans.equal()) {

        if (scaling_method_name == "bilinear8"){
            scale_image_bilinear8<image_data_32>(target.data_,source.data_,
                                                 offset_x, offset_y);
        } else {
            double scale_factor = target.data_.width() / source.data_.width();
            scaling_method_e scaling_method = get_scaling_method_by_name(scaling_method_name);
            scale_image_agg<image_data_32>(target.data_,source.data_, (scaling_method_e)scaling_method, scale_factor, offset_x, offset_y, filter_factor);
        }
    } else {
        CoordTransform ts(source.data_.width(), source.data_.height(),
                          source.ext_);
        CoordTransform tt(target.data_.width(), target.data_.height(),
                          target.ext_, offset_x, offset_y);
        unsigned i, j, mesh_size=16;
        unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1);
        unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1);

        ImageData<double> xs(mesh_nx, mesh_ny);
        ImageData<double> ys(mesh_nx, mesh_ny);

        // Precalculate reprojected mesh
        for(j=0; j<mesh_ny; j++) {
            for (i=0; i<mesh_nx; i++) {
                xs(i,j) = i*mesh_size;
                ys(i,j) = j*mesh_size;
                ts.backward(&xs(i,j), &ys(i,j));
            }
        }
        prj_trans.backward(xs.getData(), ys.getData(), NULL, mesh_nx*mesh_ny);

        // warp image using projected mesh points using bilinear interpolation
        // inside mesh cell
        typedef agg::pixfmt_rgba32 pixfmt;
        typedef pixfmt::color_type color_type;
        typedef agg::renderer_base<pixfmt> renderer_base;
        typedef agg::pixfmt_rgba32_pre pixfmt_pre;
        typedef agg::renderer_base<pixfmt_pre> renderer_base_pre;

        agg::rasterizer_scanline_aa<> rasterizer;
        agg::scanline_u8  scanline;
        agg::rendering_buffer buf((unsigned char*)target.data_.getData(),
                                  target.data_.width(),
                                  target.data_.height(),
                                  target.data_.width()*4);
        pixfmt_pre pixf_pre(buf);
        renderer_base_pre rb_pre(pixf_pre);
        rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height());

        for(j=0; j<mesh_ny-1; j++) {
            for (i=0; i<mesh_nx-1; i++) {
                box2d<double> win(xs(i,j), ys(i,j), xs(i+1,j+1), ys(i+1,j+1));
                win = tt.forward(win);
                if (!(win.maxx() < target.data_.width() &&
                      win.maxy() < target.data_.height())
                ) continue;

                double polygon[8] = {win.minx(), win.miny(),
                                     win.maxx(), win.miny(),
                                     win.maxx(), win.maxy(),
                                     win.minx(), win.maxy()};
                rasterizer.reset();
                rasterizer.move_to_d(polygon[0]-1, polygon[1]-1);
                rasterizer.line_to_d(polygon[2]+1, polygon[3]-1);
                rasterizer.line_to_d(polygon[4]+1, polygon[5]+1);
                rasterizer.line_to_d(polygon[6]-1, polygon[7]+1);

                agg::span_allocator<color_type> sa;
                agg::image_filter_bilinear filter_kernel;
                agg::image_filter_lut filter(filter_kernel, false);

                agg::rendering_buffer buf_tile(
                    (unsigned char*)source.data_.getData(),
                    source.data_.width(),
                    source.data_.height(),
                    source.data_.width() * 4);

                pixfmt pixf_tile(buf_tile);

                typedef agg::image_accessor_clone<pixfmt> img_accessor_type;
                img_accessor_type ia(pixf_tile);

                unsigned x0 = i * mesh_size;
                unsigned y0 = j * mesh_size;
                unsigned x1 = (i+1) * mesh_size;
                unsigned y1 = (j+1) * mesh_size;

                if (!(x1 < source.data_.width() &&
                      y1 < source.data_.height())) continue;

                agg::trans_bilinear tr(polygon, x0, y0, x1, y1);
                if (tr.is_valid())
                {
                    typedef agg::span_interpolator_linear<agg::trans_bilinear>
                        interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
                        interpolator_type> span_gen_type;

                    span_gen_type sg(ia, interpolator, filter);
                    agg::render_scanlines_aa(rasterizer, scanline, rb_pre,
                                             sa, sg);
                }

            }
        }
    }
}

template <typename T>
void agg_renderer<T>::process(raster_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    raster_ptr const& source=feature.get_raster();
    if (source)
    {
        // If there's a colorizer defined, use it to color the raster in-place
        raster_colorizer_ptr colorizer = sym.get_colorizer();
        if (colorizer)
            colorizer->colorize(source,feature.props());

        box2d<double> target_ext = box2d<double>(source->ext_);
        prj_trans.backward(target_ext, 20);

        box2d<double> ext=t_.forward(target_ext);
        int start_x = (int)ext.minx();
        int start_y = (int)ext.miny();
        int end_x = (int)ceil(ext.maxx());
        int end_y = (int)ceil(ext.maxy());
        int raster_width = end_x - start_x;
        int raster_height = end_y - start_y;
        double err_offs_x = ext.minx() - start_x;
        double err_offs_y = ext.miny() - start_y;

        if (raster_width > 0 && raster_height > 0)
        {
            image_data_32 target_data(raster_width,raster_height);
            raster target(target_ext, target_data);

            resample_raster(target, *source, prj_trans, err_offs_x, err_offs_y,
                            sym.calculate_filter_factor(),
                            sym.get_scaling());

            if (sym.get_mode() == "normal"){
                if (sym.get_opacity() == 1.0) {
                    pixmap_.set_rectangle_alpha(start_x,start_y,target.data_);
                } else {
                    pixmap_.set_rectangle_alpha2(target.data_,start_x,start_y, sym.get_opacity());
                }
            } else if (sym.get_mode() == "grain_merge"){
                pixmap_.template merge_rectangle<MergeGrain> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "grain_merge2"){
                pixmap_.template merge_rectangle<MergeGrain2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply"){
                pixmap_.template merge_rectangle<Multiply> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply2"){
                pixmap_.template merge_rectangle<Multiply2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide"){
                pixmap_.template merge_rectangle<Divide> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide2"){
                pixmap_.template merge_rectangle<Divide2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "screen"){
                pixmap_.template merge_rectangle<Screen> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "hard_light"){
                pixmap_.template merge_rectangle<HardLight> (target.data_,start_x,start_y, sym.get_opacity());
            } else {
                if (sym.get_opacity() == 1.0){
                    pixmap_.set_rectangle(start_x,start_y,target.data_);
                } else {
                    pixmap_.set_rectangle_alpha2(target.data_,start_x,start_y, sym.get_opacity());
                }
            }
            // TODO: other modes? (add,diff,sub,...)
        }
    }
}

template void agg_renderer<image_32>::process(raster_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);

}
<commit_msg>removed redundant bounds checks (I asuume AGG already makes sure not to write outside the buffer). Moved object creation from inside loop<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/config.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/raster.hpp>
#include <mapnik/box2d.hpp>

// stl
#include <cmath>

// agg
#include "agg_image_filters.h"
#include "agg_trans_bilinear.h"
#include "agg_span_interpolator_linear.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_basics.h"
#include "agg_scanline_u.h"
#include "agg_renderer_scanline.h"
#include "agg_span_allocator.h"
#include "agg_image_accessors.h"
#include "agg_renderer_scanline.h"

namespace mapnik {

static inline void resample_raster(raster &target, raster const& source,
                                   proj_transform const& prj_trans,
                                   double offset_x, double offset_y,
                                   double filter_factor,
                                   std::string scaling_method_name)
{
    if (prj_trans.equal()) {

        if (scaling_method_name == "bilinear8"){
            scale_image_bilinear8<image_data_32>(target.data_,source.data_,
                                                 offset_x, offset_y);
        } else {
            double scale_factor = target.data_.width() / source.data_.width();
            scaling_method_e scaling_method = get_scaling_method_by_name(scaling_method_name);
            scale_image_agg<image_data_32>(target.data_,source.data_, (scaling_method_e)scaling_method, scale_factor, offset_x, offset_y, filter_factor);
        }
    } else {
        CoordTransform ts(source.data_.width(), source.data_.height(),
                          source.ext_);
        CoordTransform tt(target.data_.width(), target.data_.height(),
                          target.ext_, offset_x, offset_y);
        unsigned i, j, mesh_size=16;
        unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1);
        unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1);

        ImageData<double> xs(mesh_nx, mesh_ny);
        ImageData<double> ys(mesh_nx, mesh_ny);

        // Precalculate reprojected mesh
        for(j=0; j<mesh_ny; j++) {
            for (i=0; i<mesh_nx; i++) {
                xs(i,j) = i*mesh_size;
                ys(i,j) = j*mesh_size;
                ts.backward(&xs(i,j), &ys(i,j));
            }
        }
        prj_trans.backward(xs.getData(), ys.getData(), NULL, mesh_nx*mesh_ny);

        // warp image using projected mesh points using bilinear interpolation
        // inside mesh cell
        typedef agg::pixfmt_rgba32 pixfmt;
        typedef pixfmt::color_type color_type;
        typedef agg::renderer_base<pixfmt> renderer_base;
        typedef agg::pixfmt_rgba32_pre pixfmt_pre;
        typedef agg::renderer_base<pixfmt_pre> renderer_base_pre;

        agg::rasterizer_scanline_aa<> rasterizer;
        agg::scanline_u8  scanline;
        agg::rendering_buffer buf((unsigned char*)target.data_.getData(),
                                  target.data_.width(),
                                  target.data_.height(),
                                  target.data_.width()*4);
        pixfmt_pre pixf_pre(buf);
        renderer_base_pre rb_pre(pixf_pre);
        rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height());
        agg::rendering_buffer buf_tile(
            (unsigned char*)source.data_.getData(),
            source.data_.width(),
            source.data_.height(),
            source.data_.width() * 4);

        pixfmt pixf_tile(buf_tile);

        typedef agg::image_accessor_clone<pixfmt> img_accessor_type;
        img_accessor_type ia(pixf_tile);

        agg::span_allocator<color_type> sa;
        agg::image_filter_bilinear filter_kernel;
        agg::image_filter_lut filter(filter_kernel, false);

        for(j=0; j<mesh_ny-1; j++) {
            for (i=0; i<mesh_nx-1; i++) {
                box2d<double> win(xs(i,j), ys(i,j), xs(i+1,j+1), ys(i+1,j+1));
                win = tt.forward(win);

                double polygon[8] = {win.minx(), win.miny(),
                                     win.maxx(), win.miny(),
                                     win.maxx(), win.maxy(),
                                     win.minx(), win.maxy()};
                rasterizer.reset();
                rasterizer.move_to_d(polygon[0]-1, polygon[1]-1);
                rasterizer.line_to_d(polygon[2]+1, polygon[3]-1);
                rasterizer.line_to_d(polygon[4]+1, polygon[5]+1);
                rasterizer.line_to_d(polygon[6]-1, polygon[7]+1);

                unsigned x0 = i * mesh_size;
                unsigned y0 = j * mesh_size;
                unsigned x1 = (i+1) * mesh_size;
                unsigned y1 = (j+1) * mesh_size;

                agg::trans_bilinear tr(polygon, x0, y0, x1, y1);
                if (tr.is_valid())
                {
                    typedef agg::span_interpolator_linear<agg::trans_bilinear>
                        interpolator_type;
                    interpolator_type interpolator(tr);

                    typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
                        interpolator_type> span_gen_type;

                    span_gen_type sg(ia, interpolator, filter);
                    agg::render_scanlines_aa(rasterizer, scanline, rb_pre,
                                             sa, sg);
                }

            }
        }
    }
}

template <typename T>
void agg_renderer<T>::process(raster_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    raster_ptr const& source=feature.get_raster();
    if (source)
    {
        // If there's a colorizer defined, use it to color the raster in-place
        raster_colorizer_ptr colorizer = sym.get_colorizer();
        if (colorizer)
            colorizer->colorize(source,feature.props());

        box2d<double> target_ext = box2d<double>(source->ext_);
        prj_trans.backward(target_ext, 20);

        box2d<double> ext=t_.forward(target_ext);
        int start_x = (int)ext.minx();
        int start_y = (int)ext.miny();
        int end_x = (int)ceil(ext.maxx());
        int end_y = (int)ceil(ext.maxy());
        int raster_width = end_x - start_x;
        int raster_height = end_y - start_y;
        double err_offs_x = ext.minx() - start_x;
        double err_offs_y = ext.miny() - start_y;

        if (raster_width > 0 && raster_height > 0)
        {
            image_data_32 target_data(raster_width,raster_height);
            raster target(target_ext, target_data);

            resample_raster(target, *source, prj_trans, err_offs_x, err_offs_y,
                            sym.calculate_filter_factor(),
                            sym.get_scaling());

            if (sym.get_mode() == "normal"){
                if (sym.get_opacity() == 1.0) {
                    pixmap_.set_rectangle_alpha(start_x,start_y,target.data_);
                } else {
                    pixmap_.set_rectangle_alpha2(target.data_,start_x,start_y, sym.get_opacity());
                }
            } else if (sym.get_mode() == "grain_merge"){
                pixmap_.template merge_rectangle<MergeGrain> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "grain_merge2"){
                pixmap_.template merge_rectangle<MergeGrain2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply"){
                pixmap_.template merge_rectangle<Multiply> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "multiply2"){
                pixmap_.template merge_rectangle<Multiply2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide"){
                pixmap_.template merge_rectangle<Divide> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "divide2"){
                pixmap_.template merge_rectangle<Divide2> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "screen"){
                pixmap_.template merge_rectangle<Screen> (target.data_,start_x,start_y, sym.get_opacity());
            } else if (sym.get_mode() == "hard_light"){
                pixmap_.template merge_rectangle<HardLight> (target.data_,start_x,start_y, sym.get_opacity());
            } else {
                if (sym.get_opacity() == 1.0){
                    pixmap_.set_rectangle(start_x,start_y,target.data_);
                } else {
                    pixmap_.set_rectangle_alpha2(target.data_,start_x,start_y, sym.get_opacity());
                }
            }
            // TODO: other modes? (add,diff,sub,...)
        }
    }
}

template void agg_renderer<image_32>::process(raster_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);

}
<|endoftext|>