Skip to content

Commit

Permalink
Merge pull request #337 from OCR4all/feature/readingDirection
Browse files Browse the repository at this point in the history
Basic LTR / RTL support
  • Loading branch information
maxnth committed Jan 10, 2024
2 parents bc977b8 + 84d5077 commit af4cdfa
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 28 deletions.
31 changes: 26 additions & 5 deletions scss/viewer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -628,23 +628,44 @@ body{
position: absolute;
max-height: 40%;
overflow-y: auto;
padding: 0px;
margin: 0px;
padding: 0;
margin: 0;
.card{
margin: 0;
}
ul{
padding: 0px;
margin: 0px;
}
li{
padding: 3px 10px !important;
min-height: 0px;
min-height: 0;
}
.legendicon{
height: 10px;
width: 10px;
display: inline-block;
margin-right: 4px;
}
.contextTypeOption{
.select-directions{
ul{
padding: 0;
margin: 0;
}
li{
padding: 3px 10px !important;
min-height: 0;
border-bottom: 1px solid #e0e0e0;
}
}
.reading-direction-item{
cursor: pointer;
&:hover{
background-color: $color3;
color: $color2;
}
}
.contextTypeOption, .contextReadingDirectionOption {
cursor: pointer;
&:hover{
background-color: $color3;
Expand Down Expand Up @@ -846,7 +867,7 @@ label{
}
}

#kb-shortcut-modal-tabs{
.tabs{
overflow-x: hidden;
.indicator{
background-color: #0277bd;
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/de/uniwue/web/io/PageXMLReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public static PageAnnotations getPageAnnotations(File sourceFilename){
// Get Type
RegionType type = TypeConverter.stringToMainType(region.getType().getName());
RegionSubType subtype = null;
String readingDirection = null;

Double orientation = !(region instanceof CustomRegion || region instanceof NoiseRegion || type == RegionType.UnknownRegion) ?
PrimaLibHelper.getOrientation(region) : null;
Expand All @@ -107,6 +108,10 @@ public static PageAnnotations getPageAnnotations(File sourceFilename){

if (type != null && type.equals(RegionType.TextRegion)) {
TextRegion textRegion = (TextRegion) region;

// Get ReadingDirection
readingDirection = textRegion.getReadingDirection();

if(textRegion.getAttributes().get("type").getValue() != null && textRegion.getTextType() != null) {
subtype = TypeConverter.stringToSubType(textRegion.getTextType());
}
Expand Down Expand Up @@ -196,7 +201,7 @@ public static PageAnnotations getPageAnnotations(File sourceFilename){
String id = region.getId().toString();
if (!regionCoords.getPoints().isEmpty()) {
resRegions.put(id, new de.uniwue.web.model.Region(id, new PAGERegionType(type, subtype).toString(),
orientation, regionCoords, textLines, readingOrder));
orientation, regionCoords, textLines, readingDirection, readingOrder));
}
}
final int height = page.getLayout().getHeight();
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/de/uniwue/web/io/PageXMLWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ private static void mergeElementChangesIntoLayout(PageAnnotations result, PageLa
String elementId = element.getId();
String elementType = element.getType();
Polygon elementCoords = element.getCoords().toPrimaPolygon();
String readingDirection = element.getReadingDirection();

if(!isRegion(elementType, true))
continue;
Expand All @@ -240,6 +241,7 @@ private static void mergeElementChangesIntoLayout(PageAnnotations result, PageLa
if(isTextRegion(elementType, true) && isTextRegion(physicalRegionType, true)){
TextRegion textRegion = (TextRegion) physicalRegion;
textRegion.setCoords(elementCoords);
textRegion.setReadingDirection(readingDirection);
String physicalSubtype = textRegion.getTextType();

if(isTextRegionSubtype(elementType)){
Expand Down
30 changes: 27 additions & 3 deletions src/main/java/de/uniwue/web/model/Region.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,38 @@ public class Region extends Element{
protected final Double orientation;
@JsonProperty("textlines")
protected final Map<String,TextLine> textlines;
@JsonProperty("readingDirection")
protected final String readingDirection;
@JsonProperty("readingOrder")
protected List<String> readingOrder;

@JsonCreator
public Region(@JsonProperty("id") String id, @JsonProperty("type") String type,
@JsonProperty("orientation") Double orientation, @JsonProperty("coords") Polygon coords,
@JsonProperty("textlines") Map<String,TextLine> textlines, @JsonProperty("readingOrder") List<String> readingOrder) {
public Region(@JsonProperty("id") String id,
@JsonProperty("type") String type,
@JsonProperty("orientation") Double orientation,
@JsonProperty("coords") Polygon coords,
@JsonProperty("textlines") Map<String,TextLine> textlines,
@JsonProperty("readingDirection") String readingDirection,
@JsonProperty("readingOrder") List<String> readingOrder) {
super(id, coords);
this.type = type;
this.orientation = orientation;
this.textlines = textlines;
this.readingDirection = readingDirection;
this.readingOrder = readingOrder;
}

public Region(String id,
String type,
Double orientation,
Polygon coords,
Map<String,TextLine> textlines,
List<String> readingOrder) {
super(id, coords);
this.type = type;
this.orientation = orientation;
this.textlines = textlines;
this.readingDirection = null;
this.readingOrder = readingOrder;
}

Expand All @@ -49,6 +70,7 @@ public Region(String id, Polygon coords, String type) {
this.type = type;
this.orientation = null;
this.textlines = new HashMap<>();
this.readingDirection = null;
this.readingOrder = new ArrayList<>();
}

Expand Down Expand Up @@ -82,6 +104,8 @@ public Double getOrientation() {
return orientation;
}

public String getReadingDirection() { return readingDirection; }

/**
* Get the reading order of the contained textlines
* @return
Expand Down
53 changes: 43 additions & 10 deletions src/main/webapp/WEB-INF/tags/contextmenu.tag
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,48 @@
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<div id="contextmenu" class="card hide infocus">
<div class="select-regions">
<ul class="collection highlight">
<c:forEach var="type" items="${regionTypes}">
<c:if test="${!(type.key eq 'ignore')}">
<li class="collection-item contextTypeOption contextregionlegend" data-type="${type.key}">
<div class="legendicon ${type.key}"></div>${type.key}
</li>
</c:if>
</c:forEach>
</ul>
<div class="card">
<div class="card-tabs">
<ul class="tabs tabs-fixed-width" id="contextMenuTab">
<li class="tab"><a href="#types">Types</a></li>
<li class="tab"><a href="#directions">Reading Direction</a></li>
</ul>
</div>
<div class="card-content">
<div id="types">
<div class="select-regions">
<ul class="collection highlight">
<c:forEach var="type" items="${regionTypes}">
<c:if test="${!(type.key eq 'ignore')}">
<li class="collection-item contextTypeOption contextregionlegend" data-type="${type.key}">
<div class="legendicon ${type.key}"></div>${type.key}
</li>
</c:if>
</c:forEach>
</ul>
</div>
</div>
<div id="directions">
<div class="select-directions">
<ul class="collection highlight">
<li class="reading-direction-item contextReadingDirectionOption" data-direction="unset">
Unset
</li>
<li class="reading-direction-item contextReadingDirectionOption" data-direction="left-to-right">
Left To Right
</li>
<li class="reading-direction-item contextReadingDirectionOption" data-direction="right-to-left">
Right To Left
</li>
<li class="reading-direction-item contextReadingDirectionOption" data-direction="top-to-bottom">
Top To Bottom
</li>
<li class="reading-direction-item contextReadingDirectionOption" data-direction="bottom-to-top">
Bottom To Top
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion src/main/webapp/resources/css/viewer.css

Large diffs are not rendered by default.

46 changes: 44 additions & 2 deletions src/main/webapp/resources/js/viewer/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,48 @@ function ActionChangeTypeSegment(id, newType, viewer, textViewer, controller, se
}
}

function ActionChangeReadingDirection(id, newDirection, viewer, textViewer, controller, selector, segmentation, page) {
let _isExecuted = false;
let _segment = segmentation[page].segments[id];
const _oldDirection = _segment.readingDirection;

this.execute = function () {
if (!_isExecuted) {
_isExecuted = true;
if(newDirection === "unset"){
_segment.readingDirection = null
}else{
_segment.readingDirection = newDirection
}

if(_segment.textlines){
let textlines = Object.entries(_segment.textlines).map(([_,t]) => t);
for(let textline of textlines){
textViewer.updateTextLineReadingDirection(textline, newDirection)
}
}

console.log('Do - Change Reading Direction: {id:"' + id + '",[..],readingDirection:"' + newDirection + '"}');
}
}
this.undo = function () {
if (_isExecuted) {
_isExecuted = false;
_segment.readingDirection = _oldDirection

if(_segment.textlines){
let textlines = Object.entries(_segment.textlines).map(([_,t]) => t);
for(let textline of textlines){
textViewer.updateTextLineReadingDirection(textline, _oldDirection)
}
}

console.log('Undo - Change Reading Direction: {id:"' + id + '",[..],readingDirection:"' + _oldDirection + '"}');
}
}

}

function ActionAddRegionArea(id, points, type, editor, settings) {
let _isExecuted = false;
const _area = { id: id, coords: {points: points, isRelative: true}, type: type };
Expand Down Expand Up @@ -408,7 +450,7 @@ function ActionAddTextLine(id, segmentID, points, text, editor, textViewer, segm
segmentation[page].segments[segmentID].textlines[id] = JSON.parse(JSON.stringify(_textLine));
}
editor.addTextLine(_textLine);
textViewer.addTextline(_textLine);
textViewer.addTextline(_textLine, segmentation[page].segments[segmentID].readingDirection);
controller.textlineRegister[_textLine.id] = segmentID;
console.log('Do - Add TextLine Polygon: {id:"' + _textLine.id + '",[..],text:"' + text + '"}');
}
Expand Down Expand Up @@ -461,7 +503,7 @@ function ActionRemoveTextLine(textline, editor, textViewer, segmentation, page,

segmentation[page].segments[_segmentID].textlines = JSON.parse(JSON.stringify(_oldTextLines));
editor.addTextLine(JSON.parse(JSON.stringify(_oldTextLine)));
textViewer.addTextline(JSON.parse(JSON.stringify(_oldTextLine)));
textViewer.addTextline(JSON.parse(JSON.stringify(_oldTextLine)), segmentation[page].segments[_segmentID].readingDirection);
if(removeROAction) removeROAction.undo();

controller.textlineRegister[textline.id] = _segmentID;
Expand Down
32 changes: 28 additions & 4 deletions src/main/webapp/resources/js/viewer/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ function Controller(bookID, accessible_modes, canvasID, regionColors, colors, gl
textLine.type = "TextLine";
}
_editor.addTextLine(textLine);
_textViewer.addTextline(textLine);
_textViewer.addTextline(textLine, pageSegment.readingDirection);
if(textLine["baseline"]){
_editor.addBaseline(textLine, textLine["baseline"]);
}
Expand Down Expand Up @@ -1529,6 +1529,30 @@ function Controller(bookID, accessible_modes, canvasID, regionColors, colors, gl
}
}

this.changeReadingDirection = function(id, direction) {
const polygonType = this.getIDType(id);
if(polygonType === ElementType.SEGMENT && this.isIDTextRegion(id)){
const actionChangeReadingDirection = new ActionChangeReadingDirection(id, direction, _editor, _textViewer, this, _selector, _segmentation, _currentPage, false);
_actionController.addAndExecuteAction(actionChangeReadingDirection, _currentPage);
}
}

this.changeReadingDirectionSelected = function (direction){
const selected = _selector.getSelectedSegments();
const selectType = _selector.getSelectedPolygonType();
const selectedlength = selected.length;
if (selectType === ElementType.SEGMENT){
if (selectedlength || selectedlength > 0) {
const actions = [];
for (let i = 0; i < selectedlength; i++) {
if(this.isIDTextRegion(selected[i])) actions.push(new ActionChangeReadingDirection(selected[i], direction, _editor, _textViewer, this, _selector, _segmentation, _currentPage, false));
}
const multiChange = new ActionMultiple(actions);
_actionController.addAndExecuteAction(multiChange, _currentPage);
}
}
}

this.openRegionSettings = function (regionType) {
if(regionType){
let region = _settings.regions[regionType];
Expand Down Expand Up @@ -1835,7 +1859,7 @@ function Controller(bookID, accessible_modes, canvasID, regionColors, colors, gl
if(selected && this.getIDType(selected[0]) === ElementType.TEXTLINE){
const id = selected[0];
const parentID = this.textlineRegister[id];
_gui.openTextLineContent(_segmentation[_currentPage].segments[parentID].textlines[id]);
_gui.openTextLineContent(_segmentation[_currentPage].segments[parentID].textlines[id], _segmentation[_currentPage].segments[parentID].readingDirection);
}
_gui.updateZoom();
}
Expand Down Expand Up @@ -2039,10 +2063,10 @@ function Controller(bookID, accessible_modes, canvasID, regionColors, colors, gl
if(!textline.minArea){
_communicator.minAreaRect(textline).done((minArea) => {
textline.minArea = minArea;
_gui.openTextLineContent(textline);
_gui.openTextLineContent(textline, _segmentation[_currentPage].segments[this.textlineRegister[id]].readingDirection);
});
} else {
_gui.openTextLineContent(textline);
_gui.openTextLineContent(textline, _segmentation[_currentPage].segments[this.textlineRegister[id]].readingDirection);
}
}
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/webapp/resources/js/viewer/gui.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ function GUI(canvas, viewer, colors, accessible_modes) {
this.openContextMenu = function (doSelected, id) {
const $contextmenu = $("#contextmenu");
$contextmenu.removeClass("hide");
const $contextMenuTab = $("#contextMenuTab")
$contextMenuTab.tabs("select_tab", "types");
const fitsInWindow = _mouse.y + $contextmenu.height() < $(window).height();

if (fitsInWindow) {
Expand Down Expand Up @@ -306,11 +308,24 @@ function GUI(canvas, viewer, colors, accessible_modes) {
/**
* Open the textline content, ready to edit
*/
this.openTextLineContent = function (textline) {
this.openTextLineContent = function (textline, readingDirection) {
console.log(readingDirection)
this.hideTextline(false);
const $textlinecontent = $("#textline-content");
$textlinecontent.removeClass("hide");

switch(readingDirection){
case "right-to-left":
$textlinecontent.attr("dir", "rtl");
break;
case "left-to-right":
$textlinecontent.attr("dir", "ltr");
break;
default:
$textlinecontent.removeAttr("dir")
break;
}

if(!this.tempTextline || this.tempTextline.id !== textline.id){
this.tempTextline = textline ? textline : this.tempTextline;
this.updateTextLine(textline.id);
Expand Down
Loading

0 comments on commit af4cdfa

Please sign in to comment.