fw4spl
SPdfWriter.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2016-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "ioQt/SPdfWriter.hpp"
8 
9 #include <fwData/location/Folder.hpp>
10 #include <fwData/location/SingleFile.hpp>
11 
12 #include <fwDataTools/helper/Image.hpp>
13 
14 #include <fwGui/dialog/LocationDialog.hpp>
15 #include <fwGui/dialog/MessageDialog.hpp>
16 #include <fwGui/GuiRegistry.hpp>
17 
18 #include <fwGuiQt/container/QtContainer.hpp>
19 
20 #include <fwRuntime/ConfigurationElement.hpp>
21 #include <fwRuntime/ConfigurationElementContainer.hpp>
22 
23 #include <fwServices/macros.hpp>
24 
25 #include <fwThread/Pool.hpp>
26 #include <fwThread/Worker.hpp>
27 
28 #include <QPainter>
29 #include <QPixmap>
30 
31 fwServicesRegisterMacro( ::fwIO::IWriter, ::ioQt::SPdfWriter, ::fwData::Object );
32 
33 namespace ioQt
34 {
35 
36 const ::fwServices::IService::KeyType s_IMAGE_INPUT = "image";
37 const ::fwServices::IService::KeyType s_CONTAINER_INPUT = "container";
38 
39 //-----------------------------------------------------------------------------
40 
42 {
43 }
44 
45 //-----------------------------------------------------------------------------
46 
47 void SPdfWriter::info(std::ostream& _sstream )
48 {
49  this->::fwIO::IWriter::info( _sstream );
50  _sstream << std::endl << " External data file reader";
51 }
52 
53 //-----------------------------------------------------------------------------
54 
56 {
57  this->stopping();
58 }
59 
60 //------------------------------------------------------------------------------
61 
63 {
65 
66  typedef ::fwRuntime::ConfigurationElement::sptr ConfigurationType;
67  const ConfigurationType containersConfig = m_configuration->findConfigurationElement("container");
68  if (containersConfig)
69  {
70  const std::vector< ConfigurationType > containersCfg = containersConfig->find(s_CONTAINER_INPUT);
71  for (const auto& cfg : containersCfg)
72  {
73  SLM_ASSERT("Missing attribute 'uid'.", cfg->hasAttribute("uid"));
74  const std::string id = cfg->getAttributeValue("uid");
75  m_containersIDs.push_back( id );
76  }
77  }
78 }
79 
80 //------------------------------------------------------------------------------
81 
83 {
84  static ::boost::filesystem::path _sDefaultPath;
85 
87  dialogFile.setTitle(m_windowTitle.empty() ? "Choose an external data file" : m_windowTitle);
88  dialogFile.setDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
89  dialogFile.addFilter("pdf", "*.pdf");
90 
91  dialogFile.setOption(::fwGui::dialog::ILocationDialog::WRITE);
92 
93  ::fwData::location::SingleFile::sptr result;
94  result = ::fwData::location::SingleFile::dynamicCast( dialogFile.show() );
95  if (result)
96  {
97  _sDefaultPath = result->getPath();
98  dialogFile.saveDefaultLocation( ::fwData::location::Folder::New(_sDefaultPath) );
99  this->setFile(result->getPath());
100  }
101  else
102  {
103  this->clearLocations();
104  }
105 }
106 
107 //------------------------------------------------------------------------------
108 
110 {
111  if( !this->hasLocationDefined() )
112  {
114  }
115  if( this->hasLocationDefined() )
116  {
117  QPdfWriter pdfWriter( this->getLocations().front().string().c_str() );
118  QPainter painter( &pdfWriter );
119  pdfWriter.setPageSize( QPagedPaintDevice::A4 );
120 
121  // Scale value to fit the images to a PDF page
122  const int scale = static_cast<const int>(pdfWriter.logicalDpiX() * 8);
123  ::fwThread::Pool& pool = ::fwThread::getDefaultPool();
124 
125  // Adding fwImage from generic scene to the list of images to scale
126  ImagesScaledListType imagesToScale;
127  std::vector< std::shared_future< QImage > > futuresQImage;
128  for( const ::fwData::Image::sptr& fwImage : m_imagesToExport )
129  {
130  std::shared_future< QImage > future;
131  future = pool.post(&SPdfWriter::convertFwImageToQImage, fwImage);
132  futuresQImage.push_back( future );
133  }
134  std::for_each(futuresQImage.begin(), futuresQImage.end(), std::mem_fn(&std::shared_future< QImage >::wait));
135  for (auto& future : futuresQImage)
136  {
137  QImage imageToDraw = future.get();
138  imagesToScale.push_back(imageToDraw);
139  }
140 
141  // Adding QImage from Qt containers to the list of images to scale
142  for( QWidget*& qtContainer : m_containersToExport )
143  {
144  QImage imageToDraw = qtContainer->grab().toImage();
145  imagesToScale.push_back(imageToDraw);
146  }
147 
148  // Scales images to fit the A4 format
149  std::vector< std::shared_future< void > > futures;
150  const size_t sizeImagesToScale = imagesToScale.size();
151  for( size_t idx = 0; idx < sizeImagesToScale; ++idx )
152  {
153  std::shared_future<void> future;
154  future = pool.post(&SPdfWriter::scaleQImage, std::ref(imagesToScale[idx]), scale);
155  futures.push_back( future );
156  }
157  std::for_each(futures.begin(), futures.end(), std::mem_fn(&std::shared_future<void>::wait));
158 
159  // Draws images onto the PDF.
160  for( QImage& qImage : imagesToScale )
161  {
162  if ( pdfWriter.newPage() )
163  {
164  pdfWriter.setPageSize( QPagedPaintDevice::A4 );
165  if ( !qImage.isNull() && qImage.bits() != nullptr )
166  {
167  painter.drawImage( 0, 0, qImage);
168  }
169  }
170  }
171  painter.end();
172  }
173 }
174 
175 //------------------------------------------------------------------------------
176 
178 {
179  const size_t groupImageSize = this->getKeyGroupSize(s_IMAGE_INPUT);
180  for (size_t idxImage = 0; idxImage < groupImageSize; ++idxImage)
181  {
182  ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_IMAGE_INPUT, idxImage);
183  m_imagesToExport.push_back(image);
184  }
185 
186  for(const auto& id : m_containersIDs)
187  {
188  ::fwGuiQt::container::QtContainer::sptr containerElt;
189  ::fwGui::container::fwContainer::sptr fwContainerFromConfig;
191  {
192  fwContainerFromConfig = ::fwGui::GuiRegistry::getSIDContainer( id );
193  }
194  else
195  {
196  fwContainerFromConfig = ::fwGui::GuiRegistry::getWIDContainer( id );
197  }
198  if (fwContainerFromConfig)
199  {
200  containerElt = ::fwGuiQt::container::QtContainer::dynamicCast(fwContainerFromConfig);
201  m_containersToExport.push_back(containerElt->getQtContainer());
202  }
203  }
204 }
205 
206 //------------------------------------------------------------------------------
207 
209 {
210  for( QWidget*& qtContainer : m_containersToExport )
211  {
212  qtContainer = nullptr;
213  }
214  m_containersToExport.clear();
215  m_imagesToExport.clear();
216 }
217 
218 //------------------------------------------------------------------------------
219 
221 {
222  return ::fwIO::FILE;
223 }
224 
225 //------------------------------------------------------------------------------
226 
227 void SPdfWriter::scaleQImage(QImage& qImage, const int scale)
228 {
229  SLM_ERROR_IF("Image is null.", qImage.isNull());
230  qImage = qImage.scaledToWidth(scale, Qt::FastTransformation);
231 }
232 
233 //------------------------------------------------------------------------------
234 
235 QImage SPdfWriter::convertFwImageToQImage(::fwData::Image::sptr fwImage)
236 {
237  if (fwImage->getNumberOfComponents() == 3
238  && fwImage->getType().string() == "uint8"
239  && fwImage->getSize()[2] == 1)
240  {
241  // Initialize QImage parameters
242  const ::fwData::Image::SizeType dimension = fwImage->getSize();
243  const int width = static_cast<int>(dimension[0]);
244  const int height = static_cast<int>(dimension[1]);
245 
246  QImage qImage(width, height, QImage::Format_ARGB32);
247  std::uint8_t* qImageBuffer = qImage.bits();
248 
249  ::fwDataTools::helper::Image imgHelper(fwImage);
250  const std::uint8_t* fwImageBuffer = reinterpret_cast< const std::uint8_t*>( imgHelper.getBuffer() );
251 
252  const unsigned int size = static_cast<unsigned int>( width * height) * 4;
253  for(unsigned int idx = 0; idx < size; idx += 4)
254  {
255  qImageBuffer[idx+3] = (255 & 0xFF);
256  qImageBuffer[idx+2] = (*fwImageBuffer++ & 0xFF);
257  qImageBuffer[idx+1] = (*fwImageBuffer++ & 0xFF);
258  qImageBuffer[idx+0] = (*fwImageBuffer++ & 0xFF);
259  }
260  return qImage.mirrored(0, 1);
261  }
262  return QImage();
263 }
264 
265 //------------------------------------------------------------------------------
266 
267 } // namespace ioQt
static FWGUI_API::fwGui::container::fwContainer::sptr getWIDContainer(std::string wid)
Returns fwContainer associate with window ID, null if not found.
Creates and writes a PDF containing images.
Definition: SPdfWriter.hpp:51
IOQT_API void configureWithIHM() override
Configure the image path.
Definition: SPdfWriter.cpp:82
IOQT_API ~SPdfWriter() noexcept
Destructor.
Definition: SPdfWriter.cpp:55
virtual IOQT_API void starting() override
Starting method : Fills the list of Qt containers as well as the list of images got from the configur...
Definition: SPdfWriter.cpp:177
IOQT_API SPdfWriter()
Constructor : does nothing.
Definition: SPdfWriter.cpp:41
auto post(F &&f, Args &&...args) -> std::shared_future< typename std::result_of< F(Args...)>::type >
add new work item to the pool
Definition: Pool.hpp:65
virtual IOQT_API void configuring() override
Configure service. This method is called by configure() from base service ( fwServices::IService ) ...
Definition: SPdfWriter.cpp:62
virtual FWGUI_API void setDefaultLocation(::fwData::location::ILocation::sptr loc) override
Set the initial location for the dialog.
FWGUI_API::fwGui::dialog::ILocationDialog & setOption(::fwGui::dialog::ILocationDialog::Options option) override
allow to set option to the file dialog mode=READ/WRITE, check=FILE_MUST_EXIST
FWGUI_API::fwData::location::ILocation::sptr show() override
Display the dialog.
static FWGUI_API::fwGui::container::fwContainer::sptr getSIDContainer(std::string sid)
Returns fwContainer associate with service ID, null if not found.
Definition: GuiRegistry.cpp:67
FWGUI_API void addFilter(const std::string &filterName, const std::string &wildcardList) override
specify some filtering when browsing files:
virtual IOQT_API void stopping() override
Stopping method : default does nothing.
Definition: SPdfWriter.cpp:208
Defines an helper to modify an fwData::Image by adding few medical fields and create in parallel the ...
FWIO_API void setFile(const ::boost::filesystem::path &file)
Sets file path.
Definition: IWriter.cpp:49
virtual FWIO_API void configuring() override
This method proposes to parse xml configuration to retrieve file/files/folder paths.
Definition: IWriter.cpp:122
#define SLM_ERROR_IF(message, cond)
Definition: spyLog.hpp:276
This class creates and manages a pool of threads which process tasks.
Definition: Pool.hpp:32
FWIO_API void clearLocations()
Clear any location set by the setFile/setFiles/setFolder setter.
Definition: IWriter.cpp:115
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
virtual IOQT_API void info(std::ostream &_sstream) override
Info method.
Definition: SPdfWriter.cpp:47
Base class for each data object.
::fwRuntime::ConfigurationElement::sptr m_configuration
Configuration element used to configure service internal state using a generic XML like structure TOD...
Definition: IService.hpp:670
IOQT_API::fwIO::IOPathType getIOPathType() const override
Returns managed path type, here service manages only single file.
Definition: SPdfWriter.cpp:220
size_t getKeyGroupSize(const KeyType &keybase) const
Return the number of key in a group of keys.
Definition: IService.hxx:119
IOPathType
IOPathType defines different type of paths used by service readers/writers.
Definition: ioTypes.hpp:19
Writer service API. It manages extension points definition and extension configuration.
Definition: IWriter.hpp:33
FWGUI_API void setTitle(const std::string &title) override
Set the title for the dialog.
Defines the generic file/folder selector dialog for IHM.
FWIO_APIconst::fwIO::LocationsType & getLocations() const
Returns file/files/folder paths set by the user or set during service configuration.
Definition: IWriter.cpp:107
static FWGUI_API bool hasSIDContainer(std::string sid)
Verifies if a SID exists in the global SID container.
Definition: GuiRegistry.cpp:79
FWDATATOOLS_API void * getBuffer()
Returns image buffer.
FWGUI_API void saveDefaultLocation(::fwData::location::ILocation::sptr loc) override
Save the specified default location for the dialog in preferences (if available)
IOQT_API void updating() override
Updating method. Creates a new PDF.
Definition: SPdfWriter.cpp:109
FWIO_API bool hasLocationDefined() const
Returns if a location has been defined ( by the configuration process or directly by user ) ...
Definition: IWriter.cpp:184
virtual FWSERVICES_API void info(std::ostream &_sstream)
Write information in a stream.
Definition: IService.cpp:74
std::string m_windowTitle
Title of the window that will open when the configureWithIHM slot is called.
Definition: IWriter.hpp:171