libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNAltoWrapper.cpp
Go to the documentation of this file.
1 /* Copyright 2011-2016 CoReNum
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNAltoWrapper.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <CRNXml/CRNAltoWrapper.h>
23 #include <CRNIO/CRNIO.h>
24 #include <CRNi18n.h>
25 
26 using namespace crn;
27 using namespace xml;
28 
30 {
31  static const crn::String p(U" ");
32  return p;
33 }
34 
36 {
37  std::vector<String> pl(p.Split(Separator()));
38  if (pl.size() < 2)
39  throw ExceptionInvalidArgument(_("Malformed path string."));
40  view_id = pl[0];
41  page_id = pl[1].CStr();
42 }
43 
45 {
46  static const PagePath p;
47  return p;
48 }
49 
51 {
52  std::vector<String> pl(p.Split(Separator()));
53  if (pl.size() < 3)
54  throw ExceptionInvalidArgument(_("Malformed path string."));
55  view_id = pl[0];
56  page_id = pl[1].CStr();
57  space_id = pl[2].CStr();
58 }
59 
61 {
62  static const SpacePath p;
63  return p;
64 }
65 
66 
68 {
69  std::vector<String> pl(p.Split(Separator()));
70  if (pl.size() < 4)
71  throw ExceptionInvalidArgument(_("Malformed path string."));
72  view_id = pl[0];
73  page_id = pl[1].CStr();
74  space_id = pl[2].CStr();
75  block_id = pl[3].CStr();
76 }
77 
79 {
80  static const BlockPath p;
81  return p;
82 }
83 
85 {
86  std::vector<String> pl(p.Split(Separator()));
87  if (pl.size() < 5)
88  throw ExceptionInvalidArgument(_("Malformed path string."));
89  view_id = pl[0];
90  page_id = pl[1].CStr();
91  space_id = pl[2].CStr();
92  block_id = pl[3].CStr();
93  textline_id = pl[4].CStr();
94 }
95 
97 {
98  static const TextLinePath p;
99  return p;
100 }
101 
103 {
104  std::vector<String> pl(p.Split(Separator()));
105  if (pl.size() < 6)
106  throw ExceptionInvalidArgument(_("Malformed path string."));
107  view_id = pl[0];
108  page_id = pl[1].CStr();
109  space_id = pl[2].CStr();
110  block_id = pl[3].CStr();
111  textline_id = pl[4].CStr();
112  word_id = pl[5].CStr();
113 }
114 
116 {
117  static const WordPath p;
118  return p;
119 }
120 
122 {
123  static const crn::String k(U"nimrod::AltoPath");
124  return k;
125 }
127 {
128  static const crn::String k(U"nimrod::Page");
129  return k;
130 }
132 {
133  static const crn::String k(U"nimrod::Space");
134  return k;
135 }
137 {
138  static const crn::String k(U"nimrod::TextBlock");
139  return k;
140 }
142 {
143  static const crn::String k(U"nimrod::Illustration");
144  return k;
145 }
147 {
148  static const crn::String k(U"nimrod::GraphicalElement");
149  return k;
150 }
152 {
153  static const crn::String k(U"nimrod::ComposedBlock");
154  return k;
155 }
157 {
158  static const crn::String k(U"nimrod::TextLine");
159  return k;
160 }
162 {
163  static const crn::String k(U"nimrod::Word");
164  return k;
165 }
166 
170 AltoWrapper::AltoWrapper(bool throw_exceptions):
171  doc(std::make_shared<crn::Document>()),
172  throws(throw_exceptions)
173 {
174  doc->SetUserData(AltoPathKey(), std::make_shared<crn::Map>());
175 }
176 
177 struct keepXML
178 {
179  bool operator()(const Path &p) { Path ext(p.GetExtension()); ext.ToLower(); return ext != "xml"; }
180 };
194 std::unique_ptr<AltoWrapper> AltoWrapper::NewFromDir(const crn::Path &directory, const crn::Path &documentname, const crn::Path &imagedirectory, crn::Progress *prog, bool throw_exceptions)
195 {
196  // create data
197  std::unique_ptr<AltoWrapper> wrapper(new AltoWrapper(throw_exceptions));
198  // compute paths
199  const Path xpath(directory);
200  //std::cout << xpath << std::endl;
201  const Path ipath = imagedirectory.IsEmpty() ? directory : imagedirectory;
202  //std::cout << ipath << std::endl;
203 
204  // get list of XML files
205  IO::Directory xdir(xpath);
206  std::vector<Path> xfiles(xdir.GetFiles());
207  xfiles.erase(std::remove_if(xfiles.begin(), xfiles.end(), keepXML()), xfiles.end()); // filter files
208  std::sort(xfiles.begin(), xfiles.end()); // sort files
209 
210  // read altos and add images to document
211  if (prog)
212  prog->SetMaxCount(int(xfiles.size()));
213  for (const Path &altofile : xfiles)
214  {
215  //std::cout << altofile.CStr()<< std::endl;
216  try
217  {
218  Alto xml(altofile, throw_exceptions);
219  Alto::Description &desc(xml.GetDescription());
220  Path imgfile(desc.GetFilename().Get());
221  if (imgfile.IsRelative())
222  imgfile = ipath / imgfile;
223  wrapper->AddView(imgfile, altofile);
224  }
225  catch (std::exception &e)
226  { // cannot read the alto its image name is wrong
227  CRNdout << altofile.CStr() << " : " << e.what() << std::endl;
228  }
229  if (prog)
230  prog->Advance();
231  }
232 
233  // save document
234  wrapper->doc->Save(documentname);
235 
236  // compute links between Blocks and Altos
237  wrapper->Synchronize(false);
238 
239  return std::move(wrapper);
240 }
241 
255 std::unique_ptr<AltoWrapper> AltoWrapper::NewFromDirs(const crn::Path &image_directory, const crn::Path &xml_directory, const crn::Path &documentname, crn::Progress *prog, bool throw_exceptions)
256 {
257  // create data
258  std::unique_ptr<AltoWrapper> wrapper(new AltoWrapper(throw_exceptions));
259 
260  // get list of XML files
261  IO::Directory idir(image_directory);
262  std::vector<Path> ifiles(idir.GetFiles());
263  std::sort(ifiles.begin(), ifiles.end()); // sort files
264 
265  // read altos and add images to document
266  if (prog)
267  prog->SetMaxCount(int(ifiles.size()));
268  for (const Path &imgfile : ifiles)
269  {
270  try
271  {
272  Path altofile(xml_directory);
273  altofile += Path::Separator();
274  altofile += imgfile.GetBase();
275  if (IO::Access(altofile + ".xml", IO::EXISTS))
276  altofile += ".xml";
277  else if (IO::Access(altofile + ".Xml", IO::EXISTS))
278  altofile += ".Xml";
279  else if (IO::Access(altofile + ".XML", IO::EXISTS))
280  altofile += ".XML";
281  else
282  { // no alto corresponds to the image
283  throw crn::ExceptionNotFound(StringUTF8(imgfile) + _(": no xml match."));
284  }
285  wrapper->AddView(imgfile, altofile);
286  }
287  catch (std::exception &e)
288  { // cannot read the alto its image name is wrong
289  CRNWarning(e.what());
290  }
291  if (prog)
292  prog->Advance();
293  }
294 
295  // save document
296  wrapper->doc->Save(documentname);
297 
298  // compute links between Blocks and Altos
299  wrapper->Synchronize(false);
300 
301  return std::move(wrapper);
302 }
303 
311 std::unique_ptr<AltoWrapper> AltoWrapper::NewFromDocument(const crn::SDocument &document, bool create_altos, bool throw_exceptions)
312 {
313  if (!document->IsUserData(AltoPathKey()) && !create_altos)
314  throw crn::ExceptionInvalidArgument(_("The document is not associated to any Alto data."));
315 
316  UAltoWrapper wrapper(new AltoWrapper(throw_exceptions));
317  wrapper->doc = document;
318 
319  if (create_altos)
320  wrapper->createAltos();
321 
322  return std::move(wrapper);
323 }
324 
336 std::unique_ptr<AltoWrapper> AltoWrapper::NewFromDocument(const crn::Path &documentname, bool create_altos, bool throw_exceptions)
337 {
338  UAltoWrapper wrapper(new AltoWrapper(throw_exceptions));
339  wrapper->doc->Load(documentname);
340 
341  if (!wrapper->doc->IsUserData(AltoPathKey()) && !create_altos)
342  throw crn::ExceptionInvalidArgument(_("The document is not associated to any Alto data."));
343 
344  if (create_altos)
345  wrapper->createAltos();
346 
347  return std::move(wrapper);
348 }
349 
362 std::unique_ptr<AltoWrapper> AltoWrapper::newFromList(const std::vector<std::pair<crn::Path, crn::Path> > &filelist, const crn::Path &documentname, crn::Progress *prog, bool throw_exceptions)
363 {
364  // create data
365  UAltoWrapper wrapper(new AltoWrapper(throw_exceptions));
366 
367  // save document
368  wrapper->doc->Save(documentname);
369 
370  // read altos and add images to document
371  if (prog)
372  prog->SetMaxCount(int(filelist.size()));
373  for (const std::pair<crn::Path, crn::Path> &p : filelist)
374  {
375  wrapper->AddView(p.first, p.second);
376  if (prog)
377  prog->Advance();
378  }
379 
380  // compute links between Blocks and Altos
381  wrapper->Synchronize(false);
382 
383  // save document
384  wrapper->doc->Save();
385 
386  return std::move(wrapper);
387 }
388 
399 const String AltoWrapper::AddView(const Path &imagename, const Path &altoname)
400 {
401  { // check image
402  auto img = NewImageFromFile(imagename); // may throw
403  }
404  if (altoname.IsNotEmpty())
405  { // check alto
406  Alto a(altoname); // may throw
407  }
408  // add view
409  String vid = doc->AddView(imagename); // may throw
410  if (altoname.IsEmpty())
411  {
412  createAltos();
413  }
414  else
415  {
416  SMap altomap(std::static_pointer_cast<Map>(doc->GetUserData(AltoPathKey())));
417  altomap->Set(vid, Clone(altoname));
418  }
419  if (doc->GetFilename().IsNotEmpty())
420  doc->Save();
421  return vid;
422 }
423 
427 void AltoWrapper::Synchronize(bool reset)
428 {
429  SMap altomap(std::static_pointer_cast<Map>(doc->GetUserData(AltoPathKey())));
430  const std::vector<String> vids(doc->GetViewIds());
431  for(const String &id : vids)
432  {
433  SBlock block(doc->GetView(id));
434  // cleanup
435  if (block->HasTree(PageKey()))
436  {
437  if (reset)
438  block->RemoveTree(PageKey());
439  else
440  continue;
441  }
442 
443  // load alto
444  Alto alto(*std::static_pointer_cast<Path>((*altomap)[id]));
445 
446  // pages
447  std::vector<std::weak_ptr<Alto::Layout::Page> > pages(alto.GetLayout().GetPages());
448  int refx = 0;
449  for (const std::weak_ptr<Alto::Layout::Page> &page : pages)
450  {
451  const std::shared_ptr<Alto::Layout::Page> spage(page.lock());
452  try { spage->GetId(); } catch (...) { alto.AddId(*spage); }
453  crn::Rect pagearea;
454  const Option<Alto::Layout::Page::Position> pos(spage->GetPosition());
455  int pagew = spage->GetWidth() ? spage->GetWidth().Get() : block->GetAbsoluteBBox().GetWidth() / int(pages.size());
456  int pageh = spage->GetHeight() ? spage->GetHeight().Get() : block->GetAbsoluteBBox().GetHeight();
457  if (pos)
458  {
459  if (*pos == Alto::Layout::Page::Position::Right)
460  {
461  pagearea = crn::Rect(block->GetAbsoluteBBox().GetRight() - pagew, 0, block->GetAbsoluteBBox().GetRight(), pageh);
462  }
463  else // considered to be left
464  {
465  pagearea = crn::Rect(refx, 0, refx + pagew, pageh);
466  refx = pagearea.GetRight();
467  }
468  }
469  else
470  {
471  pagearea = crn::Rect(refx, 0, refx + pagew, pageh);
472  refx = pagearea.GetRight();
473  }
474  SBlock pageblock(block->AddChildAbsolute(PageKey(), pagearea, spage->GetId()));
475  // spaces
476  std::vector<std::weak_ptr<Alto::Layout::Page::Space> > spaces(spage->GetSpaces());
477  for (const std::weak_ptr<Alto::Layout::Page::Space> space : spaces)
478  {
479  const std::shared_ptr<Alto::Layout::Page::Space> sspace(space.lock());
480  try { sspace->GetId(); } catch (...) { alto.AddId(*sspace); }
481  int spacev = int(sspace->GetVPos());
482  int spaceh = int(sspace->GetHPos());
483  crn::Rect spacearea(spaceh, spacev, spaceh + int(sspace->GetWidth()), spacev + int(sspace->GetHeight()));
484  String sname(sspace->GetName());
485  sname.ToLower();
486  SBlock spaceblock(pageblock->AddChildAbsolute(SpaceKey(), spacearea, sname));
487  // text blocks
488  std::vector<std::weak_ptr<Alto::Layout::Page::Space::TextBlock> > textblocks(sspace->GetTextBlocks());
489  for (const std::weak_ptr<Alto::Layout::Page::Space::TextBlock> &tb : textblocks)
490  {
491  const std::shared_ptr<Alto::Layout::Page::Space::TextBlock> stb(tb.lock());
492  try { stb->GetId(); } catch (...) { alto.AddId(*stb); }
493  int tbv = int(stb->GetVPos());
494  int tbh = int(stb->GetHPos());
495  crn::Rect tbarea(tbh, tbv, tbh + int(stb->GetWidth()), tbv + int(stb->GetHeight()));
496  SBlock tbblock(spaceblock->AddChildAbsolute(TextBlockKey(), tbarea, stb->GetId()));
497  // lines
498  std::vector<std::weak_ptr<Alto::Layout::Page::Space::TextBlock::TextLine> > textlines(stb->GetTextLines());
499  for (const std::weak_ptr<Alto::Layout::Page::Space::TextBlock::TextLine> &tl : textlines)
500  {
501  const std::shared_ptr<Alto::Layout::Page::Space::TextBlock::TextLine> stl(tl.lock());
502  try { stl->GetId(); } catch (...) { alto.AddId(*stl); }
503  int tlv = int(stl->GetVPos());
504  int tlh = int(stl->GetHPos());
505  crn::Rect tlarea(tlh, tlv, tlh + int(stl->GetWidth()), tlv + int(stl->GetHeight()));
506  SBlock tlblock(tbblock->AddChildAbsolute(TextLineKey(), tlarea, stl->GetId()));
507  // words
508  std::vector<std::weak_ptr<Alto::Layout::Page::Space::TextBlock::TextLine::Word> > words(stl->GetWords());
509  for (const std::weak_ptr<Alto::Layout::Page::Space::TextBlock::TextLine::Word> &word : words)
510  {
511  const std::shared_ptr<Alto::Layout::Page::Space::TextBlock::TextLine::Word> sword(word.lock());
512  try { sword->GetId(); } catch (...) { alto.AddId(*sword); }
513  if (sword->GetVPos() && sword->GetHPos() && sword->GetWidth())
514  {
515  int wx = int(sword->GetHPos().Get());
516  int wy = int(sword->GetVPos().Get());
517  int ww = int(sword->GetWidth().Get());
518  int wh = sword->GetHeight() ? int(sword->GetHeight().Get()) : tlarea.GetHeight();
519  crn::Rect wordarea(wx, wy, wx + ww, wy + wh);
520  tlblock->AddChildAbsolute(WordKey(), wordarea, sword->GetId().Get());
521  }
522  } // words
523  } // lines
524  } // text blocks
525  // illustrations
526  std::vector<std::weak_ptr<Alto::Layout::Page::Space::Illustration> > illustrations(sspace->GetIllustrations());
527  for (const std::weak_ptr<Alto::Layout::Page::Space::Illustration> &illus : illustrations)
528  {
529  const std::shared_ptr<Alto::Layout::Page::Space::Illustration> sillus(illus.lock());
530  try { sillus->GetId(); } catch (...) { alto.AddId(*sillus); }
531  int ilv = int(sillus->GetVPos());
532  int ilh = int(sillus->GetHPos());
533  crn::Rect ilarea(ilh, ilv, ilh + int(sillus->GetWidth()), ilv + int(sillus->GetHeight()));
534  spaceblock->AddChildAbsolute(IllustrationKey(), ilarea);
535  } // illustrations
536  // illustrations
537  std::vector<std::weak_ptr<Alto::Layout::Page::Space::GraphicalElement> > graphelems(sspace->GetGraphicalElements());
538  for (const std::weak_ptr<Alto::Layout::Page::Space::GraphicalElement> &gel : graphelems)
539  {
540  const std::shared_ptr<Alto::Layout::Page::Space::GraphicalElement> sgel(gel.lock());
541  try { sgel->GetId(); } catch (...) { alto.AddId(*sgel); }
542  int gev = int(sgel->GetVPos());
543  int geh = int(sgel->GetHPos());
544  crn::Rect gearea(geh, gev, geh + int(sgel->GetWidth()), gev + int(sgel->GetHeight()));
545  spaceblock->AddChildAbsolute(GraphicalElementKey(), gearea);
546  } // illustrations
547  // composed blocks
548  // TODO
549  } // spaces
550  } // pages
551  alto.Save();
552  } // views
553 }
554 
557 void AltoWrapper::createAltos()
558 {
559  SMap altomap;
560  if (!doc->IsUserData(AltoPathKey()))
561  {
562  altomap = std::make_shared<crn::Map>();
563  doc->SetUserData(AltoPathKey(), altomap);
564  }
565  else
566  altomap = std::static_pointer_cast<Map>(doc->GetUserData(AltoPathKey()));
567  const std::vector<String> vids(doc->GetViewIds());
568  for (const String &id : vids)
569  {
570  if (altomap->Find(id) == altomap->end())
571  { // create alto
572  Alto a(doc->GetViewFilename(id), StringUTF8("nimrod"));
573  Path altoname(doc->GetBasename() / id.CStr() + "_alto.xml");
574  a.Save(altoname);
575  altomap->Set(id, Clone(altoname));
576  }
577  }
578  doc->Save();
579 }
580 
592 {
593  return View(getLock(view_id), view_id);
594 }
595 
608 {
609  String id(doc->GetViewId(index));
610  return View(getLock(id), id);
611 }
612 
623 std::shared_ptr<AltoWrapper::ViewLock> AltoWrapper::getLock(const String &view_id) const
624 {
625  std::map<String, std::weak_ptr<ViewLock> >::iterator it(viewLocks.find(view_id));
626  if (it == viewLocks.end())
627  {
628  SCMap altomap(std::static_pointer_cast<const Map>(doc->GetUserData(AltoPathKey())));
629  std::shared_ptr<ViewLock> vl(new ViewLock(doc->GetView(view_id), std::make_shared<Alto>(*std::static_pointer_cast<const Path>(altomap->Get(view_id)), throws))); // may throw
630  //it = viewLocks.insert(std::make_pair(view_id, vl)).first;
631  viewLocks[view_id] = vl;
632  return vl;
633  }
634  else
635  {
636  if (it->second.expired())
637  {
638  SCMap altomap(std::static_pointer_cast<const Map>(doc->GetUserData(AltoPathKey())));
639  std::shared_ptr<ViewLock> vl(new ViewLock(doc->GetView(view_id), std::make_shared<Alto>(*std::static_pointer_cast<const Path>(altomap->Get(view_id)), throws))); // may throw
640  //it = viewLocks.insert(std::make_pair(view_id, vl)).first;
641  viewLocks[view_id] = vl;
642  return vl;
643  }
644  else
645  {
646  return it->second.lock();
647  }
648  }
649 }
650 
663 {
665 }
666 
679 {
681 }
682 
695 {
697 }
698 
711 {
713 }
714 
727 {
728  return GetView(p.view_id).GetPage(p.page_id);
729 }
730 
737 {
738  GetView(p.view_id).ResizeWord(p, r);
739 }
740 
748 void AltoWrapper::ResizeTextLine(const TextLinePath &p, const crn::Rect &r, bool erase_oob)
749 {
750  GetView(p.view_id).ResizeTextLine(p, r, erase_oob);
751 }
752 
760 void AltoWrapper::ResizeTextBlock(const BlockPath &p, const crn::Rect &r, bool erase_oob)
761 {
762  GetView(p.view_id).ResizeTextBlock(p, r, erase_oob);
763 }
764 
772 void AltoWrapper::ResizeSpace(const SpacePath &p, const crn::Rect &r, bool erase_oob)
773 {
774  GetView(p.view_id).ResizeSpace(p, r, erase_oob);
775 }
776 
778 // View
780 
783 {
784  std::vector<Id> ids;
785  const std::vector<std::weak_ptr<AltoPage> > &pages(lock->GetAlto()->GetLayout().GetPages());
786  for (const std::weak_ptr<AltoPage> &p : pages)
787  ids.push_back(p.lock()->GetId());
788  return ids;
789 }
790 
797 {
798  SBlock b(lock->GetBlock()->GetChild(PageKey(), pageId)); // may throw
799  AltoPage &p(lock->GetAlto()->GetLayout().GetPage(pageId)); // may throw
800  return AltoWrapper::Page(b, p, lock, id);
801 }
802 
812 {
813  Id pageId(lock->GetAlto()->CreateId());
814  AltoPage &page(lock->GetAlto()->GetLayout().AddPage(pageId, image_number, w, h, pos));
815 
816  int pagew = page.GetWidth() ? page.GetWidth().Get() : lock->GetBlock()->GetAbsoluteBBox().GetWidth() / int(lock->GetAlto()->GetLayout().GetPages().size());
817  int pageh = page.GetHeight() ? page.GetHeight().Get() : lock->GetBlock()->GetAbsoluteBBox().GetHeight();
818  auto pagearea = crn::Rect(0, 0, pagew, pageh);
819  if (pos)
820  {
821  if (*pos == Alto::Layout::Page::Position::Right)
822  {
823  pagearea = crn::Rect(lock->GetBlock()->GetAbsoluteBBox().GetRight() - pagew, 0, lock->GetBlock()->GetAbsoluteBBox().GetRight(), pageh);
824  }
825  // else considered to be left
826  }
827  auto b = lock->GetBlock()->AddChildAbsolute(PageKey(), pagearea, pageId);
828 
829  return Page(b, page, lock, id);
830 }
831 
842 AltoWrapper::Page AltoWrapper::View::AddPageAfter(const Id &pred, int image_number, int w, int h, Option<AltoPage::Position> pos)
843 {
844  Id pageId(lock->GetAlto()->CreateId());
845  AltoPage &page(lock->GetAlto()->GetLayout().AddPageAfter(pred, pageId, image_number, w, h, pos)); // may throw
846 
847  int pagew = page.GetWidth() ? page.GetWidth().Get() : lock->GetBlock()->GetAbsoluteBBox().GetWidth() / int(lock->GetAlto()->GetLayout().GetPages().size());
848  int pageh = page.GetHeight() ? page.GetHeight().Get() : lock->GetBlock()->GetAbsoluteBBox().GetHeight();
849  auto pagearea = crn::Rect(0, 0, pagew, pageh);
850  if (pos)
851  {
852  if (*pos == Alto::Layout::Page::Position::Right)
853  {
854  pagearea = crn::Rect(lock->GetBlock()->GetAbsoluteBBox().GetRight() - pagew, 0, lock->GetBlock()->GetAbsoluteBBox().GetRight(), pageh);
855  }
856  // else considered to be left
857  }
858  auto b = lock->GetBlock()->AddChildAbsolute(PageKey(), pagearea, pageId);
859 
860  return Page(b, page, lock, id);
861 }
862 
873 AltoWrapper::Page AltoWrapper::View::AddPageBefore(const Id &next, int image_number, int w, int h, Option<AltoPage::Position> pos)
874 {
875  Id pageId(lock->GetAlto()->CreateId());
876  AltoPage &page(lock->GetAlto()->GetLayout().AddPageBefore(next, pageId, image_number, w, h, pos)); // may throw
877 
878  int pagew = page.GetWidth() ? page.GetWidth().Get() : lock->GetBlock()->GetAbsoluteBBox().GetWidth() / int(lock->GetAlto()->GetLayout().GetPages().size());
879  int pageh = page.GetHeight() ? page.GetHeight().Get() : lock->GetBlock()->GetAbsoluteBBox().GetHeight();
880  auto pagearea = crn::Rect(0, 0, pagew, pageh);
881  if (pos)
882  {
883  if (*pos == Alto::Layout::Page::Position::Right)
884  {
885  pagearea = crn::Rect(lock->GetBlock()->GetAbsoluteBBox().GetRight() - pagew, 0, lock->GetBlock()->GetAbsoluteBBox().GetRight(), pageh);
886  }
887  // else considered to be left
888  }
889  auto b = lock->GetBlock()->AddChildAbsolute(PageKey(), pagearea, pageId);
890 
891  return Page(b, page, lock, id);
892 }
893 
899 {
900  lock->GetAlto()->GetLayout().RemovePage(pageId);
901  lock->GetBlock()->RemoveChild(PageKey(), pageId);
902 }
903 
910 {
911  Page page(GetPage(p.page_id)); // may throw
912  Space space(page.GetSpace(p.space_id)); // may throw
913  TextBlock tb(space.GetTextBlock(p.block_id)); // may throw
914  TextLine tl(tb.GetTextLine(p.textline_id)); // may throw
915  Word w(tl.GetWord(p.word_id)); // may throw
916 
917  // page
918  crn::Rect box(page.GetBBox() | r);
919  if (box != page.GetBBox())
920  page.SetBBox(box, false); // grow
921  // space
922  box = space.GetBBox() | r;
923  if (box != space.GetBBox())
924  space.SetBBox(box, false); // grow
925  // block
926  box = tb.GetBBox() | r;
927  if (box != tb.GetBBox())
928  tb.SetBBox(box, false); // grow
929  // line
930  box = tl.GetBBox() | r;
931  if (box != tl.GetBBox())
932  tl.SetBBox(box, false); // grow
933  // word
934  w.SetBBox(r);
935 }
936 
944 void AltoWrapper::View::ResizeTextLine(const TextLinePath &p, const crn::Rect &r, bool erase_oob)
945 {
946  Page page(GetPage(p.page_id)); // may throw
947  Space space(page.GetSpace(p.space_id)); // may throw
948  TextBlock tb(space.GetTextBlock(p.block_id)); // may throw
949  TextLine tl(tb.GetTextLine(p.textline_id)); // may throw
950 
951  // page
952  crn::Rect box(page.GetBBox() | r);
953  if (box != page.GetBBox())
954  page.SetBBox(box, false); // grow
955  // space
956  box = space.GetBBox() | r;
957  if (box != space.GetBBox())
958  space.SetBBox(box, false); // grow
959  // block
960  box = tb.GetBBox() | r;
961  if (box != tb.GetBBox())
962  tb.SetBBox(box, false); // grow
963  // line
964  tl.SetBBox(r, erase_oob); // may throw only if shrinking
965 }
966 
974 void AltoWrapper::View::ResizeTextBlock(const BlockPath &p, const crn::Rect &r, bool erase_oob)
975 {
976  Page page(GetPage(p.page_id)); // may throw
977  Space space(page.GetSpace(p.space_id)); // may throw
978  TextBlock tb(space.GetTextBlock(p.block_id)); // may throw
979 
980  // page
981  crn::Rect box(page.GetBBox() | r);
982  if (box != page.GetBBox())
983  page.SetBBox(box, false); // grow
984  // space
985  box = space.GetBBox() | r;
986  if (box != space.GetBBox())
987  space.SetBBox(box, false); // grow
988  // block
989  tb.SetBBox(r, erase_oob); // may throw only if shrinking
990 }
991 
999 void AltoWrapper::View::ResizeSpace(const SpacePath &p, const crn::Rect &r, bool erase_oob)
1000 {
1001  Page page(GetPage(p.page_id)); // may throw
1002  Space space(page.GetSpace(p.space_id)); // may throw
1003 
1004  // page
1005  crn::Rect box(page.GetBBox() | r);
1006  if (box != page.GetBBox())
1007  page.SetBBox(box, false); // grow
1008  // space
1009  space.SetBBox(r, erase_oob); // may throw only if shrinking
1010 }
1011 
1013 // Page
1015 
1023 void AltoWrapper::Page::SetBBox(const crn::Rect &r, bool erase_oob)
1024 {
1025  // check inner elements
1026  const std::vector<Id> spaces(GetSpaces());
1027  for (const Id &sid : spaces)
1028  {
1029  Space s(GetSpace(sid));
1030  if ((s.GetBBox() & r).GetArea() == 0)
1031  {
1032  if (erase_oob)
1033  RemoveSpace(sid);
1034  else
1035  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1036  }
1037  if (!erase_oob)
1038  {
1039  const std::vector<Id> blocks(s.GetTextBlocks());
1040  for (const Id &bid : blocks)
1041  {
1042  TextBlock tb(s.GetTextBlock(bid));
1043  if ((tb.GetBBox() & r).GetArea() == 0)
1044  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1045  const std::vector<Id> lines(tb.GetTextLines());
1046  for (const Id &lid : lines)
1047  {
1048  TextLine tl(tb.GetTextLine(lid));
1049  if ((tl.GetBBox() & r).GetArea() == 0)
1050  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1051  const std::vector<Id> words(tl.GetWords());
1052  for (const Id &wid : words)
1053  {
1054  Word w(tl.GetWord(wid));
1055  if ((w.GetBBox() & r).GetArea() == 0)
1056  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1057  }
1058  }
1059  }
1060  }
1061  }
1062  block->SetAbsoluteBBox(r); // adjusts the coordinates of the words in the CRNBlock
1063  const crn::Rect crop(block->GetAbsoluteBBox());
1064  //page->SetHPos(crop.GetLeft());
1065  //page->SetVPos(crop.GetTop());
1066  page->SetWidth(crop.GetWidth());
1067  page->SetHeight(crop.GetHeight());
1068  for (const Id &sid : spaces)
1069  {
1070  Space s(GetSpace(sid));
1071  s.SetBBox(s.GetBBox(), erase_oob); // GetBBox() uses the CRNBlock's coordinates that are up to date
1072  }
1073 }
1074 
1076 std::vector<Alto::Styles::Text> AltoWrapper::Page::GetTextStyles()
1077 {
1078  std::vector<Alto::Styles::Text> sty;
1079  const std::vector<Id> &sids(GetStyles());
1080  for (const Id &sid : sids)
1081  {
1082  try { sty.push_back(lock->GetAlto()->GetStyles().GetTextStyle(sid)); } catch (...) { }
1083  }
1084  return sty;
1085 }
1086 
1088 std::vector<Alto::Styles::Paragraph> AltoWrapper::Page::GetParagraphStyles()
1089 {
1090  std::vector<Alto::Styles::Paragraph> sty;
1091  const std::vector<Id> &sids(GetStyles());
1092  for (const Id &sid : sids)
1093  {
1094  try { sty.push_back(lock->GetAlto()->GetStyles().GetParagraphStyle(sid)); } catch (...) { }
1095  }
1096  return sty;
1097 }
1098 
1100 std::vector<Id> AltoWrapper::Page::GetSpaces() const
1101 {
1102  const std::vector<std::weak_ptr<AltoSpace> > spaces(page->GetSpaces());
1103  std::vector<Id> ids(spaces.size());
1104  for (size_t tmp = 0; tmp < spaces.size(); ++tmp)
1105  ids[tmp] = spaces[tmp].lock()->GetId().Get(); // the id should have been allocated if it was originally missing
1106  return ids;
1107 }
1108 
1115 {
1116  AltoSpace &sp(page->GetSpace(spaceid)); // may throw
1117  String n(sp.GetName());
1118  n.ToLower();
1119  SBlock b(block->GetChild(SpaceKey(), n)); // may throw
1120  return AltoWrapper::Space(b, sp, lock, path);
1121 }
1122 
1128 {
1129  std::weak_ptr<AltoSpace> sp(page->GetTopMargin());
1130  if (sp.expired())
1131  throw ExceptionNotFound(_("No top margin on this page."));
1132  SBlock b(block->GetChild(SpaceKey(), U"topmargin")); // may throw
1133  return AltoWrapper::Space(b, *sp.lock(), lock, path);
1134 }
1135 
1142 {
1143  AltoSpace &sp(page->AddTopMargin(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1144  SBlock b(block->AddChildAbsolute(SpaceKey(), bbox, U"topmargin"));
1145  return AltoWrapper::Space(b, sp, lock, path);
1146 }
1147 
1153 {
1154  std::weak_ptr<AltoSpace> sp(page->GetLeftMargin());
1155  if (sp.expired())
1156  throw ExceptionNotFound(_("No left margin on this page."));
1157  SBlock b(block->GetChild(SpaceKey(), U"leftmargin")); // may throw
1158  return AltoWrapper::Space(b, *sp.lock(), lock, path);
1159 }
1160 
1167 {
1168  AltoSpace &sp(page->AddLeftMargin(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1169  SBlock b(block->AddChildAbsolute(SpaceKey(), bbox, U"leftmargin"));
1170  return AltoWrapper::Space(b, sp, lock, path);
1171 }
1172 
1178 {
1179  std::weak_ptr<AltoSpace> sp(page->GetBottomMargin());
1180  if (sp.expired())
1181  throw ExceptionNotFound(_("No bottom margin on this page."));
1182  SBlock b(block->GetChild(SpaceKey(), U"bottommargin")); // may throw
1183  return AltoWrapper::Space(b, *sp.lock(), lock, path);
1184 }
1185 
1192 {
1193  AltoSpace &sp(page->AddBottomMargin(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1194  SBlock b(block->AddChildAbsolute(SpaceKey(), bbox, U"bottommargin"));
1195  return AltoWrapper::Space(b, sp, lock, path);
1196 }
1197 
1203 {
1204  std::weak_ptr<AltoSpace> sp(page->GetRightMargin());
1205  if (sp.expired())
1206  throw ExceptionNotFound(_("No right margin on this page."));
1207  SBlock b(block->GetChild(SpaceKey(), U"rightmargin")); // may throw
1208  return AltoWrapper::Space(b, *sp.lock(), lock, path);
1209 }
1210 
1217 {
1218  AltoSpace &sp(page->AddRightMargin(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1219  SBlock b(block->AddChildAbsolute(SpaceKey(), bbox, U"rightmargin"));
1220  return AltoWrapper::Space(b, sp, lock, path);
1221 }
1222 
1228 {
1229  std::weak_ptr<AltoSpace> sp(page->GetPrintSpace());
1230  if (sp.expired())
1231  throw ExceptionNotFound(_("No print space on this page."));
1232  SBlock b(block->GetChild(SpaceKey(), U"printspace")); // may throw
1233  return AltoWrapper::Space(b, *sp.lock(), lock, path);
1234 }
1235 
1242 {
1243  AltoSpace &sp(page->AddPrintSpace(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1244  SBlock b(block->AddChildAbsolute(SpaceKey(), bbox, U"printspace"));
1245  return AltoWrapper::Space(b, sp, lock, path);
1246 }
1247 
1253 {
1254  page->RemoveSpace(sid);
1255  block->RemoveChild(SpaceKey(), sid);
1256 }
1257 
1262 /*
1263  void AltoWrapper::Page::ImportContent(AltoWrapper::Page &other, const crn::Rect &crop)
1264  {
1265  try
1266  {
1267  crn::xml::AltoWrapper::Space sp(other.GetTopMargin());
1268  crn::Rect sbbox(sp.GetBBox());
1269  if (crop.IsValid())
1270  sbbox &= crop;
1271  if (sbbox.IsValid())
1272  {
1273 // TODO!!
1274 }
1275 }
1276 catch (crn::ExceptionNotFound&) { } // no top margin
1277 
1278 }
1279 */
1280 
1282 // Space
1284 
1292 void AltoWrapper::Space::SetBBox(const crn::Rect &r, bool erase_oob)
1293 {
1294  // check inner elements
1295  const std::vector<Id> blocks(GetTextBlocks());
1296  for (const Id &bid : blocks)
1297  {
1298  TextBlock tb(GetTextBlock(bid));
1299  if ((tb.GetBBox() & r).GetArea() == 0)
1300  {
1301  if (erase_oob)
1302  RemoveBlock(bid);
1303  else
1304  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1305  }
1306  if (!erase_oob)
1307  {
1308  const std::vector<Id> lines(tb.GetTextLines());
1309  for (const Id &lid : lines)
1310  {
1311  TextLine tl(tb.GetTextLine(lid));
1312  if ((tl.GetBBox() & r).GetArea() == 0)
1313  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1314  const std::vector<Id> words(tl.GetWords());
1315  for (const Id &wid : words)
1316  {
1317  Word w(tl.GetWord(wid));
1318  if ((w.GetBBox() & r).GetArea() == 0)
1319  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1320  }
1321  }
1322  }
1323  }
1324  block->SetAbsoluteBBox(r); // adjusts the coordinates of the words in the CRNBlock
1325  const crn::Rect crop(block->GetAbsoluteBBox());
1326  space->SetHPos(crop.GetLeft());
1327  space->SetVPos(crop.GetTop());
1328  space->SetWidth(crop.GetWidth());
1329  space->SetHeight(crop.GetHeight());
1330  for (const Id &bid : blocks)
1331  {
1332  TextBlock tb(GetTextBlock(bid));
1333  tb.SetBBox(tb.GetBBox(), erase_oob); // GetBBox() uses the CRNBlock's coordinates that are up to date
1334  } // TODO XXX resize the illustrations and other non-text blocks
1335 }
1336 
1338 std::vector<Alto::Styles::Text> AltoWrapper::Space::GetTextStyles()
1339 {
1340  std::vector<Alto::Styles::Text> sty;
1341  const std::vector<Id> &sids(GetStyles());
1342  for (const Id &sid : sids)
1343  {
1344  try { sty.push_back(lock->GetAlto()->GetStyles().GetTextStyle(sid)); } catch (...) { }
1345  }
1346  return sty;
1347 }
1348 
1350 std::vector<Alto::Styles::Paragraph> AltoWrapper::Space::GetParagraphStyles()
1351 {
1352  std::vector<Alto::Styles::Paragraph> sty;
1353  const std::vector<Id> &sids(GetStyles());
1354  for (const Id &sid : sids)
1355  {
1356  try { sty.push_back(lock->GetAlto()->GetStyles().GetParagraphStyle(sid)); } catch (...) { }
1357  }
1358  return sty;
1359 }
1360 
1362 std::vector<Id> AltoWrapper::Space::GetTextBlocks() const
1363 {
1364  const std::vector<std::weak_ptr<AltoTextBlock> > tbs(space->GetTextBlocks());
1365  std::vector<Id> ids(tbs.size());
1366  for (size_t tmp = 0; tmp < tbs.size(); ++tmp)
1367  ids[tmp] = tbs[tmp].lock()->GetId();
1368  return ids;
1369 }
1370 
1377 {
1378  AltoTextBlock &tb(space->GetTextBlock(id)); // may throw
1379  SBlock b(block->GetChild(TextBlockKey(), id)); // may throw
1380  return AltoWrapper::TextBlock(b, tb, lock, path);
1381 }
1382 
1388 {
1389  AltoTextBlock &tb(space->AddTextBlock(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1390  SBlock b(block->AddChildAbsolute(TextBlockKey(), bbox, tb.GetId()));
1391  return AltoWrapper::TextBlock(b, tb, lock, path);
1392 }
1393 
1401 {
1402  AltoTextBlock &tb(space->AddTextBlockAfter(pred, lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1403  SBlock b(block->AddChildAbsolute(TextBlockKey(), bbox, tb.GetId()));
1404  return AltoWrapper::TextBlock(b, tb, lock, path);
1405 }
1406 
1414 {
1415  AltoTextBlock &tb(space->AddTextBlockBefore(next, lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight())); // may throw
1416  SBlock b(block->AddChildAbsolute(TextBlockKey(), bbox, tb.GetId()));
1417  return AltoWrapper::TextBlock(b, tb, lock, path);
1418 }
1419 
1425 {
1426  space->RemoveBlock(bid);
1427  block->RemoveChild(TextBlockKey(), bid);
1428 }
1429 
1431 // TextBlock
1433 
1441 void AltoWrapper::TextBlock::SetBBox(const crn::Rect &r, bool erase_oob)
1442 {
1443  // check inner elements
1444  const std::vector<Id> lines(GetTextLines());
1445  for (const Id &lid : lines)
1446  {
1447  TextLine tl(GetTextLine(lid));
1448  if ((tl.GetBBox() & r).GetArea() == 0)
1449  {
1450  if (erase_oob)
1451  RemoveTextLine(lid);
1452  else
1453  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1454  }
1455  if (!erase_oob)
1456  {
1457  const std::vector<Id> words(tl.GetWords());
1458  for (const Id &wid : words)
1459  {
1460  Word w(tl.GetWord(wid));
1461  if ((w.GetBBox() & r).GetArea() == 0)
1462  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1463  }
1464  }
1465  }
1466  block->SetAbsoluteBBox(r); // adjusts the coordinates of the words in the CRNBlock
1467  const crn::Rect crop(block->GetAbsoluteBBox());
1468  textblock->SetHPos(crop.GetLeft());
1469  textblock->SetVPos(crop.GetTop());
1470  textblock->SetWidth(crop.GetWidth());
1471  textblock->SetHeight(crop.GetHeight());
1472  for (const Id &lid : lines)
1473  {
1474  TextLine tl(GetTextLine(lid));
1475  tl.SetBBox(tl.GetBBox(), erase_oob); // GetBBox() uses the CRNBlock's coordinates that are up to date
1476  }
1477 }
1478 
1480 std::vector<Alto::Styles::Text> AltoWrapper::TextBlock::GetTextStyles()
1481 {
1482  std::vector<Alto::Styles::Text> sty;
1483  const std::vector<Id> &sids(GetStyles());
1484  for (const Id &sid : sids)
1485  {
1486  try { sty.push_back(lock->GetAlto()->GetStyles().GetTextStyle(sid)); } catch (...) { }
1487  }
1488  return sty;
1489 }
1490 
1492 std::vector<Alto::Styles::Paragraph> AltoWrapper::TextBlock::GetParagraphStyles()
1493 {
1494  std::vector<Alto::Styles::Paragraph> sty;
1495  const std::vector<Id> &sids(GetStyles());
1496  for (const Id &sid : sids)
1497  {
1498  try { sty.push_back(lock->GetAlto()->GetStyles().GetParagraphStyle(sid)); } catch (...) { }
1499  }
1500  return sty;
1501 }
1502 
1505 {
1506  const std::vector<std::weak_ptr<AltoTextLine> > tls(textblock->GetTextLines());
1507  std::vector<Id> ids(tls.size());
1508  for (size_t tmp = 0; tmp < tls.size(); ++tmp)
1509  ids[tmp] = tls[tmp].lock()->GetId();
1510  return ids;
1511 }
1512 
1519 {
1520  AltoTextLine &tl(textblock->GetTextLine(id)); // may throw
1521  SBlock b(block->GetChild(TextLineKey(), id)); // may throw
1522  return AltoWrapper::TextLine(b, tl, lock, path);
1523 }
1524 
1530 {
1531  AltoTextLine &tl(textblock->AddTextLine(lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1532  SBlock b(block->AddChildAbsolute(TextLineKey(), bbox, tl.GetId()));
1533  return AltoWrapper::TextLine(b, tl, lock, path);
1534 }
1535 
1543 {
1544  AltoTextLine &tl(textblock->AddTextLineAfter(pred, lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1545  SBlock b(block->AddChildAbsolute(TextLineKey(), bbox, tl.GetId()));
1546  return AltoWrapper::TextLine(b, tl, lock, path);
1547 }
1548 
1556 {
1557  AltoTextLine &tl(textblock->AddTextLineBefore(next, lock->GetAlto()->CreateId(), bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1558  SBlock b(block->AddChildAbsolute(TextLineKey(), bbox, tl.GetId()));
1559  return AltoWrapper::TextLine(b, tl, lock, path);
1560 }
1561 
1567 {
1568  textblock->RemoveTextLine(tid);
1569  block->RemoveChild(TextLineKey(), tid);
1570 }
1571 
1573 // TextLine
1575 
1577 std::vector<Alto::Styles::Text> AltoWrapper::TextLine::GetTextStyles()
1578 {
1579  std::vector<Alto::Styles::Text> sty;
1580  const std::vector<Id> &sids(GetStyles());
1581  for (const Id &sid : sids)
1582  {
1583  try { sty.push_back(lock->GetAlto()->GetStyles().GetTextStyle(sid)); } catch (...) { }
1584  }
1585  return sty;
1586 }
1587 
1589 std::vector<Alto::Styles::Paragraph> AltoWrapper::TextLine::GetParagraphStyles()
1590 {
1591  std::vector<Alto::Styles::Paragraph> sty;
1592  const std::vector<Id> &sids(GetStyles());
1593  for (const Id &sid : sids)
1594  {
1595  try { sty.push_back(lock->GetAlto()->GetStyles().GetParagraphStyle(sid)); } catch (...) { }
1596  }
1597  return sty;
1598 }
1599 
1607 void AltoWrapper::TextLine::SetBBox(const crn::Rect &r, bool erase_oob)
1608 {
1609  // check inner elements
1610  const std::vector<Id> words(GetWords());
1611  for (const Id &wid : words)
1612  {
1613  Word w(GetWord(wid));
1614  if ((w.GetBBox() & r).GetArea() == 0)
1615  {
1616  if (erase_oob)
1617  RemoveWord(wid);
1618  else
1619  throw crn::ExceptionDomain(_("Resizing the element would invalidate its content."));
1620  }
1621  }
1622  block->SetAbsoluteBBox(r); // adjusts the coordinates of the words in the CRNBlock
1623  const crn::Rect crop(block->GetAbsoluteBBox());
1624  textline->SetHPos(crop.GetLeft());
1625  textline->SetVPos(crop.GetTop());
1626  textline->SetWidth(crop.GetWidth());
1627  textline->SetHeight(crop.GetHeight());
1628  for (const Id &wid : words)
1629  {
1630  Word w(GetWord(wid));
1631  w.SetBBox(w.GetBBox()); // GetBBox() uses the CRNBlock's coordinates that are up to date
1632  }
1633 }
1634 
1636 std::vector<Id> AltoWrapper::TextLine::GetWords() const
1637 {
1638  const std::vector<std::weak_ptr<AltoWord> > words(textline->GetWords());
1639  std::vector<Id> ids(words.size());
1640  for (size_t tmp = 0; tmp < words.size(); ++tmp)
1641  ids[tmp] = words[tmp].lock()->GetId().Get();
1642  return ids;
1643 }
1644 
1651 {
1652  AltoWord &word(textline->GetWord(id)); // may throw
1653  SBlock b(block->GetChild(WordKey(), id)); // may throw
1654  return AltoWrapper::Word(b, word, lock, path);
1655 }
1656 
1662 {
1663  AltoWord &w(textline->AddWord(lock->GetAlto()->CreateId(), text, bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1664  SBlock b(block->AddChildAbsolute(WordKey(), bbox, w.GetId().Get()));
1665  return AltoWrapper::Word(b, w, lock, path);
1666 }
1667 
1675 {
1676  AltoWord &w(textline->AddWordAfter(pred, lock->GetAlto()->CreateId(), text, bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1677  SBlock b(block->AddChildAbsolute(WordKey(), bbox, w.GetId().Get()));
1678  return AltoWrapper::Word(b, w, lock, path);
1679 }
1680 
1688 {
1689  AltoWord &w(textline->AddWordBefore(next, lock->GetAlto()->CreateId(), text, bbox.GetLeft(), bbox.GetTop(), bbox.GetWidth(), bbox.GetHeight()));
1690  SBlock b(block->AddChildAbsolute(WordKey(), bbox, w.GetId().Get()));
1691  return AltoWrapper::Word(b, w, lock, path);
1692 }
1693 
1699 {
1700  textline->RemoveWord(wid);
1701  block->RemoveChild(WordKey(), wid);
1702 }
1703 
1705 // Word
1707 
1709 std::vector<Alto::Styles::Text> AltoWrapper::Word::GetTextStyles()
1710 {
1711  std::vector<Alto::Styles::Text> sty;
1712  const std::vector<Id> &sids(GetStyles());
1713  for (const Id &sid : sids)
1714  {
1715  try { sty.push_back(lock->GetAlto()->GetStyles().GetTextStyle(sid)); } catch (...) { }
1716  }
1717  return sty;
1718 }
1719 
1721 std::vector<Alto::Styles::Paragraph> AltoWrapper::Word::GetParagraphStyles()
1722 {
1723  std::vector<Alto::Styles::Paragraph> sty;
1724  const std::vector<Id> &sids(GetStyles());
1725  for (const Id &sid : sids)
1726  {
1727  try { sty.push_back(lock->GetAlto()->GetStyles().GetParagraphStyle(sid)); } catch (...) { }
1728  }
1729  return sty;
1730 }
1731 
1738 {
1739  block->SetAbsoluteBBox(r);
1740  const crn::Rect crop(block->GetAbsoluteBBox());
1741  word->SetHPos(crop.GetLeft());
1742  word->SetVPos(crop.GetTop());
1743  word->SetWidth(crop.GetWidth());
1744  word->SetHeight(crop.GetHeight());
1745 }
1746 
static const String & GraphicalElementKey()
const Rect & GetBBox() const
Gets the coordinates of the text block.
TextBlock AddTextBlockAfter(const Id &pred, const crn::Rect &bbox)
Adds a text block to the space.
void RemovePage(const Id &pageId)
Removes a page.
TextLine GetTextLine(const TextLinePath &p)
Gets a TextLine by path.
Space AddPrintSpace(const crn::Rect &bbox)
Adds the print space.
StringUTF8 & ToLower()
Converts the string to lowercase.
AltoWrapper(const AltoWrapper &)=delete
Page AddPageAfter(const Id &pred, int image_number, int w, int h, Option< AltoPage::Position > pos=Option< AltoPage::Position >())
Adds a page.
const Rect & GetBBox() const
Gets the coordinates of the word.
void ResizeTextLine(const TextLinePath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a line and all its parents if needed.
std::vector< Alto::Styles::Paragraph > GetParagraphStyles()
Returns the paragraph styles.
TextBlock AddTextBlockBefore(const Id &next, const crn::Rect &bbox)
Adds a text block to the space.
std::vector< String > Split(const String &sep) const
Splits the string in multiple strings delimited by a set of separators.
Definition: CRNString.cpp:772
static std::unique_ptr< AltoWrapper > NewFromDir(const crn::Path &directory, const crn::Path &documentname, const crn::Path &imagedirectory="", crn::Progress *prog=nullptr, bool throw_exceptions=true)
Creates a wrapper from a directory containing Altos.
std::vector< Alto::Styles::Text > GetTextStyles()
Returns the text styles.
Base class for a progress display.
Definition: CRNProgress.h:39
Page GetPage(const PagePath &p)
Gets a Page by path.
TextLine AddTextLineBefore(const Id &next, const crn::Rect &bbox)
Adds a text line to the block.
void ResizeTextLine(const TextLinePath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a line and all its parents if needed.
XML Alto file wrapper.
Definition: CRNAlto.h:40
Space AddBottomMargin(const crn::Rect &bbox)
Adds a bottom margin.
std::vector< Alto::Styles::Paragraph > GetParagraphStyles()
Returns the paragraph styles.
Page GetPage(const Id &pageId)
Gets a page.
#define _(String)
Definition: CRNi18n.h:51
Space GetRightMargin()
Gets the space proxy on the right margin.
Word AddWordAfter(const Id &pred, const StringUTF8 &text, const crn::Rect &bbox)
Adds a word to the line.
Word AddWordBefore(const Id &next, const StringUTF8 &text, const crn::Rect &bbox)
Adds a word to the line.
void SetBBox(const crn::Rect &r, bool erase_oob)
Sets the coordinates of the space.
void ResizeSpace(const SpacePath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a space and all its parents if needed.
std::vector< Id > GetWords() const
Returns the ids of the words in the line.
XML document.
Definition: CRNXml.h:429
static const String & TextBlockKey()
std::vector< Alto::Styles::Paragraph > GetParagraphStyles()
Returns the paragraph styles.
void RemoveSpace(const Id &sid)
Removes a space.
Page AddPageBefore(const Id &next, int image_number, int w, int h, Option< AltoPage::Position > pos=Option< AltoPage::Position >())
Adds a page.
static const String & ComposedBlockKey()
bool IsNotEmpty() const noexcept
Checks if the string is not empty.
static const String & WordKey()
void RemoveWord(const Id &wid)
Removes a line element.
#define CRNWarning(x)
Definition: CRNIO.h:145
static char Separator() noexcept
Local directory separator.
Definition: CRNPath.cpp:42
Space GetLeftMargin()
Gets the space proxy on the left margin.
int GetTop() const
Returns the topmost coordinate.
Definition: CRNRect.h:107
int GetLeft() const
Returns the leftmost coordinate.
Definition: CRNRect.h:99
void Synchronize(bool reset=false)
Creates CRNBlocks and ids where there is none.
static const String & IllustrationKey()
View GetView(const String &view_id)
Gets a view by id.
A handler to the content of a directory.
Definition: CRNIO.h:116
Alto::Layout::Page AltoPage
Definition: CRNAlto.h:139
void Advance()
Progresses of one step.
Definition: CRNProgress.cpp:34
A UTF32 character string class.
Definition: CRNString.h:61
const String AddView(const Path &imagename, const Path &altoname="")
Adds a view to the document.
void ResizeWord(const WordPath &p, const crn::Rect &r)
Changes the size of a word and all its parents if needed.
TextBlock GetTextBlock(const Id &id)
Gets a text block proxy.
Space GetBottomMargin()
Gets the space proxy on the bottom margin.
T & Get() noexcept
Value access (undefined behaviour if the value is not set)
Definition: CRNOption.h:65
A generic domain error.
Definition: CRNException.h:83
std::vector< Alto::Styles::Text > GetTextStyles()
Returns the text styles.
Alto::Layout::Page::Space::TextBlock AltoTextBlock
Definition: CRNAlto.h:145
TextBlock AddTextBlock(const crn::Rect &bbox)
Adds a text block to the space.
std::vector< Id > GetTextBlocks() const
Returns the ids of the text blocks in the page space.
#define CRNdout
Definition: CRNIO.h:143
int SetWidth(int wid)
Changes the width of the rectangle.
Definition: CRNRect.h:210
const char * CStr() const noexcept
Conversion to UTF8 cstring.
static const crn::String & Separator()
Space GetSpace(const SpacePath &p)
Gets a Space by path.
Word AddWord(const StringUTF8 &text, const crn::Rect &bbox)
Adds a word to the line.
bool IsEmpty() const noexcept
Checks if the string is empty.
static const TextLinePath & NullPath()
A convenience class for file paths.
Definition: CRNPath.h:39
void ResizeWord(const WordPath &p, const crn::Rect &r)
Changes the size of a word and all its parents if needed.
std::vector< Alto::Styles::Text > GetTextStyles()
Returns the text styles.
Id AddId(Element &el)
Adds an id to an element.
Definition: CRNAlto.cpp:622
std::vector< Alto::Styles::Paragraph > GetParagraphStyles()
Returns the paragraph styles.
void SetBBox(const crn::Rect &r, bool erase_oob)
Sets the coordinates of the text line.
const Rect & GetBBox() const
Gets the coordinates of the page.
std::vector< PagePtr > GetPages() const
Returns the list of all pages.
static const BlockPath & NullPath()
static const WordPath & NullPath()
Layout & GetLayout()
Gets the layout description part of the Alto.
Definition: CRNAlto.h:101
void Save(const Path &fname)
Saves to file.
Definition: CRNXml.cpp:1009
bool operator()(const Path &p)
const Rect & GetBBox() const
Gets the coordinates of the space.
void SetBBox(const crn::Rect &r, bool erase_oob)
Sets the coordinates of the page.
Word GetWord(const Id &id)
Gets a word proxy.
void ResizeTextBlock(const BlockPath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a text block and all its parents if needed.
static const String & TextLineKey()
Space GetTopMargin()
Gets the space proxy on the top margin.
static std::unique_ptr< AltoWrapper > NewFromDocument(const crn::SDocument &document, bool create_altos=false, bool throw_exceptions=true)
Creates a wrapper from a crn::Document that was created by Nimrod.
Alto::Layout::Page::Space::TextBlock::TextLine::Word AltoWord
Definition: CRNAlto.h:157
std::vector< Id > GetTextLines() const
Returns the ids of the text lines in the page space.
Space AddRightMargin(const crn::Rect &bbox)
Adds a right margin.
static std::unique_ptr< AltoWrapper > NewFromDirs(const crn::Path &image_directory, const crn::Path &xml_directory, const crn::Path &documentname, crn::Progress *prog=nullptr, bool throw_exceptions=true)
Creates a wrapper from two directories containing images and Altos with the same base names...
void SetBBox(const crn::Rect &r, bool erase_oob)
Sets the coordinates of the text block.
Alto::Layout::Page::Space AltoSpace
Definition: CRNAlto.h:141
void SetMaxCount(size_t maxcount, bool reset=true)
Sets the total number of steps.
Definition: CRNProgress.h:56
int GetHeight() const
Returns the height of the rectangle.
Definition: CRNRect.h:119
static const String & PageKey()
std::vector< Alto::Styles::Text > GetTextStyles()
Returns the text styles.
TextLine GetTextLine(const Id &id)
Gets a text line proxy.
Path GetBase() const
Returns the base of the filename.
Definition: CRNPath.cpp:235
String & ToLower()
Converts the string to lowercase.
Definition: CRNString.cpp:493
UImage NewImageFromFile(const Path &fname)
Loads an image from a file.
Definition: CRNImage.cpp:609
Space AddTopMargin(const crn::Rect &bbox)
Adds a top margin.
static const String & AltoPathKey()
Space AddLeftMargin(const crn::Rect &bbox)
Adds a left margin.
int GetWidth() const
Returns the width of the rectangle.
Definition: CRNRect.h:115
Word GetWord(const WordPath &p)
Gets a Word by path.
Space GetPrintSpace()
Gets the space proxy on the print space.
Page AddPage(int image_number, int w, int h, Option< AltoPage::Position > pos=Option< AltoPage::Position >())
Adds a page.
TextLine AddTextLineAfter(const Id &pred, const crn::Rect &bbox)
Adds a text line to the block.
const std::vector< Path > & GetFiles() const
Returns the list of files.
Definition: CRNIO.h:122
std::vector< Alto::Styles::Paragraph > GetParagraphStyles()
Returns the paragraph styles.
TextLine AddTextLine(const crn::Rect &bbox)
Adds a text line to the block.
static bool Access(const Path &name, int mode)
Checks rights on a file.
Definition: CRNIO.cpp:161
Data map class.
Definition: CRNMap.h:42
void ResizeTextBlock(const BlockPath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a text block and all its parents if needed.
TextBlock GetTextBlock(const BlockPath &p)
Gets a TextBlock by path.
A character string class.
Definition: CRNStringUTF8.h:49
void SetBBox(const crn::Rect &r)
Sets the coordinates of the word.
UObject Clone(const Object &obj)
Clones an object if possible.
Definition: CRNObject.cpp:35
void RemoveBlock(const Id &bid)
Removes a block.
std::vector< Id > GetSpaces() const
Returns the ids of the spaces in the page.
A class to store an optional value.
Definition: CRNOption.h:33
static const String & SpaceKey()
std::vector< Id > GetPages()
Gets the list of page ids.
int GetRight() const
Returns the rightmost coordinate.
Definition: CRNRect.h:103
Path GetExtension() const
Returns the extension.
Definition: CRNPath.cpp:252
void ResizeSpace(const SpacePath &p, const crn::Rect &r, bool erase_oob)
Changes the size of a space and all its parents if needed.
Alto::Layout::Page::Space::TextBlock::TextLine AltoTextLine
Definition: CRNAlto.h:153
Space GetSpace(const Id &spaceid)
Gets a space proxy.
const Rect & GetBBox() const
Gets the coordinates of the text line.
void RemoveTextLine(const Id &tid)
Removes a text line.
static const PagePath & NullPath()
static const SpacePath & NullPath()
Invalid argument error (e.g.: nullptr pointer)
Definition: CRNException.h:107
Description & GetDescription()
Gets the global description part of the Alto (may be null)
Definition: CRNAlto.h:91
std::vector< Alto::Styles::Text > GetTextStyles()
Returns the text styles.
An item was not found in a container.
Definition: CRNException.h:95
A rectangle class.
Definition: CRNRect.h:46