├── .gitignore ├── LICENSE ├── README.md ├── out ├── file.pdf ├── file2.pdf └── nested │ ├── file.pdf │ └── nested2 │ └── file.pdf ├── pom.xml └── src ├── main ├── java │ ├── hse │ │ └── btf │ │ │ └── pdfeditor │ │ │ ├── FormulaPaneController.java │ │ │ ├── FormulaWindowController.java │ │ │ ├── HelloSceneController.java │ │ │ ├── ImagePaneController.java │ │ │ ├── MouseController.java │ │ │ ├── PdfEditorApplication.java │ │ │ ├── PdfWorkWindowController.java │ │ │ ├── TablePaneController.java │ │ │ ├── TextPaneController.java │ │ │ ├── entity │ │ │ ├── PDFDocument.java │ │ │ ├── PDFFormula.java │ │ │ ├── PDFImage.java │ │ │ ├── PDFItem.java │ │ │ ├── PDFTable.java │ │ │ └── PDFText.java │ │ │ ├── models │ │ │ ├── entities │ │ │ │ ├── FormulaEntity.java │ │ │ │ ├── FormulaEntityInterface.java │ │ │ │ ├── ImageEntity.java │ │ │ │ ├── ImageEntityInterface.java │ │ │ │ ├── PaperEntity.java │ │ │ │ ├── TextEntity.java │ │ │ │ └── TextEntityInterface.java │ │ │ └── utility │ │ │ │ ├── PaperContextMenu.java │ │ │ │ └── ProjectNameBox.java │ │ │ ├── service │ │ │ └── Converter.java │ │ │ ├── storages │ │ │ ├── EntitiesStorage.java │ │ │ └── ProjectDataStorage.java │ │ │ └── utils │ │ │ ├── CreatorConstants.java │ │ │ ├── FileUtil.java │ │ │ ├── FontUtil.java │ │ │ └── PDFEditorConstants.java │ └── module-info.java ├── kotlin │ └── hse │ │ └── btf │ │ └── pdfeditor │ │ ├── EntityToItemConverter.kt │ │ ├── Holder.kt │ │ ├── datasaving │ │ └── test.json │ │ ├── models │ │ ├── FormulaItem.kt │ │ ├── ImageItem.kt │ │ ├── Item.kt │ │ ├── TableItem.kt │ │ └── TextItem.kt │ │ └── serializers │ │ ├── SavingClass.kt │ │ └── Serializers.kt └── resources │ ├── hello-scene.properties │ ├── hse │ └── btf │ │ └── pdfeditor │ │ ├── arial.ttf │ │ ├── formula-pane.fxml │ │ ├── formula-window.fxml │ │ ├── free_sans.ttf │ │ ├── hello-view.fxml │ │ ├── image-pane.fxml │ │ ├── main.css │ │ ├── table-pane.fxml │ │ ├── text-pane.fxml │ │ ├── times_new_roman.ttf │ │ └── work-window.fxml │ └── users.projects │ └── projectNamesList.json └── test ├── java └── hse │ └── btf │ └── pdfeditor │ ├── ExportTest.java │ └── PDFDocumentTest.java └── resources └── images └── java_logo.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | target 4 | /out/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alexander Buyantuev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pdf-editor 2 | -------------------------------------------------------------------------------- /out/file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pdf-Creator/pdf-editor/ae30ad8db46ab7c922219e100ef6f5c7ebf551b8/out/file.pdf -------------------------------------------------------------------------------- /out/file2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pdf-Creator/pdf-editor/ae30ad8db46ab7c922219e100ef6f5c7ebf551b8/out/file2.pdf -------------------------------------------------------------------------------- /out/nested/file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pdf-Creator/pdf-editor/ae30ad8db46ab7c922219e100ef6f5c7ebf551b8/out/nested/file.pdf -------------------------------------------------------------------------------- /out/nested/nested2/file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pdf-Creator/pdf-editor/ae30ad8db46ab7c922219e100ef6f5c7ebf551b8/out/nested/nested2/file.pdf -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | hse.btf 8 | pdf-editor 9 | 1.0-SNAPSHOT 10 | pdf-editor 11 | 12 | 13 | 14 | nexus-gluonhq-com-repo 15 | gluon repo 16 | https://nexus.gluonhq.com/nexus/content/repositories/releases/ 17 | 18 | 19 | itext 20 | iText Repository - releases 21 | https://repo.itextsupport.com/releases 22 | 23 | 24 | 25 | 26 | UTF-8 27 | 5.8.1 28 | 1.5.32 29 | 1.3.0-RC 30 | 31 | 32 | 33 | 34 | org.openjfx 35 | javafx-base 36 | 17.0.1 37 | 38 | 39 | org.openjfx 40 | javafx-controls 41 | 17.0.1 42 | 43 | 44 | org.openjfx 45 | javafx-fxml 46 | 17.0.1 47 | 48 | 49 | org.openjfx 50 | javafx-web 51 | 17.0.1 52 | 53 | 54 | org.openjfx 55 | javafx-swing 56 | 17.0.1 57 | 58 | 59 | org.jfree 60 | fxgraphics2d 61 | 1.8 62 | 63 | 64 | org.controlsfx 65 | controlsfx 66 | 11.1.0 67 | 68 | 69 | com.dlsc.formsfx 70 | formsfx-core 71 | 11.3.2 72 | 73 | 74 | org.openjfx 75 | * 76 | 77 | 78 | 79 | 80 | net.synedra 81 | validatorfx 82 | 0.1.13 83 | 84 | 85 | org.openjfx 86 | * 87 | 88 | 89 | 90 | 91 | org.kordamp.ikonli 92 | ikonli-javafx 93 | 12.2.0 94 | 95 | 96 | org.kordamp.bootstrapfx 97 | bootstrapfx-core 98 | 0.4.0 99 | 100 | 101 | org.scilab.forge 102 | jlatexmath 103 | 1.0.7 104 | 105 | 106 | 107 | com.proudapes 108 | jlatexmathfx 109 | 0.3.2 110 | 111 | 112 | com.itextpdf 113 | kernel 114 | 7.2.1 115 | 116 | 117 | com.itextpdf 118 | io 119 | 7.2.1 120 | 121 | 122 | com.itextpdf 123 | layout 124 | 7.2.1 125 | 126 | 127 | com.itextpdf 128 | forms 129 | 7.2.1 130 | 131 | 132 | com.itextpdf 133 | pdfa 134 | 7.2.1 135 | 136 | 137 | com.itextpdf 138 | sign 139 | 7.2.1 140 | 141 | 142 | com.itextpdf 143 | barcodes 144 | 7.2.1 145 | 146 | 147 | com.itextpdf 148 | font-asian 149 | 7.2.1 150 | 151 | 152 | com.itextpdf 153 | hyph 154 | 7.2.1 155 | 156 | 157 | org.slf4j 158 | slf4j-api 159 | 2.0.0-alpha7 160 | 161 | 162 | org.slf4j 163 | slf4j-simple 164 | 2.0.0-alpha7 165 | 166 | 167 | eu.hansolo 168 | tilesfx 169 | 11.48 170 | 171 | 172 | org.openjfx 173 | * 174 | 175 | 176 | 177 | 178 | org.junit.jupiter 179 | junit-jupiter-api 180 | ${junit.version} 181 | test 182 | 183 | 184 | com.gluonhq 185 | charm-glisten 186 | 6.0.2 187 | 188 | 189 | org.junit.jupiter 190 | junit-jupiter-engine 191 | ${junit.version} 192 | test 193 | 194 | 195 | org.jetbrains.kotlin 196 | kotlin-stdlib 197 | ${kotlin.version} 198 | 199 | 200 | no.tornado 201 | tornadofx 202 | 1.7.20 203 | 204 | 205 | org.jetbrains.kotlin 206 | kotlin-reflect 207 | ${kotlin.version} 208 | 209 | 210 | org.jetbrains.kotlinx 211 | kotlinx-serialization-json-jvm 212 | ${serialization.version} 213 | 214 | 215 | commons-io 216 | commons-io 217 | 2.11.0 218 | 219 | 220 | 221 | 222 | 223 | 224 | src/main/java 225 | ${project.build.outputDirectory} 226 | 227 | **/*.ttf 228 | 229 | 230 | 231 | 232 | src/main/resources 233 | 234 | 235 | 236 | 237 | org.jetbrains.kotlin 238 | kotlin-maven-plugin 239 | ${kotlin.version} 240 | 241 | 242 | compile 243 | 244 | compile 245 | 246 | 247 | 1.8 248 | 249 | ${project.basedir}/src/main/kotlin 250 | ${project.basedir}/src/main/java 251 | 252 | 253 | 254 | 255 | test-compile 256 | test-compile 257 | 258 | 259 | ${project.basedir}/src/test/kotlin 260 | ${project.basedir}/src/test/java 261 | 262 | 263 | 264 | 265 | 266 | 267 | kotlinx-serialization 268 | 269 | 270 | 271 | 272 | org.jetbrains.kotlin 273 | kotlin-maven-serialization 274 | ${kotlin.version} 275 | 276 | 277 | 278 | 279 | org.apache.maven.plugins 280 | maven-compiler-plugin 281 | 3.5.1 282 | 283 | 284 | 285 | default-compile 286 | none 287 | 288 | 289 | 290 | default-testCompile 291 | none 292 | 293 | 294 | java-compile 295 | compile 296 | 297 | compile 298 | 299 | 300 | 301 | java-test-compile 302 | test-compile 303 | 304 | testCompile 305 | 306 | 307 | 308 | 309 | 11 310 | 11 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | org.openjfx 324 | javafx-maven-plugin 325 | 0.0.8 326 | 327 | 328 | 329 | default-cli 330 | 331 | hse.btf.pdfeditor/hse.btf.pdfeditor.PdfEditorApplication 332 | app 333 | app 334 | app 335 | true 336 | true 337 | true 338 | 339 | 340 | 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/FormulaPaneController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import javafx.fxml.FXML; 4 | import javafx.fxml.FXMLLoader; 5 | import javafx.fxml.Initializable; 6 | import javafx.scene.Parent; 7 | import javafx.scene.Scene; 8 | import javafx.scene.control.Button; 9 | import javafx.stage.Stage; 10 | 11 | import java.io.IOException; 12 | import java.net.URL; 13 | import java.util.ResourceBundle; 14 | 15 | public class FormulaPaneController implements Initializable { 16 | 17 | @Override 18 | public void initialize(URL url, ResourceBundle resourceBundle) { 19 | setFormulaActions(); 20 | } 21 | 22 | synchronized private void setFormulaActions() { 23 | newFormulaButton.setOnMouseClicked(ev -> { 24 | Stage stage = new Stage(); 25 | FXMLLoader fxmlLoader = new FXMLLoader(PdfEditorApplication.class.getResource("formula-window.fxml")); 26 | 27 | Parent root = null; 28 | try { 29 | root = fxmlLoader.load(); 30 | } catch (IOException e) { 31 | e.printStackTrace(); 32 | return; 33 | } 34 | Scene scene = new Scene(root); 35 | stage.setScene(scene); 36 | stage.show(); 37 | }); 38 | } 39 | 40 | @FXML 41 | public Button newFormulaButton; 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/FormulaWindowController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.models.entities.FormulaEntity; 4 | import javafx.fxml.Initializable; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.TextArea; 7 | import javafx.stage.Stage; 8 | 9 | import java.net.URL; 10 | import java.util.ResourceBundle; 11 | 12 | import static hse.btf.pdfeditor.PdfWorkWindowController.papers; 13 | import static hse.btf.pdfeditor.storages.EntitiesStorage.entitiesList; 14 | 15 | public class FormulaWindowController implements Initializable { 16 | public TextArea formulaText; 17 | public Button createFormula; 18 | public Button closeFormula; 19 | 20 | @Override 21 | public void initialize(URL url, ResourceBundle resourceBundle) { 22 | createFormula.setOnAction(ev -> { 23 | FormulaEntity entity = new FormulaEntity(formulaText.getText()); 24 | entitiesList.add(entity); 25 | entity.setBottomPadding(0); 26 | entity.setTopPadding(0); 27 | entity.setLeftPadding(0); 28 | entity.setRightPadding(0); 29 | papers.get(0).getChildren().add(entity.createFxmlObject()); 30 | papers.get(0).getStylesheets().add(PdfEditorApplication.class.getResource("main.css").toExternalForm()); 31 | Stage stage = (Stage)formulaText.getScene().getWindow(); 32 | stage.close(); 33 | }); 34 | 35 | closeFormula.setOnAction(ev -> { 36 | Stage stage = (Stage)formulaText.getScene().getWindow(); 37 | stage.close(); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/HelloSceneController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.models.utility.ProjectNameBox; 4 | import javafx.event.ActionEvent; 5 | import javafx.fxml.FXML; 6 | import javafx.fxml.FXMLLoader; 7 | import javafx.fxml.Initializable; 8 | import javafx.scene.Parent; 9 | import javafx.scene.Scene; 10 | import javafx.scene.control.Button; 11 | import javafx.scene.control.ListView; 12 | import javafx.scene.control.TextField; 13 | import javafx.stage.Stage; 14 | import javafx.stage.StageStyle; 15 | 16 | import java.io.IOException; 17 | import java.net.URL; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.ResourceBundle; 21 | 22 | import static hse.btf.pdfeditor.serializers.SavingClassKt.deserializeProjectsNames; 23 | import static hse.btf.pdfeditor.serializers.SavingClassKt.readFromFile; 24 | import static hse.btf.pdfeditor.serializers.SavingClassKt.serializeProjectsNames; 25 | 26 | public class HelloSceneController implements Initializable { 27 | @FXML 28 | private TextField projectNameField; 29 | 30 | @FXML 31 | private Button createButton; 32 | 33 | @FXML 34 | private Button openButton; 35 | 36 | @FXML 37 | private ListView projectNamesListView; 38 | 39 | private final List projectNamesList = new ArrayList<>(); 40 | private String currentProjectName = ""; 41 | private final ResourceBundle resourceBundle = ResourceBundle.getBundle("hello-scene"); 42 | 43 | public static boolean usedByOpenButton = false; 44 | 45 | @Override 46 | public void initialize(URL url, ResourceBundle resourceBundle) { 47 | deserializeProjectsNames(projectNamesList); 48 | 49 | projectNamesListView.getItems().addAll(projectNamesList); 50 | projectNamesListView.getSelectionModel().selectedItemProperty().addListener((observableValue, s, t1) -> { 51 | currentProjectName = projectNamesListView.getSelectionModel().getSelectedItem(); 52 | projectNameField.setText(currentProjectName); 53 | }); 54 | } 55 | 56 | @FXML 57 | public void createProjectButton(ActionEvent event) throws IOException { 58 | // check whether the project with that name is already created 59 | if (projectNamesList.contains(projectNameField.getText())) { 60 | ProjectNameBox.display(resourceBundle.getString("label.project-name.non-new"), resourceBundle.getString("message.project-name.non-new")); 61 | return; 62 | } 63 | 64 | if (projectNameField.getText().isEmpty()) { 65 | ProjectNameBox.display(resourceBundle.getString("label.project-name.empty"), resourceBundle.getString("message.project-name.empty")); 66 | return; 67 | } 68 | 69 | // add new project name to the name list 70 | projectNamesList.add(projectNameField.getText()); 71 | serializeProjectsNames(projectNamesList); 72 | 73 | changeScene(); 74 | } 75 | 76 | @FXML 77 | public void openProjectButton(ActionEvent event) throws IOException { 78 | // check whether project with that name doesn't exist 79 | if (!projectNamesList.contains(projectNameField.getText())) { 80 | ProjectNameBox.display(resourceBundle.getString("label.project-name.non-existing"), resourceBundle.getString("message.project-name.non-existing")); 81 | return; 82 | } 83 | 84 | // выгрузить состояние всей прошлой сцены 85 | System.out.println(projectNameField.getText()); 86 | usedByOpenButton = readFromFile(projectNameField.getText()); 87 | 88 | changeScene(); 89 | } 90 | 91 | private void changeScene() throws IOException { 92 | // closing previous 93 | Stage thisStage = (Stage) createButton.getScene().getWindow(); 94 | thisStage.close(); 95 | 96 | FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("work-window.fxml")); 97 | 98 | Stage stage = new Stage(); 99 | Parent root = fxmlLoader.load(); 100 | Scene scene = new Scene(root); 101 | 102 | stage.setMaximized(false); 103 | stage.initStyle(StageStyle.DECORATED); 104 | 105 | stage.setTitle("Working Window"); 106 | stage.setScene(scene); 107 | stage.show(); 108 | } 109 | } -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/ImagePaneController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.utils.FileUtil; 4 | import javafx.fxml.FXML; 5 | import javafx.fxml.Initializable; 6 | import javafx.scene.control.Button; 7 | 8 | import java.net.URL; 9 | import java.util.ResourceBundle; 10 | 11 | public class ImagePaneController implements Initializable { 12 | @Override 13 | public void initialize(URL url, ResourceBundle resourceBundle) { 14 | setImageActions(); 15 | } 16 | 17 | private void setImageActions() { 18 | // добавить рамки + посмотреть в видео, что можно делать с картинкой 19 | FileUtil.loadImage(newImageButton); 20 | } 21 | 22 | @FXML 23 | public Button newImageButton; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/MouseController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | public class MouseController { 4 | public static class Position { 5 | static public double x; 6 | static public double y; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/PdfEditorApplication.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.utils.FontUtil; 4 | import javafx.application.Application; 5 | import javafx.fxml.FXMLLoader; 6 | import javafx.scene.Parent; 7 | import javafx.scene.Scene; 8 | import javafx.stage.Stage; 9 | 10 | import java.io.IOException; 11 | 12 | public class PdfEditorApplication extends Application { 13 | @Override 14 | public void start(Stage stage) throws IOException { 15 | FXMLLoader fxmlLoader = new FXMLLoader(PdfEditorApplication.class.getResource("hello-view.fxml")); 16 | FontUtil.init(); 17 | 18 | Parent root = fxmlLoader.load(); 19 | Scene scene = new Scene(root); 20 | 21 | stage.setTitle("Hello!"); 22 | stage.setScene(scene); 23 | stage.show(); 24 | } 25 | 26 | public static void main(String[] args) { 27 | launch(); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/PdfWorkWindowController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.models.utility.PaperContextMenu; 4 | import hse.btf.pdfeditor.models.entities.PaperEntity; 5 | import hse.btf.pdfeditor.utils.FileUtil; 6 | import javafx.fxml.FXML; 7 | import javafx.fxml.Initializable; 8 | import javafx.scene.control.Button; 9 | import javafx.scene.control.Label; 10 | import javafx.scene.input.MouseButton; 11 | import javafx.scene.input.MouseEvent; 12 | import javafx.scene.layout.AnchorPane; 13 | 14 | import java.net.URL; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.ResourceBundle; 18 | 19 | import static hse.btf.pdfeditor.HelloSceneController.usedByOpenButton; 20 | 21 | public class PdfWorkWindowController implements Initializable { 22 | 23 | @Override 24 | public void initialize(URL url, ResourceBundle resourceBundle) { 25 | papers = new ArrayList<>(); 26 | papers.add(paper); 27 | 28 | setPaperSettings(); 29 | setLeftPanelsActions(); 30 | 31 | // TODO 32 | if (usedByOpenButton) { 33 | // создать entities из списка item'ов 34 | // отрисовать объекты на бумаге 35 | } 36 | 37 | FileUtil.savePDFDocument(createPdfButton); 38 | } 39 | 40 | private void setLeftPanelsActions() { 41 | leftPanel.setPrefWidth(20); 42 | 43 | textPane.setPrefWidth(0); 44 | tablePane.setPrefWidth(0); 45 | imagePane.setPrefWidth(0); 46 | formulaPane.setPrefWidth(0); 47 | 48 | addLeftButtonClicker(leftTextPaneButton, textPane); 49 | addLeftButtonClicker(leftTablePaneButton, tablePane); 50 | addLeftButtonClicker(leftImagePaneButton, imagePane); 51 | addLeftButtonClicker(leftFormulaPaneButton, formulaPane); 52 | } 53 | 54 | private void setPaperSettings() { 55 | paperSize = 100; 56 | originalPaperWidth = paper.getPrefWidth(); 57 | originalPaperHeight = paper.getPrefHeight(); 58 | 59 | PaperContextMenu contextMenu = new PaperContextMenu(); 60 | paper.setOnMouseClicked(ev -> { 61 | if (ev.getButton() == MouseButton.SECONDARY) { 62 | contextMenu.show(paper, ev.getScreenX(), ev.getScreenY()); 63 | } else { 64 | contextMenu.hide(); 65 | } 66 | }); 67 | } 68 | 69 | /* 70 | TODO : ultimate way to add handlers 71 | private void initFormulaPane() { 72 | formulaPane.getChildren().forEach(node -> { 73 | node.setOnMouseClicked(); 74 | }); 75 | } 76 | */ 77 | 78 | private void addLeftButtonClicker(Button button, AnchorPane panel) { 79 | button.setOnMouseClicked(ev -> { 80 | if (selectedPane == null) { 81 | selectedPane = panel; 82 | leftPanel.setPrefWidth(164); 83 | selectedPane.setPrefWidth(144); 84 | } else { 85 | selectedPane.setPrefWidth(0); 86 | 87 | if (selectedPane == panel) { 88 | selectedPane = null; 89 | leftPanel.setPrefWidth(20); 90 | } else { 91 | selectedPane = panel; 92 | selectedPane.setPrefWidth(144); 93 | } 94 | } 95 | }); 96 | } 97 | 98 | @FXML 99 | public void paperSizeDecrease(MouseEvent event) { 100 | if (paperSize != 25) { 101 | paperSize -= 25; 102 | sizeLabel.setText(paperSize + "%"); 103 | resizePaper(); 104 | } 105 | } 106 | 107 | @FXML 108 | public void paperSizeIncrease(MouseEvent event) { 109 | if (paperSize != 100) { 110 | paperSize += 25; 111 | sizeLabel.setText(paperSize + "%"); 112 | resizePaper(); 113 | } 114 | } 115 | 116 | private void resizePaper() { 117 | paper.setPrefWidth(originalPaperWidth / 100 * paperSize); 118 | paper.setPrefHeight(originalPaperHeight / 100 * paperSize); 119 | } 120 | 121 | static public PaperEntity target = null; 122 | /** 123 | * left panel 124 | **/ 125 | @FXML 126 | public AnchorPane leftPanel; 127 | 128 | /** 129 | * choosing pane buttons 130 | **/ 131 | @FXML 132 | public Button leftTextPaneButton; 133 | 134 | @FXML 135 | public Button leftTablePaneButton; 136 | 137 | @FXML 138 | public Button leftImagePaneButton; 139 | 140 | @FXML 141 | public Button leftFormulaPaneButton; 142 | 143 | /** 144 | * panes 145 | **/ 146 | @FXML 147 | private AnchorPane selectedPane = null; 148 | 149 | public static List papers; 150 | 151 | @FXML 152 | public AnchorPane textPane; 153 | 154 | @FXML 155 | public AnchorPane tablePane; 156 | 157 | @FXML 158 | public AnchorPane imagePane; 159 | 160 | @FXML 161 | public AnchorPane formulaPane; 162 | 163 | /** 164 | * paper 165 | **/ 166 | @FXML 167 | private AnchorPane paperBackground; 168 | 169 | @FXML 170 | private AnchorPane paper; 171 | 172 | @FXML 173 | private Button buttonPaperSizeIncrease; 174 | 175 | @FXML 176 | private Button buttonPaperSizeDecrease; 177 | 178 | @FXML 179 | private Label sizeLabel; 180 | 181 | @FXML 182 | private Button createPdfButton; 183 | 184 | private final EntityToItemConverter pdfEditorView = new EntityToItemConverter(); 185 | 186 | private double originalPaperWidth; 187 | 188 | private double originalPaperHeight; 189 | 190 | private Integer paperSize; 191 | } -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/TablePaneController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import javafx.fxml.FXML; 4 | import javafx.fxml.Initializable; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.Slider; 7 | import javafx.scene.control.TextField; 8 | 9 | import java.net.URL; 10 | import java.util.ResourceBundle; 11 | 12 | public class TablePaneController implements Initializable { 13 | @Override 14 | public void initialize(URL url, ResourceBundle resourceBundle) { 15 | setTableActions(); 16 | } 17 | 18 | private void setTableActions() { 19 | newTableButton.setOnMouseClicked(ev -> { 20 | } 21 | //entitiesHolder.getObservableItemsList().add(new TableItem()) 22 | ); 23 | 24 | // columns 25 | connectSliderWithTextField(tableColsSlider, tableColsField); 26 | 27 | tableColsSlider.setMin(1.0); 28 | tableColsSlider.setMax(20.0); 29 | tableColsField.setText("2.0"); 30 | 31 | // rows 32 | connectSliderWithTextField(tableRowsSlider, tableRowsField); 33 | 34 | tableRowsSlider.setMin(1.0); 35 | tableRowsSlider.setMax(20.0); 36 | tableRowsField.setText("2.0"); 37 | } 38 | 39 | private void connectSliderWithTextField(Slider slider, TextField field) { 40 | slider.valueProperty().addListener((changed, oldValue, newValue) -> field.setText(newValue.toString())); 41 | field.textProperty().addListener((changed, oldValue, newValue) -> slider.setValue(Double.parseDouble(newValue))); 42 | } 43 | 44 | @FXML 45 | public Button newTableButton; 46 | 47 | @FXML 48 | public TextField tableColsField; 49 | public Slider tableColsSlider; 50 | public TextField tableRowsField; 51 | public Slider tableRowsSlider; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/TextPaneController.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor; 2 | 3 | import hse.btf.pdfeditor.models.entities.TextEntity; 4 | import hse.btf.pdfeditor.utils.CreatorConstants; 5 | import hse.btf.pdfeditor.utils.FontUtil; 6 | import javafx.collections.FXCollections; 7 | import javafx.collections.ObservableList; 8 | import javafx.fxml.FXML; 9 | import javafx.fxml.Initializable; 10 | import javafx.scene.control.Button; 11 | import javafx.scene.control.ChoiceBox; 12 | import javafx.scene.control.ColorPicker; 13 | import javafx.scene.control.Slider; 14 | import javafx.scene.control.TextField; 15 | import javafx.scene.control.ToggleButton; 16 | import javafx.scene.control.ToggleGroup; 17 | import javafx.scene.control.Tooltip; 18 | import javafx.scene.input.MouseEvent; 19 | import javafx.scene.layout.AnchorPane; 20 | import javafx.scene.paint.Color; 21 | 22 | import java.net.URL; 23 | import java.util.List; 24 | import java.util.Objects; 25 | import java.util.ResourceBundle; 26 | 27 | import static hse.btf.pdfeditor.PdfWorkWindowController.papers; 28 | import static hse.btf.pdfeditor.PdfWorkWindowController.target; 29 | import static hse.btf.pdfeditor.storages.EntitiesStorage.entitiesList; 30 | 31 | public class TextPaneController implements Initializable { 32 | 33 | @Override 34 | public void initialize(URL url, ResourceBundle resourceBundle) { 35 | textParameters.setVisible(false); 36 | newTextButton.setOnMouseClicked(ev -> { 37 | textParameters.setVisible(true); 38 | TextEntity entity = new TextEntity(); 39 | entitiesList.add(entity); 40 | entity.setBottomPadding(8.0); 41 | entity.setTopPadding(8.0); 42 | entity.setLeftPadding(8.0); 43 | entity.setRightPadding(8.0); 44 | entity.setWidth(150); 45 | entity.setHeight(90); 46 | papers.get(0).getChildren().add(entity.createFxmlObject()); 47 | papers.get(0).getStylesheets().add(Objects.requireNonNull(PdfEditorApplication.class.getResource("main.css")).toExternalForm()); 48 | }); 49 | 50 | textShriftChoiceBox.getItems().addAll(List.of("Free Sans", "Arial", "Times New Roman")); 51 | textShriftChoiceBox.setValue("Free Sans"); 52 | textShriftChoiceBox.setOnAction(ev -> { 53 | TextEntity entity = (TextEntity)target; 54 | String fontName = textShriftChoiceBox.getValue(); 55 | entity.setFont(fontName); 56 | }); 57 | } 58 | 59 | @FXML 60 | public AnchorPane textParameters; 61 | 62 | @FXML 63 | public Button newTextButton; 64 | 65 | @FXML 66 | public ChoiceBox textShriftChoiceBox; 67 | 68 | @FXML 69 | public TextField textSizeField; 70 | public Slider textSizeSlider; 71 | 72 | @FXML 73 | public ToggleButton alignmentLeftButton; 74 | public ToggleButton alignmentCenterButton; 75 | public ToggleButton alignmentRightButton; 76 | public ToggleButton alignmentWidthButton; 77 | 78 | private final ToggleGroup alignmentToggleGroup = new ToggleGroup(); 79 | 80 | @FXML 81 | public ToggleButton textPropertyBoldButton; 82 | public ToggleButton textPropertyCursiveButton; 83 | public ToggleButton textPropertyUnderlineButton; 84 | public ToggleButton textPropertyCrossOutButton; 85 | 86 | @FXML 87 | public ColorPicker textColorPicker; 88 | public ColorPicker textFillColorPicker; 89 | 90 | @FXML 91 | public ColorPicker textFieldColorPicker; 92 | } -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFDocument.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | import com.itextpdf.io.image.ImageData; 4 | import com.itextpdf.io.image.ImageDataFactory; 5 | import com.itextpdf.kernel.geom.PageSize; 6 | import com.itextpdf.kernel.geom.Rectangle; 7 | import com.itextpdf.kernel.pdf.PdfDocument; 8 | import com.itextpdf.kernel.pdf.PdfPage; 9 | import com.itextpdf.kernel.pdf.PdfWriter; 10 | import com.itextpdf.kernel.pdf.canvas.PdfCanvas; 11 | import com.itextpdf.layout.Canvas; 12 | import com.itextpdf.layout.Document; 13 | import com.itextpdf.layout.element.Image; 14 | import com.itextpdf.layout.element.Paragraph; 15 | import com.itextpdf.layout.element.Table; 16 | import com.itextpdf.layout.element.Text; 17 | import com.itextpdf.layout.properties.TransparentColor; 18 | import hse.btf.pdfeditor.service.Converter; 19 | import hse.btf.pdfeditor.utils.PDFEditorConstants; 20 | import org.scilab.forge.jlatexmath.TeXConstants; 21 | import org.scilab.forge.jlatexmath.TeXFormula; 22 | import org.scilab.forge.jlatexmath.TeXIcon; 23 | 24 | import javax.imageio.ImageIO; 25 | import javax.swing.*; 26 | import javax.swing.text.StyleConstants; 27 | import java.awt.*; 28 | import java.awt.image.BufferedImage; 29 | import java.io.ByteArrayOutputStream; 30 | import java.io.IOException; 31 | import java.net.MalformedURLException; 32 | import java.nio.file.Files; 33 | import java.nio.file.Path; 34 | import java.nio.file.Paths; 35 | import java.util.List; 36 | 37 | public class PDFDocument { 38 | private final PdfWriter pdfWriter; 39 | private final PdfDocument pdfDocument; 40 | List pages; 41 | private PdfPage currentPage; 42 | private final PageSize pageSize; 43 | 44 | public PDFDocument() throws IOException { 45 | this(PDFEditorConstants.DEFAULT_PDF_FILE, PDFEditorConstants.DEFAULT_PAGE_SIZE); 46 | } 47 | 48 | public PDFDocument(String fileName) throws IOException { 49 | this(fileName, PDFEditorConstants.DEFAULT_PAGE_SIZE); 50 | } 51 | 52 | public PDFDocument(String fileName, PageSize pageSize) throws IOException { 53 | Path path = Paths.get(fileName); 54 | if (!Files.exists(path)) { 55 | Files.createDirectories(path.getParent()); 56 | Files.createFile(path); 57 | } 58 | pdfWriter = new PdfWriter(fileName); 59 | pdfDocument = new PdfDocument(pdfWriter); 60 | this.pageSize = pageSize; 61 | addPage(); 62 | } 63 | 64 | public PageSize getPageSize() { 65 | return pageSize; 66 | } 67 | 68 | public void addRectangleWithTextItem(PDFText textItem) { 69 | // creating canvas on current page 70 | PdfCanvas canvas = new PdfCanvas(currentPage); 71 | // creating rectangle on canvas 72 | Rectangle rect = new Rectangle( 73 | (float) textItem.getX(), 74 | (float) textItem.getY(), 75 | (float) textItem.getW(), 76 | (float) textItem.getH() 77 | ); 78 | // drawing rectangle 79 | // stroke 80 | TransparentColor borderColor = textItem.getBorderColor(); 81 | canvas.saveState().setStrokeColor(borderColor.getColor()); 82 | borderColor.applyStrokeTransparency(canvas); 83 | canvas.rectangle(rect); 84 | canvas.stroke().restoreState(); 85 | // fill 86 | TransparentColor backgroundColor = textItem.getBackgroundColor(); 87 | canvas.saveState().setFillColor(backgroundColor.getColor()); 88 | backgroundColor.applyFillTransparency(canvas); 89 | canvas.rectangle(rect); 90 | canvas.fill().restoreState(); 91 | 92 | // adding text to rectangle 93 | Text text = new Text(textItem.getText()) 94 | .setFontColor(textItem.getTextColor()) 95 | .setFont(textItem.getTextFont()); 96 | Paragraph paragraph = new Paragraph(text); 97 | new Canvas(canvas, rect).add(paragraph); 98 | } 99 | 100 | public void addRectangleWithImageItem(PDFImage imageItem) throws MalformedURLException { 101 | PdfCanvas canvas = new PdfCanvas(currentPage); 102 | Rectangle rect = new Rectangle( 103 | (float) imageItem.getX(), 104 | (float) imageItem.getY(), 105 | (float) imageItem.getW(), 106 | (float) imageItem.getH() 107 | ); 108 | 109 | // drawing rectangle 110 | // stroke 111 | TransparentColor borderColor = imageItem.getBorderColor(); 112 | canvas.saveState().setStrokeColor(borderColor.getColor()); 113 | borderColor.applyStrokeTransparency(canvas); 114 | canvas.rectangle(rect); 115 | canvas.stroke().restoreState(); 116 | // fill 117 | TransparentColor backgroundColor = imageItem.getBackgroundColor(); 118 | canvas.saveState().setFillColor(backgroundColor.getColor()); 119 | backgroundColor.applyFillTransparency(canvas); 120 | canvas.rectangle(rect); 121 | canvas.fill().restoreState(); 122 | 123 | ImageData data = ImageDataFactory.create(imageItem.getImagePath()); 124 | Image image = new Image(data); 125 | image.setFixedPosition((float) imageItem.getX(), (float) imageItem.getY()); 126 | image.scaleAbsolute((float) imageItem.getW(), (float) imageItem.getH()); 127 | 128 | new Canvas(canvas, rect).add(image); 129 | } 130 | 131 | public void addRectangleWithFormulaItem(PDFFormula formulaItem) throws IOException { 132 | PdfCanvas canvas = new PdfCanvas(currentPage); 133 | Rectangle rect = new Rectangle( 134 | (float) formulaItem.getX(), 135 | (float) formulaItem.getY(), 136 | (float) formulaItem.getW(), 137 | (float) formulaItem.getH() 138 | ); 139 | 140 | // drawing rectangle 141 | // stroke 142 | TransparentColor borderColor = formulaItem.getBorderColor(); 143 | canvas.saveState().setStrokeColor(borderColor.getColor()); 144 | borderColor.applyStrokeTransparency(canvas); 145 | canvas.rectangle(rect); 146 | canvas.stroke().restoreState(); 147 | // fill 148 | TransparentColor backgroundColor = formulaItem.getBackgroundColor(); 149 | canvas.saveState().setFillColor(backgroundColor.getColor()); 150 | backgroundColor.applyFillTransparency(canvas); 151 | canvas.rectangle(rect); 152 | canvas.fill().restoreState(); 153 | 154 | // сreating formula image 155 | TeXFormula formula = new TeXFormula(formulaItem.getFormula()); 156 | java.awt.Image formulaImage = formula.createBufferedImage(TeXConstants.STYLE_TEXT, PDFEditorConstants.DEFAULT_LATEX_DPI, formulaItem.getFormulaColor(), null); 157 | BufferedImage bufferedImage = (BufferedImage) formulaImage; 158 | 159 | // -- adding it to pdf -- 160 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 161 | ImageIO.write(bufferedImage, "png", byteArrayOutputStream); 162 | 163 | ImageData data = ImageDataFactory.create(byteArrayOutputStream.toByteArray()); 164 | Image image = new Image(data); 165 | image.setFixedPosition((float) formulaItem.getX(), (float) formulaItem.getY()); 166 | image.setWidth((float) formulaItem.getW()); 167 | image.setHeight((float) formulaItem.getH()); 168 | 169 | new Canvas(canvas, rect).add(image); 170 | } 171 | 172 | public void addRectangleWithTableItem(PDFTable tableItem) { 173 | PdfCanvas canvas = new PdfCanvas(currentPage); 174 | Rectangle rect = new Rectangle( 175 | (float) tableItem.getX(), 176 | (float) tableItem.getY(), 177 | (float) tableItem.getW(), 178 | (float) tableItem.getH() 179 | ); 180 | // canvas.setStrokeColor(tableItem.getRectangleStrokeColor().getColor()) 181 | // .setFillColor(tableItem.getRectangleFillColor().getColor()) 182 | // .rectangle(rect) 183 | // .fill() 184 | // .stroke(); 185 | 186 | Table table = new Table(tableItem.getCols()); 187 | table.setFontColor(tableItem.getFontColor()); 188 | 189 | for (String cellContent : tableItem.getCellContents()) { 190 | table.addCell(cellContent); 191 | } 192 | 193 | new Canvas(canvas, rect).add(table); 194 | } 195 | 196 | public void setCurrentPage(int index) { 197 | currentPage = pdfDocument.getPage(index); 198 | } 199 | 200 | public void addPage() { 201 | currentPage = pdfDocument.addNewPage(); 202 | } 203 | 204 | public void exportDocument() { 205 | Document document = new Document(pdfDocument, pageSize); 206 | document.close(); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFFormula.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | import java.awt.Color; 4 | import com.itextpdf.kernel.colors.ColorConstants; 5 | 6 | public class PDFFormula extends PDFItem { 7 | public static final Color defaultColor = Color.BLACK; 8 | private String formula; 9 | private int fontSize; 10 | private Color formulaColor; 11 | 12 | public PDFFormula(float x, float y, float w, float h) { 13 | super(x, y, w, h); 14 | setFormulaColor(defaultColor); 15 | } 16 | 17 | public void setFormula(String formula) { 18 | this.formula = formula; 19 | } 20 | 21 | public String getFormula() { 22 | return formula; 23 | } 24 | 25 | public void setFontSize(int fontSize) { 26 | this.fontSize = fontSize; 27 | } 28 | 29 | public int getFontSize() { 30 | return fontSize; 31 | } 32 | 33 | public Color getFormulaColor() { 34 | return formulaColor; 35 | } 36 | 37 | public void setFormulaColor(Color formulaColor) { 38 | this.formulaColor = formulaColor; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFImage.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | public class PDFImage extends PDFItem { 4 | private String imagePath; 5 | 6 | public PDFImage(float x, float y, float w, float h) { 7 | super(x, y, w, h); 8 | } 9 | 10 | public void setImagePath(String imagePath) { 11 | this.imagePath = imagePath; 12 | } 13 | 14 | public String getImagePath() { 15 | return imagePath; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFItem.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | import com.itextpdf.kernel.colors.Color; 4 | import com.itextpdf.kernel.colors.ColorConstants; 5 | import com.itextpdf.layout.properties.TransparentColor; 6 | 7 | public class PDFItem { 8 | private double x; 9 | private double y; 10 | private double w; 11 | private double h; 12 | private TransparentColor borderColor; 13 | private TransparentColor backgroundColor; 14 | 15 | public PDFItem(double x, double y, double w, double h) { 16 | this.x = x; 17 | this.y = y; 18 | this.w = w; 19 | this.h = h; 20 | borderColor = new TransparentColor(ColorConstants.WHITE, 0); 21 | backgroundColor = new TransparentColor(ColorConstants.WHITE, 0); 22 | } 23 | 24 | public void setBorderColor(TransparentColor borderColor) { 25 | this.borderColor = borderColor; 26 | } 27 | 28 | public void setBackgroundColor(TransparentColor backgroundColor) { 29 | this.backgroundColor = backgroundColor; 30 | } 31 | 32 | public void setX(float x) { 33 | this.x = x; 34 | } 35 | 36 | public void setY(float y) { 37 | this.y = y; 38 | } 39 | 40 | public void setW(float w) { 41 | this.w = w; 42 | } 43 | 44 | public void setH(float h) { 45 | this.h = h; 46 | } 47 | 48 | public double getX() { 49 | return x; 50 | } 51 | 52 | public double getY() { 53 | return y; 54 | } 55 | 56 | public double getW() { 57 | return w; 58 | } 59 | 60 | public double getH() { 61 | return h; 62 | } 63 | 64 | public TransparentColor getBorderColor() { 65 | return borderColor; 66 | } 67 | 68 | public TransparentColor getBackgroundColor() { 69 | return backgroundColor; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFTable.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | import com.itextpdf.kernel.colors.Color; 4 | 5 | import java.util.List; 6 | 7 | public class PDFTable extends PDFItem { 8 | private int cols; 9 | private List cellContents; 10 | private Color fontColor; 11 | 12 | 13 | public PDFTable(double x, double y, double w, double h) { 14 | super(x, y, w, h); 15 | } 16 | 17 | public void setCols(int cols) { 18 | this.cols = cols; 19 | } 20 | 21 | public int getCols() { 22 | return cols; 23 | } 24 | 25 | public void setCellContents(List cellContents) { 26 | this.cellContents = cellContents; 27 | } 28 | 29 | public List getCellContents() { 30 | return cellContents; 31 | } 32 | 33 | public void setFontColor(Color fontColor) { 34 | this.fontColor = fontColor; 35 | } 36 | 37 | public Color getFontColor() { 38 | return fontColor; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/entity/PDFText.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.entity; 2 | 3 | import com.itextpdf.io.font.PdfEncodings; 4 | import com.itextpdf.kernel.colors.Color; 5 | import com.itextpdf.kernel.colors.ColorConstants; 6 | import com.itextpdf.kernel.font.PdfFont; 7 | import com.itextpdf.kernel.font.PdfFontFactory; 8 | import hse.btf.pdfeditor.utils.FontUtil; 9 | import hse.btf.pdfeditor.utils.PDFEditorConstants; 10 | 11 | import java.io.IOException; 12 | 13 | public class PDFText extends PDFItem { 14 | // TODO add to PDFEditorConstants 15 | public static final String defaultText = "default text"; 16 | public static final Color defaultColor = ColorConstants.BLACK; 17 | 18 | private String text; 19 | private PdfFont textFont; 20 | private double textSize; 21 | private Color textColor; 22 | 23 | public PDFText(double x, double y, double w, double h) { 24 | super(x, y, w, h); 25 | setText(defaultText); 26 | setTextFont(FontUtil.getPdfFontByName(PDFEditorConstants.DEFAULT_FONT)); 27 | setTextColor(defaultColor); 28 | setTextSize(PDFEditorConstants.DEFAULT_FONT_SIZE); 29 | } 30 | 31 | public void setText(String text) { 32 | this.text = text; 33 | } 34 | 35 | public void setTextColor(Color textColor) { 36 | this.textColor = textColor; 37 | } 38 | 39 | public void setTextFont(PdfFont font) { 40 | this.textFont = font; 41 | } 42 | 43 | public void setTextSize(double textSize) { 44 | this.textSize = textSize; 45 | } 46 | 47 | public String getText() { 48 | return text; 49 | } 50 | 51 | public Color getTextColor() { 52 | return textColor; 53 | } 54 | 55 | public PdfFont getTextFont() { 56 | return textFont; 57 | } 58 | 59 | public double getTextSize() { 60 | return textSize; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/FormulaEntity.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import hse.btf.pdfeditor.MouseController; 4 | import hse.btf.pdfeditor.PdfWorkWindowController; 5 | import hse.btf.pdfeditor.utils.PDFEditorConstants; 6 | import javafx.beans.property.SimpleStringProperty; 7 | import javafx.beans.property.StringProperty; 8 | import javafx.embed.swing.SwingFXUtils; 9 | import javafx.scene.Cursor; 10 | import javafx.scene.image.Image; 11 | import javafx.scene.image.ImageView; 12 | import javafx.scene.input.MouseEvent; 13 | import javafx.scene.layout.AnchorPane; 14 | import javafx.scene.layout.Pane; 15 | import javafx.scene.paint.Color; 16 | import javafx.scene.shape.Circle; 17 | import javafx.scene.shape.StrokeType; 18 | import org.scilab.forge.jlatexmath.TeXConstants; 19 | import org.scilab.forge.jlatexmath.TeXFormula; 20 | 21 | import java.awt.image.BufferedImage; 22 | 23 | public class FormulaEntity extends PaperEntity implements FormulaEntityInterface { 24 | private ImageView formulaImage; 25 | private final String formula; 26 | private final StringProperty formulaProperty; 27 | 28 | public FormulaEntity(String formula) { 29 | super(); 30 | formulaImage = drawFormula(formula); 31 | double coef = formulaImage.getImage().getWidth() / formulaImage.getImage().getHeight(); 32 | this.formula = formula; 33 | this.formulaProperty = new SimpleStringProperty(formula); 34 | formulaImage.setFitHeight(50); 35 | textBox.setPrefHeight(50); 36 | textBox.setPrefWidth(50 * coef); 37 | } 38 | 39 | @Override 40 | public Pane createFxmlObject() { 41 | if (PdfWorkWindowController.target != null) { 42 | PdfWorkWindowController.target.removeCss("text-region"); 43 | PdfWorkWindowController.target.hidePoint(); 44 | } 45 | this.applyCss("text-region"); 46 | PdfWorkWindowController.target = this; 47 | 48 | 49 | formulaImage.setPreserveRatio(true); 50 | resizePoint = new Circle(6, Color.WHITE); 51 | resizePoint.setStrokeWidth(1); 52 | resizePoint.setStrokeType(StrokeType.INSIDE); 53 | resizePoint.setStroke(Color.valueOf("0x808080FF")); 54 | 55 | AnchorPane.setRightAnchor(resizePoint, -6.0); 56 | AnchorPane.setBottomAnchor(resizePoint, -6.0); 57 | 58 | AnchorPane.setTopAnchor(formulaImage, topPadding); 59 | AnchorPane.setLeftAnchor(formulaImage, leftPadding); 60 | AnchorPane.setRightAnchor(formulaImage, rightPadding); 61 | AnchorPane.setBottomAnchor(formulaImage, bottomPadding); 62 | 63 | textBox.getChildren().add(formulaImage); 64 | textBox.getChildren().add(resizePoint); 65 | 66 | textBox.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> textBox.setCursor(Cursor.HAND)); 67 | textBox.addEventHandler(MouseEvent.MOUSE_EXITED, event -> textBox.setCursor(Cursor.DEFAULT)); 68 | 69 | textBox.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 70 | if (PdfWorkWindowController.target != null) { 71 | PdfWorkWindowController.target.removeCss("text-region"); 72 | PdfWorkWindowController.target.hidePoint(); 73 | } 74 | this.applyCss("text-region"); 75 | PdfWorkWindowController.target = this; 76 | this.showPoint(); 77 | textBox.setCursor(Cursor.MOVE); 78 | MouseController.Position.x = e.getX(); 79 | MouseController.Position.y = e.getY(); 80 | }); 81 | 82 | textBox.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> textBox.setCursor(Cursor.DEFAULT)); 83 | 84 | textBox.setOnMouseDragged(e -> { 85 | double distanceX = e.getX() - MouseController.Position.x; 86 | double distanceY = e.getY() - MouseController.Position.y; 87 | 88 | double x = textBox.getLayoutX() + distanceX; 89 | double y = textBox.getLayoutY() + distanceY; 90 | 91 | textBox.relocate(x, y); 92 | }); 93 | 94 | resizePoint.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> { 95 | textBox.setCursor(Cursor.SE_RESIZE); 96 | event.consume(); 97 | }); 98 | 99 | resizePoint.addEventHandler(MouseEvent.MOUSE_EXITED, event -> { 100 | textBox.setCursor(Cursor.DEFAULT); 101 | event.consume(); 102 | }); 103 | 104 | resizePoint.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 105 | MouseController.Position.x = e.getX(); 106 | MouseController.Position.y = e.getY(); 107 | e.consume(); 108 | }); 109 | 110 | resizePoint.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> { 111 | textBox.setCursor(Cursor.DEFAULT); 112 | event.consume(); 113 | }); 114 | 115 | resizePoint.setOnMouseDragged(e -> { 116 | double distanceX = e.getX() - MouseController.Position.x; 117 | double distanceY = e.getY() - MouseController.Position.y; 118 | 119 | double coef = textBox.getPrefHeight() / textBox.getPrefWidth(); 120 | double x = textBox.getPrefWidth() + distanceX; 121 | double y = textBox.getPrefHeight() + distanceX * coef; 122 | 123 | textBox.setPrefWidth(x); 124 | textBox.setPrefHeight(y); 125 | formulaImage.setFitWidth(x - leftPadding - rightPadding); 126 | formulaImage.setFitHeight(y - bottomPadding - topPadding); 127 | 128 | e.consume(); 129 | }); 130 | 131 | return textBox; 132 | } 133 | 134 | private ImageView drawFormula(String latex) { 135 | TeXFormula formula = new TeXFormula(latex); 136 | java.awt.Image awtImage = formula.createBufferedImage(TeXConstants.STYLE_TEXT, PDFEditorConstants.DEFAULT_LATEX_DPI, java.awt.Color.BLACK, null); 137 | Image fxImage = SwingFXUtils.toFXImage((BufferedImage) awtImage, null); 138 | return new ImageView(fxImage); 139 | } 140 | 141 | @Override 142 | public StringProperty getFormulaProperty() { 143 | return formulaProperty; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/FormulaEntityInterface.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import javafx.beans.property.StringProperty; 4 | 5 | public interface FormulaEntityInterface { 6 | StringProperty getFormulaProperty(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/ImageEntity.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import hse.btf.pdfeditor.MouseController; 4 | import hse.btf.pdfeditor.PdfWorkWindowController; 5 | import javafx.beans.property.DoubleProperty; 6 | import javafx.scene.Cursor; 7 | import javafx.scene.image.ImageView; 8 | import javafx.scene.input.MouseEvent; 9 | import javafx.scene.layout.AnchorPane; 10 | import javafx.scene.layout.Pane; 11 | import javafx.scene.paint.Color; 12 | import javafx.scene.shape.Circle; 13 | import javafx.scene.shape.StrokeType; 14 | 15 | 16 | public class ImageEntity extends PaperEntity implements ImageEntityInterface { 17 | ImageView image; 18 | String fileName; 19 | 20 | public ImageEntity(String url) { 21 | super(); 22 | image = new ImageView(url); 23 | textBox.setPrefHeight(image.getImage().getHeight()); 24 | textBox.setPrefWidth(image.getImage().getWidth()); 25 | fileName = url; 26 | } 27 | 28 | @Override 29 | public Pane createFxmlObject() { 30 | if (PdfWorkWindowController.target != null) { 31 | PdfWorkWindowController.target.removeCss("text-region"); 32 | PdfWorkWindowController.target.hidePoint(); 33 | } 34 | PdfWorkWindowController.target = this; 35 | this.applyCss("text-region"); 36 | 37 | image.setPreserveRatio(true); 38 | resizePoint = new Circle(6, Color.WHITE); 39 | resizePoint.setStrokeWidth(1); 40 | resizePoint.setStrokeType(StrokeType.INSIDE); 41 | resizePoint.setStroke(Color.valueOf("0x808080FF")); 42 | 43 | AnchorPane.setRightAnchor(resizePoint, -6.0); 44 | AnchorPane.setBottomAnchor(resizePoint, -6.0); 45 | 46 | AnchorPane.setTopAnchor(image, topPadding); 47 | AnchorPane.setLeftAnchor(image, leftPadding); 48 | AnchorPane.setRightAnchor(image, rightPadding); 49 | AnchorPane.setBottomAnchor(image, bottomPadding); 50 | 51 | textBox.getChildren().add(image); 52 | textBox.getChildren().add(resizePoint); 53 | 54 | textBox.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> textBox.setCursor(Cursor.HAND)); 55 | textBox.addEventHandler(MouseEvent.MOUSE_EXITED, event -> textBox.setCursor(Cursor.DEFAULT)); 56 | 57 | textBox.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 58 | if (PdfWorkWindowController.target != null) { 59 | PdfWorkWindowController.target.removeCss("text-region"); 60 | PdfWorkWindowController.target.hidePoint(); 61 | } 62 | this.applyCss("text-region"); 63 | PdfWorkWindowController.target = this; 64 | this.showPoint(); 65 | textBox.setCursor(Cursor.MOVE); 66 | MouseController.Position.x = e.getX(); 67 | MouseController.Position.y = e.getY(); 68 | }); 69 | 70 | textBox.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> textBox.setCursor(Cursor.DEFAULT)); 71 | 72 | textBox.setOnMouseDragged(e -> { 73 | double distanceX = e.getX() - MouseController.Position.x; 74 | double distanceY = e.getY() - MouseController.Position.y; 75 | 76 | double x = textBox.getLayoutX() + distanceX; 77 | double y = textBox.getLayoutY() + distanceY; 78 | 79 | textBox.relocate(x, y); 80 | }); 81 | 82 | resizePoint.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> { 83 | textBox.setCursor(Cursor.SE_RESIZE); 84 | event.consume(); 85 | }); 86 | 87 | resizePoint.addEventHandler(MouseEvent.MOUSE_EXITED, event -> { 88 | textBox.setCursor(Cursor.DEFAULT); 89 | event.consume(); 90 | }); 91 | 92 | resizePoint.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 93 | MouseController.Position.x = e.getX(); 94 | MouseController.Position.y = e.getY(); 95 | e.consume(); 96 | }); 97 | 98 | resizePoint.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> { 99 | textBox.setCursor(Cursor.DEFAULT); 100 | event.consume(); 101 | }); 102 | 103 | resizePoint.setOnMouseDragged(e -> { 104 | double distanceX = e.getX() - MouseController.Position.x; 105 | double distanceY = e.getY() - MouseController.Position.y; 106 | 107 | double coef = textBox.getPrefHeight() / textBox.getPrefWidth(); 108 | double x = textBox.getPrefWidth() + distanceX; 109 | double y = textBox.getPrefHeight() + distanceX * coef; 110 | 111 | textBox.setPrefWidth(x); 112 | textBox.setPrefHeight(y); 113 | image.setFitWidth(x - leftPadding - rightPadding); 114 | image.setFitHeight(y - bottomPadding - topPadding); 115 | 116 | e.consume(); 117 | }); 118 | 119 | return textBox; 120 | } 121 | 122 | @Override 123 | public String getFileName() { 124 | return fileName; 125 | } 126 | } -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/ImageEntityInterface.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | public interface ImageEntityInterface { 4 | String getFileName(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/PaperEntity.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import javafx.beans.property.DoubleProperty; 4 | import javafx.scene.layout.AnchorPane; 5 | import javafx.scene.layout.Pane; 6 | import javafx.scene.shape.Circle; 7 | 8 | public abstract class PaperEntity { 9 | protected AnchorPane textBox; 10 | protected Circle resizePoint; 11 | protected double leftPadding; 12 | protected double rightPadding; 13 | protected double topPadding; 14 | protected double bottomPadding; 15 | 16 | protected PaperEntity() { 17 | textBox = new AnchorPane(); 18 | } 19 | 20 | public abstract Pane createFxmlObject(); 21 | 22 | public DoubleProperty getXProperty() { 23 | return textBox.layoutXProperty(); 24 | } 25 | 26 | public DoubleProperty getYProperty() { 27 | return textBox.layoutYProperty(); 28 | } 29 | 30 | public DoubleProperty getWidthProperty() { 31 | return textBox.prefWidthProperty(); 32 | } 33 | 34 | public DoubleProperty getHeightProperty() { 35 | return textBox.prefHeightProperty(); 36 | } 37 | 38 | public double getWidth() { 39 | return textBox.getWidth(); 40 | } 41 | 42 | public double getHeight() { 43 | return textBox.getHeight(); 44 | } 45 | 46 | public double getLeftPadding() { 47 | return leftPadding; 48 | } 49 | 50 | public double getRightPadding() { 51 | return rightPadding; 52 | } 53 | 54 | public double getTopPadding() { 55 | return topPadding; 56 | } 57 | 58 | public double getBottomPadding() { 59 | return bottomPadding; 60 | } 61 | 62 | public void setX(double x) { 63 | textBox.setLayoutX(x); 64 | } 65 | 66 | public void setY(double y) { 67 | textBox.setLayoutY(y); 68 | } 69 | 70 | public void setWidth(double width) { 71 | textBox.setPrefWidth(width); 72 | } 73 | 74 | public void setHeight(double height) { 75 | textBox.setPrefHeight(height); 76 | } 77 | 78 | public void setLeftPadding(double leftPadding) { 79 | this.leftPadding = leftPadding; 80 | } 81 | 82 | public void setRightPadding(double rightPadding) { 83 | this.rightPadding = rightPadding; 84 | } 85 | 86 | public void setTopPadding(double topPadding) { 87 | this.topPadding = topPadding; 88 | } 89 | 90 | public void setBottomPadding(double bottomPadding) { 91 | this.bottomPadding = bottomPadding; 92 | } 93 | 94 | protected void removeCss(String css) { 95 | textBox.getStyleClass().remove(css); 96 | } 97 | 98 | protected void applyCss(String css) { 99 | textBox.getStyleClass().add(css); 100 | } 101 | 102 | protected void hidePoint() { 103 | resizePoint.setVisible(false); 104 | } 105 | 106 | protected void showPoint() { 107 | resizePoint.setVisible(true); 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/TextEntity.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import hse.btf.pdfeditor.PdfWorkWindowController; 4 | import hse.btf.pdfeditor.utils.FontUtil; 5 | import javafx.beans.property.IntegerProperty; 6 | import javafx.beans.property.ObjectProperty; 7 | import javafx.beans.property.SimpleIntegerProperty; 8 | import javafx.beans.property.SimpleStringProperty; 9 | import javafx.beans.property.StringProperty; 10 | import javafx.scene.Cursor; 11 | import javafx.scene.control.TextArea; 12 | import javafx.scene.input.MouseEvent; 13 | import javafx.scene.layout.AnchorPane; 14 | import javafx.scene.layout.Background; 15 | import javafx.scene.layout.Border; 16 | import javafx.scene.layout.Pane; 17 | import javafx.scene.paint.Color; 18 | import javafx.scene.shape.Circle; 19 | import javafx.scene.shape.StrokeType; 20 | import javafx.scene.text.Font; 21 | 22 | import static hse.btf.pdfeditor.MouseController.Position; 23 | 24 | public class TextEntity extends PaperEntity implements TextEntityInterface { 25 | private final TextArea text = new TextArea(); 26 | private final StringProperty textFontFamily = new SimpleStringProperty(""); 27 | private final StringProperty textFontName = new SimpleStringProperty(""); 28 | private final IntegerProperty textFontSize = new SimpleIntegerProperty(13); 29 | private final StringProperty textFontStyle = new SimpleStringProperty(""); 30 | public TextEntity() { 31 | super(); 32 | } 33 | 34 | @Override 35 | public Pane createFxmlObject() { 36 | if (PdfWorkWindowController.target != null) { 37 | PdfWorkWindowController.target.removeCss("text-region"); 38 | PdfWorkWindowController.target.hidePoint(); 39 | } 40 | this.applyCss("text-region"); 41 | PdfWorkWindowController.target = this; 42 | 43 | text.setWrapText(true); 44 | 45 | resizePoint = new Circle(6, Color.WHITE); 46 | resizePoint.setStrokeWidth(1); 47 | resizePoint.setStrokeType(StrokeType.INSIDE); 48 | resizePoint.setStroke(Color.valueOf("0x808080FF")); 49 | 50 | AnchorPane.setRightAnchor(resizePoint, -6.0); 51 | AnchorPane.setBottomAnchor(resizePoint, -6.0); 52 | 53 | AnchorPane.setTopAnchor(text, topPadding); 54 | AnchorPane.setLeftAnchor(text, leftPadding); 55 | AnchorPane.setRightAnchor(text, rightPadding); 56 | AnchorPane.setBottomAnchor(text, bottomPadding); 57 | 58 | textBox.getChildren().add(text); 59 | textBox.getChildren().add(resizePoint); 60 | 61 | textBox.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> textBox.setCursor(Cursor.HAND)); 62 | textBox.addEventHandler(MouseEvent.MOUSE_EXITED, event -> textBox.setCursor(Cursor.DEFAULT)); 63 | 64 | textBox.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 65 | if (PdfWorkWindowController.target != null) { 66 | PdfWorkWindowController.target.removeCss("text-region"); 67 | PdfWorkWindowController.target.hidePoint(); 68 | } 69 | this.applyCss("text-region"); 70 | PdfWorkWindowController.target = this; 71 | this.showPoint(); 72 | textBox.setCursor(Cursor.MOVE); 73 | Position.x = e.getX(); 74 | Position.y = e.getY(); 75 | }); 76 | 77 | textBox.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> textBox.setCursor(Cursor.DEFAULT)); 78 | 79 | textBox.setOnMouseDragged(e -> { 80 | double distanceX = e.getX() - Position.x; 81 | double distanceY = e.getY() - Position.y; 82 | 83 | double x = textBox.getLayoutX() + distanceX; 84 | double y = textBox.getLayoutY() + distanceY; 85 | 86 | textBox.relocate(x, y); 87 | }); 88 | 89 | resizePoint.addEventHandler(MouseEvent.MOUSE_ENTERED, event -> { 90 | textBox.setCursor(Cursor.SE_RESIZE); 91 | event.consume(); 92 | }); 93 | 94 | resizePoint.addEventHandler(MouseEvent.MOUSE_EXITED, event -> { 95 | textBox.setCursor(Cursor.DEFAULT); 96 | event.consume(); 97 | }); 98 | 99 | resizePoint.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> { 100 | Position.x = e.getX(); 101 | Position.y = e.getY(); 102 | e.consume(); 103 | }); 104 | 105 | resizePoint.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> { 106 | textBox.setCursor(Cursor.DEFAULT); 107 | event.consume(); 108 | }); 109 | 110 | resizePoint.setOnMouseDragged(e -> { 111 | double distanceX = e.getX() - Position.x; 112 | double distanceY = e.getY() - Position.y; 113 | 114 | double x = textBox.getPrefWidth() + distanceX; 115 | double y = textBox.getPrefHeight() + distanceY; 116 | 117 | textBox.setPrefWidth(x); 118 | textBox.setPrefHeight(y); 119 | e.consume(); 120 | }); 121 | 122 | return textBox; 123 | } 124 | 125 | @Override 126 | public StringProperty getText() { 127 | return text.textProperty(); 128 | } 129 | 130 | @Override 131 | public ObjectProperty getFont() { 132 | return text.fontProperty(); 133 | } 134 | 135 | @Override 136 | public StringProperty getFontFamily() { 137 | return textFontFamily; 138 | } 139 | 140 | @Override 141 | public StringProperty getFontName() { 142 | return textFontName; 143 | } 144 | 145 | @Override 146 | public IntegerProperty getFontSize() { 147 | return textFontSize; 148 | } 149 | 150 | @Override 151 | public StringProperty getFontStyle() { 152 | return textFontStyle; 153 | } 154 | 155 | @Override 156 | public ObjectProperty getBackground() { 157 | return text.backgroundProperty(); 158 | } 159 | 160 | @Override 161 | public ObjectProperty getBorder() { 162 | return text.borderProperty(); 163 | } 164 | 165 | public void setFont(String fontName) { 166 | text.setFont(FontUtil.getFxFontByName(fontName)); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/entities/TextEntityInterface.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.entities; 2 | 3 | import javafx.beans.property.IntegerProperty; 4 | import javafx.beans.property.ObjectProperty; 5 | import javafx.beans.property.StringProperty; 6 | import javafx.scene.layout.Background; 7 | import javafx.scene.layout.Border; 8 | import javafx.scene.text.Font; 9 | 10 | public interface TextEntityInterface { 11 | StringProperty getText(); 12 | ObjectProperty getFont(); 13 | ObjectProperty getBackground(); 14 | ObjectProperty getBorder(); 15 | StringProperty getFontFamily(); 16 | StringProperty getFontName(); 17 | IntegerProperty getFontSize(); 18 | StringProperty getFontStyle(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/utility/PaperContextMenu.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.utility; 2 | 3 | import javafx.scene.control.ContextMenu; 4 | import javafx.scene.control.MenuItem; 5 | 6 | public class PaperContextMenu extends ContextMenu { 7 | public PaperContextMenu() { 8 | super(); 9 | MenuItem menuItem1 = new MenuItem("menu item 1"); 10 | MenuItem menuItem2 = new MenuItem("menu item 2"); 11 | MenuItem menuItem3 = new MenuItem("menu item 3"); 12 | 13 | this.getItems().add(menuItem1); 14 | this.getItems().add(menuItem2); 15 | this.getItems().add(menuItem3); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/models/utility/ProjectNameBox.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models.utility; 2 | 3 | import javafx.geometry.Pos; 4 | import javafx.scene.Scene; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.layout.VBox; 8 | import javafx.stage.Modality; 9 | import javafx.stage.Stage; 10 | 11 | public class ProjectNameBox { 12 | public static void display(String title, String message) { 13 | Stage window = new Stage(); 14 | 15 | // blocking events for other windows 16 | window.initModality(Modality.APPLICATION_MODAL); 17 | window.setTitle(title); 18 | window.setMinWidth(350); 19 | 20 | // window elements 21 | Label messageLabel = new Label(message); 22 | Button okButton = new Button("Ok"); 23 | okButton.setOnAction(event -> window.close()); 24 | 25 | // layout 26 | VBox layout = new VBox(10); 27 | layout.getChildren().addAll(messageLabel, okButton); 28 | layout.setAlignment(Pos.CENTER); 29 | 30 | // displaying window and waiting for it to be closed 31 | Scene scene = new Scene(layout); 32 | window.setScene(scene); 33 | window.showAndWait(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/service/Converter.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.service; 2 | 3 | import com.itextpdf.kernel.colors.Color; 4 | import com.itextpdf.kernel.colors.ColorConstants; 5 | import com.itextpdf.kernel.colors.DeviceRgb; 6 | import com.itextpdf.kernel.font.PdfFont; 7 | import com.itextpdf.kernel.geom.PageSize; 8 | import com.itextpdf.kernel.pdf.colorspace.PdfColorSpace; 9 | import com.itextpdf.layout.properties.TransparentColor; 10 | import hse.btf.pdfeditor.entity.*; 11 | import hse.btf.pdfeditor.models.*; 12 | import hse.btf.pdfeditor.utils.FontUtil; 13 | import hse.btf.pdfeditor.entity.PDFDocument; 14 | import hse.btf.pdfeditor.entity.PDFFormula; 15 | import hse.btf.pdfeditor.entity.PDFImage; 16 | import hse.btf.pdfeditor.entity.PDFText; 17 | import hse.btf.pdfeditor.models.FormulaItem; 18 | import hse.btf.pdfeditor.models.ImageItem; 19 | import hse.btf.pdfeditor.models.Item; 20 | import hse.btf.pdfeditor.models.TextItem; 21 | import hse.btf.pdfeditor.utils.PDFEditorConstants; 22 | import javafx.scene.layout.Background; 23 | import javafx.scene.layout.BackgroundFill; 24 | import javafx.scene.layout.Border; 25 | import javafx.scene.layout.BorderStroke; 26 | 27 | import java.awt.*; 28 | import java.awt.image.ColorConvertOp; 29 | import java.io.IOException; 30 | import java.math.BigInteger; 31 | import java.nio.file.Path; 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | import java.util.Optional; 35 | 36 | import static hse.btf.pdfeditor.storages.ProjectDataStorage.itemsHolder; 37 | import static hse.btf.pdfeditor.utils.FontUtil.*; 38 | 39 | public class Converter { 40 | public static void saveDocument(String fileName) throws IOException { 41 | FontUtil.init(); 42 | PDFDocument pdfDocument = new PDFDocument(fileName); 43 | PageSize pageSize = pdfDocument.getPageSize(); 44 | 45 | System.out.println("size: " + itemsHolder.getObservableItemsList().size()); 46 | for (Item item : itemsHolder.getObservableItemsList()) { 47 | if (item instanceof TextItem) { 48 | System.out.println("TextItem"); 49 | 50 | TextItem textItem = (TextItem) item; 51 | PDFText pdfText = convertTextItem(textItem, pageSize); 52 | pdfDocument.addRectangleWithTextItem(pdfText); 53 | } 54 | if (item instanceof ImageItem) { 55 | System.out.println("image item"); 56 | ImageItem imageItem = (ImageItem) item; 57 | PDFImage pdfImage = convertImageItem(imageItem, pageSize); 58 | pdfDocument.addRectangleWithImageItem(pdfImage); 59 | } 60 | if (item instanceof FormulaItem) { 61 | System.out.println("formula item"); 62 | FormulaItem formulaItem = (FormulaItem) item; 63 | PDFFormula pdfFormula = convertFormulaItem(formulaItem, pageSize); 64 | pdfDocument.addRectangleWithFormulaItem(pdfFormula); 65 | } 66 | } 67 | pdfDocument.exportDocument(); 68 | } 69 | 70 | // static { 71 | // try { 72 | // FontUtil.registerFont("Free Sans", Path.of(FREE_SANS)); 73 | // FontUtil.registerFont("Arial", Path.of(ARIAL)); 74 | // FontUtil.registerFont("Times New Roman", Path.of(TIMES_NEW_ROMAN)); 75 | // } catch (IOException e) { 76 | // System.err.println("Couldn't load default fonts"); 77 | // } 78 | // } 79 | 80 | private static List convertCoordinates(double x, double y, double w, double h, PageSize pageSize) { 81 | System.out.println("-- from ui --"); 82 | System.out.println("x = " + x); 83 | System.out.println("y = " + y); 84 | System.out.println("w = " + w); 85 | System.out.println("h = " + h); 86 | System.out.println("-------------"); 87 | System.out.println("-- page size --"); 88 | System.out.println("width = " + pageSize.getWidth()); 89 | System.out.println("height = " + pageSize.getHeight()); 90 | System.out.println("---------------"); 91 | List coordinates = new ArrayList<>(); 92 | // // prefHeight="1188.0" prefWidth="840.0" 93 | double coef = 842.0 / 1188.0; 94 | double conv_x = x * coef; 95 | double conv_y = y * coef; 96 | double conv_w = w * coef; 97 | double conv_h = h * coef; 98 | System.out.println("conv_x = " + conv_x); 99 | System.out.println("conv_y = " + conv_y); 100 | System.out.println("conv_w = " + conv_w); 101 | System.out.println("conv_h = " + conv_h); 102 | coordinates.add(0, (float) conv_x); // x 103 | coordinates.add(1, (float) (pageSize.getHeight() - conv_y - conv_h)); // 104 | coordinates.add(2, (float) conv_w); // w 105 | coordinates.add(3, (float) conv_h); // h 106 | System.out.println("-- pdf --"); 107 | System.out.println("x = " + coordinates.get(0)); 108 | System.out.println("y = " + coordinates.get(1)); 109 | System.out.println("w = " + coordinates.get(2)); 110 | System.out.println("h = " + coordinates.get(3)); 111 | System.out.println("---------"); 112 | return coordinates; 113 | } 114 | 115 | private static TransparentColor getPdfColorfromRGBA(String rgbaString) { 116 | List rgba = new ArrayList<>(); 117 | for (int i = 0; i < rgbaString.length(); i += 2) { 118 | rgba.add(Integer.parseInt(rgbaString.substring(i, i + 2), 16)); 119 | } 120 | Color color = new DeviceRgb(rgba.get(0), rgba.get(1), rgba.get(2)); 121 | return new TransparentColor(color, (float) rgba.get(3) / 255); 122 | } 123 | 124 | private static TransparentColor convertBorderColor(Border border) { 125 | if (border == null) { 126 | return new TransparentColor(ColorConstants.WHITE, 0); 127 | } 128 | Optional stroke = border.getStrokes().stream().findFirst(); 129 | if (stroke.isEmpty()) { 130 | return new TransparentColor(ColorConstants.WHITE, 0); 131 | } 132 | System.out.println(stroke.get().getTopStroke()); 133 | String rgbaString = stroke.get().getTopStroke().toString().substring(2); 134 | return getPdfColorfromRGBA(rgbaString); 135 | } 136 | 137 | private static TransparentColor convertBackgroundColor(Background background) { 138 | if (background == null) { 139 | return new TransparentColor(ColorConstants.WHITE, 0); 140 | } 141 | Optional fill = background.getFills().stream().findFirst(); 142 | if (fill.isEmpty()) { 143 | return new TransparentColor(ColorConstants.WHITE, 0); 144 | } 145 | System.out.println(fill.get().getFill()); 146 | String rgbaString = fill.get().getFill().toString().substring(2); 147 | return getPdfColorfromRGBA(rgbaString); 148 | } 149 | 150 | private static PDFText convertTextItem(TextItem textItem, PageSize pageSize) { 151 | List converted = convertCoordinates(textItem.getX().get(), textItem.getY().get(), textItem.getW().get(), textItem.getH().get(), pageSize); 152 | PDFText pdfText = new PDFText( 153 | converted.get(0), 154 | converted.get(1), 155 | converted.get(2), 156 | converted.get(3) 157 | ); 158 | pdfText.setText(textItem.getText().get()); 159 | // background and border 160 | // TransparentColor backgroundColor = convertBackgroundColor(textItem.getBackground().get()); 161 | // TransparentColor borderColor = convertBorderColor(textItem.getBorder().get()); 162 | // pdfText.setBackgroundColor(backgroundColor); 163 | // pdfText.setBorderColor(borderColor); 164 | 165 | // TODO add size, font, color 166 | PdfFont font = FontUtil.getPdfFontByName(textItem.getFontFamily().get()); 167 | if (font == null) { 168 | font = FontUtil.getPdfFontByName(PDFEditorConstants.DEFAULT_FONT); 169 | } 170 | pdfText.setTextFont(font); 171 | pdfText.setTextSize(textItem.getFontSize().get()); 172 | // TODO: здесь пофиксить геттеры 173 | // pdfText.setText(textItem.getText().get()); 174 | // System.out.println("-- font --"); 175 | // Font font = textItem.getFont().get(); 176 | // if (font != null) { 177 | // System.out.println(font.getFamily()); 178 | // System.out.println(font.getName()); 179 | // System.out.println(font.getSize()); 180 | // System.out.println(font.getStyle()); 181 | // } 182 | // System.out.println("----------"); 183 | // System.out.println("-- background --"); 184 | // Background background = textItem.getBackground().get(); 185 | // if (background != null) { 186 | // background.getFills().forEach(fill -> System.out.println("background fill: " + fill.getFill())); 187 | // background.getImages().forEach(image -> System.out.println("background image: " + image.getImage().getUrl())); 188 | // System.out.println("background outsets: " + background.getOutsets()); 189 | // } 190 | // System.out.println("----------------"); 191 | // System.out.println("-- border --"); 192 | // Border border = textItem.getBorder().get(); 193 | // if (border != null) { 194 | // border.getImages().forEach(image -> System.out.println("border image: " + image.getImage().getUrl())); 195 | // border.getStrokes().forEach(stroke -> System.out.println("border stroke: " + stroke)); 196 | // System.out.println("border insets: " + border.getInsets()); 197 | // System.out.println("border outsets: " + border.getOutsets()); 198 | // } 199 | // System.out.println("------------"); 200 | return pdfText; 201 | } 202 | 203 | private static PDFImage convertImageItem(ImageItem imageItem, PageSize pageSize) { 204 | List converted = convertCoordinates(imageItem.getX().get(), imageItem.getY().get(), imageItem.getW().get(), imageItem.getH().get(), pageSize); 205 | PDFImage pdfImage = new PDFImage( 206 | converted.get(0), 207 | converted.get(1), 208 | converted.get(2), 209 | converted.get(3) 210 | ); 211 | pdfImage.setImagePath(imageItem.getImageFileName()); 212 | return pdfImage; 213 | } 214 | 215 | private static PDFFormula convertFormulaItem(FormulaItem formulaItem, PageSize pageSize) { 216 | List converted = convertCoordinates(formulaItem.getX().get(), formulaItem.getY().get(), formulaItem.getW().get(), formulaItem.getH().get(), pageSize); 217 | PDFFormula pdfFormula = new PDFFormula( 218 | converted.get(0), 219 | converted.get(1), 220 | converted.get(2), 221 | converted.get(3) 222 | ); 223 | pdfFormula.setFormula(formulaItem.getFormula().get()); 224 | pdfFormula.setFontSize(50); 225 | return pdfFormula; 226 | } 227 | } 228 | 229 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/storages/EntitiesStorage.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.storages; 2 | 3 | import hse.btf.pdfeditor.models.entities.PaperEntity; 4 | import javafx.collections.FXCollections; 5 | import javafx.collections.ObservableList; 6 | 7 | public class EntitiesStorage { 8 | public static final ObservableList entitiesList = FXCollections.observableArrayList(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/storages/ProjectDataStorage.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.storages; 2 | 3 | import hse.btf.pdfeditor.Holder; 4 | 5 | public class ProjectDataStorage { 6 | public static String pdfFileName = ""; 7 | public static final Holder itemsHolder = new Holder(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/utils/CreatorConstants.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | 7 | public final class CreatorConstants { 8 | private CreatorConstants() { 9 | } 10 | 11 | public static final @NotNull List FONTS = List.of("Arial", "Georgia", "Dubai"); 12 | public static final @NotNull String DEFAULT_FONT = "Arial"; 13 | public static final @NotNull List IMAGE_EFFECTS = List.of("Normal"); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.utils; 2 | 3 | import hse.btf.pdfeditor.PdfEditorApplication; 4 | import hse.btf.pdfeditor.models.entities.ImageEntity; 5 | import hse.btf.pdfeditor.service.Converter; 6 | import hse.btf.pdfeditor.storages.ProjectDataStorage; 7 | import javafx.scene.control.Button; 8 | import javafx.stage.FileChooser; 9 | 10 | import java.awt.*; 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.util.Locale; 16 | 17 | import static hse.btf.pdfeditor.PdfWorkWindowController.papers; 18 | import static hse.btf.pdfeditor.serializers.SavingClassKt.saveToFile; 19 | import static hse.btf.pdfeditor.storages.EntitiesStorage.entitiesList; 20 | 21 | public class FileUtil { 22 | private static final FileChooser fileChooser = new FileChooser(); 23 | private static final Desktop desktop = Desktop.getDesktop(); 24 | 25 | public static void savePDFDocument(Button button) { 26 | button.setOnAction(ev -> { 27 | fileChooser.getExtensionFilters().clear(); 28 | fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("PDF files", "*.pdf")); 29 | File file; 30 | if (ProjectDataStorage.pdfFileName.isEmpty()) { 31 | file = fileChooser.showSaveDialog(null); 32 | if (file == null) { 33 | return; 34 | } 35 | ProjectDataStorage.pdfFileName = file.getAbsolutePath(); 36 | } else { 37 | file = Path.of(ProjectDataStorage.pdfFileName).toFile(); 38 | } 39 | try { 40 | Converter.saveDocument(file.getAbsolutePath().toLowerCase(Locale.ROOT)); 41 | } catch (IOException e) { 42 | System.err.println("Couldn't convert document"); 43 | } 44 | openPDFDocument(file); 45 | 46 | // saving info to JSON 47 | saveToFile(file.getName()); 48 | }); 49 | } 50 | 51 | private static void openPDFDocument(File file) { 52 | try { 53 | desktop.open(file); 54 | } catch (IOException e) { 55 | System.err.println("Couldn't open file"); 56 | } 57 | } 58 | 59 | public static void loadImage(Button button) { 60 | button.setOnAction(ev -> { 61 | fileChooser.getExtensionFilters().clear(); 62 | fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Image files", "*.jpg", "*.png", "*.gif")); 63 | File loadedImage = fileChooser.showOpenDialog(null); 64 | if (loadedImage == null) { 65 | return; 66 | } 67 | ImageEntity entity = new ImageEntity(loadedImage.getAbsolutePath()); 68 | entitiesList.add(entity); 69 | entity.setBottomPadding(0); 70 | entity.setTopPadding(0); 71 | entity.setLeftPadding(0); 72 | entity.setRightPadding(0); 73 | papers.get(0).getChildren().add(entity.createFxmlObject()); 74 | papers.get(0).getStylesheets().add(PdfEditorApplication.class.getResource("main.css").toExternalForm()); 75 | }); 76 | } 77 | 78 | public static void loadFont(Button button, String fontName) { 79 | button.setOnAction(ev -> { 80 | fileChooser.getExtensionFilters().clear(); 81 | fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("TTF files", "*.ttf")); 82 | File loadedFont = fileChooser.showOpenDialog(null); 83 | System.out.println(loadedFont.getName()); 84 | Path newPath = Path.of("src", "main", "resources", "hse/btf/pdfeditor/fonts", loadedFont.getName()); 85 | try { 86 | Files.copy(loadedFont.toPath(), newPath); 87 | FontUtil.registerFont(fontName, newPath); 88 | } catch (IOException e) { 89 | System.err.println("Couldn't load font"); 90 | } 91 | }); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/utils/FontUtil.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.utils; 2 | 3 | import com.itextpdf.io.font.PdfEncodings; 4 | import com.itextpdf.kernel.font.PdfFont; 5 | import com.itextpdf.kernel.font.PdfFontFactory; 6 | import hse.btf.pdfeditor.PdfEditorApplication; 7 | import javafx.scene.text.Font; 8 | import org.apache.commons.io.IOUtils; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.nio.file.Path; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | public class FontUtil { 18 | public static final @NotNull String FREE_SANS = "free_sans.ttf"; 19 | public static final @NotNull String ARIAL = "arial.ttf"; 20 | public static final @NotNull String TIMES_NEW_ROMAN = "times_new_roman.ttf"; 21 | 22 | private static Map fontNameToFontPath = new HashMap<>(); 23 | private static Map pdfFonts = new HashMap<>(); 24 | private static Map fxFonts = new HashMap<>(); 25 | 26 | public static void init() { 27 | try { 28 | fontNameToFontPath.clear(); 29 | pdfFonts.clear(); 30 | fxFonts.clear(); 31 | registerFont("Free Sans", Path.of(FREE_SANS)); 32 | registerFont("Arial", Path.of(ARIAL)); 33 | registerFont("Times New Roman", Path.of(TIMES_NEW_ROMAN)); 34 | } catch (IOException e) { 35 | System.err.println("Couldn't load default fonts"); 36 | } 37 | } 38 | 39 | public static void registerFont(String fontName, Path fontPath) throws IOException { 40 | fontNameToFontPath.put(fontName, fontPath); 41 | addPdfFont(fontPath); 42 | addFxFont(fontPath); 43 | } 44 | 45 | private static void addPdfFont(Path fontPath) throws IOException { 46 | InputStream is = PdfEditorApplication.class.getResourceAsStream(fontPath.toString()); 47 | byte[] fontBytes = IOUtils.toByteArray(is); 48 | PdfFont font = PdfFontFactory.createFont(fontBytes, PdfEncodings.IDENTITY_H); 49 | pdfFonts.put(fontPath, font); 50 | } 51 | 52 | private static void addFxFont(Path fontPath) { 53 | addFxFont(fontPath, PDFEditorConstants.DEFAULT_FONT_SIZE); 54 | } 55 | 56 | public static void addFxFont(Path fontPath, double fontSize) { 57 | Font font = Font.loadFont(PdfEditorApplication.class.getResourceAsStream(fontPath.toString()), fontSize); 58 | fxFonts.put(fontPath, font); 59 | } 60 | 61 | public static PdfFont getPdfFontByName(String fontName) { 62 | Path fontPath = fontNameToFontPath.get(fontName); 63 | return pdfFonts.get(fontPath); 64 | } 65 | 66 | public static Font getFxFontByName(String fontName) { 67 | Path fontPath = fontNameToFontPath.get(fontName); 68 | return fxFonts.get(fontPath); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/hse/btf/pdfeditor/utils/PDFEditorConstants.java: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.utils; 2 | 3 | import com.itextpdf.kernel.geom.PageSize; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class PDFEditorConstants { 7 | public static final @NotNull String DEFAULT_FONT = "Free Sans"; 8 | public static final double DEFAULT_FONT_SIZE = 14; 9 | // TODO add default color 10 | // TODO add default bg color 11 | 12 | public static final @NotNull String DEFAULT_OUTPUT_DIR = "out/"; 13 | public static final @NotNull String DEFAULT_PDF_FILE = DEFAULT_OUTPUT_DIR + "file.pdf"; 14 | 15 | public static final @NotNull PageSize DEFAULT_PAGE_SIZE = PageSize.A4; 16 | public static final @NotNull int DEFAULT_LATEX_DPI = 1000; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module hse.btf.pdfeditor { 2 | requires javafx.controls; 3 | requires javafx.fxml; 4 | requires javafx.web; 5 | requires javafx.swing; 6 | 7 | requires org.controlsfx.controls; 8 | requires com.dlsc.formsfx; 9 | requires validatorfx; 10 | requires org.kordamp.ikonli.javafx; 11 | requires org.kordamp.bootstrapfx.core; 12 | requires eu.hansolo.tilesfx; 13 | 14 | requires jlatexmath; 15 | requires kernel; 16 | requires io; 17 | requires layout; 18 | requires forms; 19 | requires pdfa; 20 | requires sign; 21 | requires barcodes; 22 | requires font.asian; 23 | requires hyph; 24 | requires java.desktop; 25 | requires org.apache.commons.io; 26 | 27 | opens hse.btf.pdfeditor to javafx.fxml; 28 | exports hse.btf.pdfeditor; 29 | exports hse.btf.pdfeditor.entity; 30 | opens hse.btf.pdfeditor.entity to javafx.fxml; 31 | exports hse.btf.pdfeditor.models; 32 | opens hse.btf.pdfeditor.models to javafx.fxml; 33 | exports hse.btf.pdfeditor.utils; 34 | opens hse.btf.pdfeditor.utils to javafx.fxml; 35 | exports hse.btf.pdfeditor.models.utility; 36 | opens hse.btf.pdfeditor.models.utility to javafx.fxml; 37 | exports hse.btf.pdfeditor.models.entities; 38 | opens hse.btf.pdfeditor.models.entities to javafx.fxml; 39 | exports hse.btf.pdfeditor.storages; 40 | opens hse.btf.pdfeditor.storages to javafx.fxml; 41 | exports hse.btf.pdfeditor.serializers; 42 | opens hse.btf.pdfeditor.serializers to javafx.fxml; 43 | 44 | requires tornadofx; 45 | requires kotlin.stdlib; 46 | requires kotlin.reflect; 47 | requires kotlinx.serialization.core; 48 | requires kotlinx.serialization.json; 49 | requires annotations; 50 | requires org.jfree.fxgraphics2d; 51 | } -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/EntityToItemConverter.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor 2 | 3 | import hse.btf.pdfeditor.models.FormulaItem 4 | import hse.btf.pdfeditor.models.ImageItem 5 | import hse.btf.pdfeditor.models.TextItem 6 | import hse.btf.pdfeditor.models.entities.FormulaEntity 7 | import hse.btf.pdfeditor.models.entities.ImageEntity 8 | import hse.btf.pdfeditor.models.entities.TextEntity 9 | import hse.btf.pdfeditor.storages.EntitiesStorage.entitiesList 10 | import hse.btf.pdfeditor.storages.ProjectDataStorage.itemsHolder 11 | import tornadofx.bind 12 | 13 | class EntityToItemConverter { 14 | init { 15 | itemsHolder.observableItemsList.bind(entitiesList) { 16 | when (it) { 17 | is TextEntity -> 18 | TextItem().apply { 19 | x.bindBidirectional(it.xProperty) 20 | y.bindBidirectional(it.yProperty) 21 | w.bindBidirectional(it.widthProperty) 22 | h.bindBidirectional(it.heightProperty) 23 | 24 | text.bindBidirectional(it.text) 25 | fontFamily.bindBidirectional(it.fontFamily) 26 | fontName.bindBidirectional(it.fontName) 27 | fontSize.bindBidirectional(it.fontSize) 28 | fontStyle.bindBidirectional(it.fontStyle) 29 | // font.bindBidirectional(it.font) 30 | // background.bindBidirectional(it.background) 31 | // border.bindBidirectional(it.border) 32 | 33 | } 34 | is ImageEntity -> 35 | ImageItem().apply { 36 | x.bindBidirectional(it.xProperty) 37 | y.bindBidirectional(it.yProperty) 38 | w.bindBidirectional(it.widthProperty) 39 | h.bindBidirectional(it.heightProperty) 40 | 41 | imageFileName = it.fileName 42 | } 43 | is FormulaEntity -> 44 | FormulaItem().apply { 45 | x.bindBidirectional(it.xProperty) 46 | y.bindBidirectional(it.yProperty) 47 | w.bindBidirectional(it.widthProperty) 48 | h.bindBidirectional(it.heightProperty) 49 | 50 | formula.bindBidirectional(it.formulaProperty) 51 | } 52 | else -> { 53 | println("Else branch converter") 54 | null 55 | } 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/Holder.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor 2 | 3 | import hse.btf.pdfeditor.models.Item 4 | import hse.btf.pdfeditor.storages.ProjectDataStorage 5 | import javafx.collections.FXCollections 6 | import javafx.collections.ObservableList 7 | import kotlinx.serialization.decodeFromString 8 | import kotlinx.serialization.json.Json 9 | 10 | data class Holder(val observableItemsList: ObservableList = FXCollections.observableArrayList()) { 11 | fun updateFromFileData(fileData: String) { 12 | val itemsList = Json.decodeFromString>(fileData) 13 | 14 | // updating data 15 | ProjectDataStorage.itemsHolder.observableItemsList.clear() 16 | ProjectDataStorage.itemsHolder.observableItemsList.addAll(itemsList) 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/datasaving/test.json: -------------------------------------------------------------------------------- 1 | [{"type":"hse.btf.pdfeditor.models.ImageItem","x":112.4,"y":180.0,"w":614,"h":614,"imageFileName":"C:\\Users\\sasha\\Downloads\\268.340x340.jpg"},{"type":"hse.btf.pdfeditor.models.TextItem","x":325.5999999999999,"y":331.2,"w":282,"h":142,"text":"fdjsalkfjslkjflsakjflkdsa;","fontFamily":"","fontName":"","fontSize":13,"fontStyle":""},{"type":"hse.btf.pdfeditor.models.FormulaItem","x":513.5999999999999,"y":284.0,"w":135,"h":220,"formula":"\\frac{1}{2}"}] -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/models/FormulaItem.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models 2 | 3 | import hse.btf.pdfeditor.serializers.StringPropertySerializer 4 | import javafx.beans.property.SimpleStringProperty 5 | import javafx.beans.property.StringProperty 6 | import kotlinx.serialization.Serializable 7 | 8 | @Serializable 9 | data class FormulaItem( 10 | @Serializable(with = StringPropertySerializer::class) 11 | val formula: StringProperty = SimpleStringProperty("1") 12 | ) : Item() -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/models/ImageItem.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class ImageItem( 7 | var imageFileName: String = "" 8 | ) : Item() -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/models/Item.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models 2 | 3 | import hse.btf.pdfeditor.serializers.DoublePropertySerializer 4 | import hse.btf.pdfeditor.serializers.IntegerPropertySerializer 5 | import javafx.beans.property.DoubleProperty 6 | import javafx.beans.property.IntegerProperty 7 | import javafx.beans.property.SimpleDoubleProperty 8 | import javafx.beans.property.SimpleIntegerProperty 9 | import kotlinx.serialization.Serializable 10 | 11 | @Serializable 12 | sealed class Item { 13 | @Serializable(with = DoublePropertySerializer::class) 14 | val x: DoubleProperty = SimpleDoubleProperty(150.0) 15 | 16 | @Serializable(with = DoublePropertySerializer::class) 17 | val y: DoubleProperty = SimpleDoubleProperty(200.0) 18 | 19 | @Serializable(with = IntegerPropertySerializer::class) 20 | val w: IntegerProperty = SimpleIntegerProperty(100) 21 | 22 | @Serializable(with = IntegerPropertySerializer::class) 23 | val h: IntegerProperty = SimpleIntegerProperty(50) 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/models/TableItem.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models 2 | 3 | import hse.btf.pdfeditor.serializers.IntegerPropertySerializer 4 | import javafx.beans.property.IntegerProperty 5 | import javafx.beans.property.SimpleIntegerProperty 6 | import kotlinx.serialization.Serializable 7 | 8 | @Serializable 9 | data class TableItem ( 10 | @Serializable(with = IntegerPropertySerializer::class) 11 | val rows: IntegerProperty = SimpleIntegerProperty(2), 12 | 13 | @Serializable(with = IntegerPropertySerializer::class) 14 | val cols: IntegerProperty = SimpleIntegerProperty(2) 15 | ) -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/models/TextItem.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.models 2 | 3 | import hse.btf.pdfeditor.serializers.IntegerPropertySerializer 4 | import hse.btf.pdfeditor.serializers.StringPropertySerializer 5 | import javafx.beans.property.IntegerProperty 6 | import javafx.beans.property.SimpleIntegerProperty 7 | import javafx.beans.property.SimpleStringProperty 8 | import javafx.beans.property.StringProperty 9 | import kotlinx.serialization.Serializable 10 | 11 | @Serializable 12 | data class TextItem( 13 | @Serializable(with = StringPropertySerializer::class) 14 | val text: StringProperty = SimpleStringProperty("type text here"), 15 | 16 | // val font: ObjectProperty = SimpleObjectProperty(), 17 | // val background: ObjectProperty = SimpleObjectProperty(), 18 | // val border: ObjectProperty = SimpleObjectProperty() 19 | 20 | @Serializable(with = StringPropertySerializer::class) 21 | val fontFamily: StringProperty = SimpleStringProperty(""), 22 | 23 | @Serializable(with = StringPropertySerializer::class) 24 | val fontName: StringProperty = SimpleStringProperty("Arial"), 25 | 26 | @Serializable(with = IntegerPropertySerializer::class) 27 | val fontSize: IntegerProperty = SimpleIntegerProperty(13), 28 | 29 | @Serializable(with = StringPropertySerializer::class) 30 | val fontStyle: StringProperty = SimpleStringProperty("") 31 | ) : Item() -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/serializers/SavingClass.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.serializers 2 | 3 | 4 | import hse.btf.pdfeditor.storages.ProjectDataStorage.itemsHolder 5 | import kotlinx.serialization.ExperimentalSerializationApi 6 | import kotlinx.serialization.decodeFromString 7 | import kotlinx.serialization.encodeToString 8 | import kotlinx.serialization.json.Json 9 | import java.io.File 10 | import java.nio.file.Files 11 | import java.nio.file.Path 12 | 13 | private val format = Json { encodeDefaults = true } 14 | 15 | @OptIn(ExperimentalSerializationApi::class) 16 | fun saveToFile(fileName: String) { 17 | // opening vs creating file and (over)writing information to it 18 | // test.pdf -> test.json 19 | var splitedFile = fileName.split(".").toTypedArray() 20 | var fileDir = Path.of("src","main", "kotlin", "hse", "btf", "pdfeditor", "datasaving") 21 | if (Files.notExists(fileDir)) { 22 | Files.createDirectories(fileDir) 23 | } 24 | var filePath = Path.of(fileDir.toString(), splitedFile.get(0) + ".json") 25 | if (Files.notExists(filePath)) { 26 | Files.createFile(filePath) 27 | } 28 | val file = filePath.toAbsolutePath().toFile() 29 | // getting Json string 30 | System.out.println(filePath) 31 | val json = format.encodeToString(itemsHolder.observableItemsList.toList()) 32 | file.writeText(json) 33 | } 34 | 35 | fun readFromFile(fileName: String) : Boolean { 36 | var filePath = "./src/main/kotlin/hse/btf/pdfeditor/datasaving/" 37 | filePath += if (fileName != "") "$fileName.json" else "dataFile.json" 38 | val file = File(filePath) 39 | 40 | if (!file.exists()) { 41 | return false 42 | } 43 | 44 | val fileData = file.readText() 45 | itemsHolder.updateFromFileData(fileData) 46 | return true 47 | } 48 | 49 | @OptIn(ExperimentalSerializationApi::class) 50 | fun serializeProjectsNames(projectNamesList: List) { 51 | val jsonFile = File("./src/main/resources/users.projects/projectNamesList.json") 52 | 53 | val json = format.encodeToString(projectNamesList) 54 | jsonFile.writeText(json) 55 | } 56 | 57 | @OptIn(ExperimentalSerializationApi::class) 58 | fun deserializeProjectsNames(projectNamesList: MutableList) { 59 | val jsonFile = File("./src/main/resources/users.projects/projectNamesList.json") 60 | 61 | val fileData = jsonFile.readText() 62 | val namesList = try { 63 | Json.decodeFromString>(fileData) 64 | } catch (e: Throwable) { 65 | listOf() 66 | } 67 | 68 | projectNamesList.clear() 69 | projectNamesList.addAll(namesList) 70 | } -------------------------------------------------------------------------------- /src/main/kotlin/hse/btf/pdfeditor/serializers/Serializers.kt: -------------------------------------------------------------------------------- 1 | package hse.btf.pdfeditor.serializers 2 | 3 | import javafx.beans.property.DoubleProperty 4 | import javafx.beans.property.IntegerProperty 5 | import javafx.beans.property.SimpleDoubleProperty 6 | import javafx.beans.property.SimpleIntegerProperty 7 | import javafx.beans.property.SimpleStringProperty 8 | import javafx.beans.property.StringProperty 9 | import kotlinx.serialization.ExperimentalSerializationApi 10 | import kotlinx.serialization.KSerializer 11 | import kotlinx.serialization.builtins.serializer 12 | import kotlinx.serialization.encoding.Decoder 13 | import kotlinx.serialization.encoding.Encoder 14 | 15 | object StringPropertySerializer : KSerializer { 16 | private val delegateSerializer = String.serializer() 17 | 18 | @OptIn(ExperimentalSerializationApi::class) 19 | override val descriptor = delegateSerializer.descriptor 20 | 21 | override fun serialize(encoder: Encoder, value: StringProperty) { 22 | encoder.encodeSerializableValue(delegateSerializer, value.get()) 23 | } 24 | 25 | override fun deserialize(decoder: Decoder): StringProperty { 26 | val stringData = decoder.decodeSerializableValue(delegateSerializer) 27 | return SimpleStringProperty(stringData) 28 | } 29 | } 30 | 31 | object IntegerPropertySerializer : KSerializer { 32 | private val delegateSerializer = Int.serializer() 33 | 34 | @OptIn(ExperimentalSerializationApi::class) 35 | override val descriptor = delegateSerializer.descriptor 36 | 37 | override fun serialize(encoder: Encoder, value: IntegerProperty) { 38 | encoder.encodeSerializableValue(delegateSerializer, value.get()) 39 | } 40 | 41 | override fun deserialize(decoder: Decoder): IntegerProperty { 42 | val intData = decoder.decodeSerializableValue(delegateSerializer) 43 | return SimpleIntegerProperty(intData) 44 | } 45 | } 46 | 47 | object DoublePropertySerializer : KSerializer { 48 | private val delegateSerializer = Double.serializer() 49 | 50 | @OptIn(ExperimentalSerializationApi::class) 51 | override val descriptor = delegateSerializer.descriptor 52 | 53 | override fun serialize(encoder: Encoder, value: DoubleProperty) { 54 | encoder.encodeSerializableValue(delegateSerializer, value.get()) 55 | } 56 | 57 | override fun deserialize(decoder: Decoder): DoubleProperty { 58 | val doubleData = decoder.decodeSerializableValue(delegateSerializer) 59 | return SimpleDoubleProperty(doubleData) 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/resources/hello-scene.properties: -------------------------------------------------------------------------------- 1 | # messages and labels for Hello Scene 2 | label.project-name.empty=Empty project name 3 | label.project-name.non-new=Non-new project name 4 | label.project-name.non-existing=No such project 5 | 6 | message.project-name.empty=A project name cannot be an empty string! 7 | message.project-name.non-new=The project with this name was already created!\nPlease, enter a new name or click the button \"open\" 8 | message.project-name.non-existing=The project with this name doesn't exist!\nPlease, enter the name of an existing project or click the button \"create\" 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/hse/btf/pdfeditor/arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pdf-Creator/pdf-editor/ae30ad8db46ab7c922219e100ef6f5c7ebf551b8/src/main/resources/hse/btf/pdfeditor/arial.ttf -------------------------------------------------------------------------------- /src/main/resources/hse/btf/pdfeditor/formula-pane.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 |