Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/java/com/google/scrollview/ScrollView.java @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright 2007 Google Inc. All Rights Reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); You may not | |
| 4 // use this file except in compliance with the License. You may obtain a copy of | |
| 5 // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by | |
| 6 // applicable law or agreed to in writing, software distributed under the | |
| 7 // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS | |
| 8 // OF ANY KIND, either express or implied. See the License for the specific | |
| 9 // language governing permissions and limitations under the License. | |
| 10 | |
| 11 package com.google.scrollview; | |
| 12 | |
| 13 import com.google.scrollview.events.SVEvent; | |
| 14 import com.google.scrollview.ui.SVImageHandler; | |
| 15 import com.google.scrollview.ui.SVWindow; | |
| 16 import org.piccolo2d.nodes.PImage; | |
| 17 | |
| 18 import java.io.BufferedReader; | |
| 19 import java.io.IOException; | |
| 20 import java.io.InputStreamReader; | |
| 21 import java.io.PrintStream; | |
| 22 import java.net.ServerSocket; | |
| 23 import java.net.Socket; | |
| 24 import java.util.ArrayList; | |
| 25 import java.util.regex.Pattern; | |
| 26 | |
| 27 /** | |
| 28 * The ScrollView class is the main class which gets started from the command | |
| 29 * line. It sets up LUA and handles the network processing. | |
| 30 * @author wanke@google.com | |
| 31 */ | |
| 32 public class ScrollView { | |
| 33 | |
| 34 /** The port our server listens at. */ | |
| 35 public static int SERVER_PORT = 8461; | |
| 36 | |
| 37 /** | |
| 38 * All SVWindow objects share the same connection stream. The socket is needed | |
| 39 * to detect when the connection got closed, in/out are used to send and | |
| 40 * receive messages. | |
| 41 */ | |
| 42 private static Socket socket; | |
| 43 private static PrintStream out; | |
| 44 public static BufferedReader in; | |
| 45 public static float polylineXCoords[]; // The coords being received. | |
| 46 public static float polylineYCoords[]; // The coords being received. | |
| 47 public static int polylineSize; // The size of the coords arrays. | |
| 48 public static int polylineScanned; // The size read so far. | |
| 49 private static ArrayList<SVWindow> windows; // The id to SVWindow map. | |
| 50 private static Pattern intPattern; // For checking integer arguments. | |
| 51 private static Pattern floatPattern; // For checking float arguments. | |
| 52 | |
| 53 /** Keeps track of the number of messages received. */ | |
| 54 static int nrInputLines = 0; | |
| 55 | |
| 56 /** Prints all received messages to the console if true. */ | |
| 57 static boolean debugViewNetworkTraffic = false; | |
| 58 | |
| 59 /** Add a new message to the outgoing queue. */ | |
| 60 public static void addMessage(SVEvent e) { | |
| 61 if (debugViewNetworkTraffic) { | |
| 62 System.out.println("(S->c) " + e.toString()); | |
| 63 } | |
| 64 String str = e.toString(); | |
| 65 // Send the whole thing as UTF8. | |
| 66 try { | |
| 67 byte [] utf8 = str.getBytes("UTF8"); | |
| 68 out.write(utf8, 0, utf8.length); | |
| 69 } catch (java.io.UnsupportedEncodingException ex) { | |
| 70 System.out.println("Oops... can't encode to UTF8... Exiting"); | |
| 71 System.exit(0); | |
| 72 } | |
| 73 out.println(); | |
| 74 // Flush the output and check for errors. | |
| 75 boolean error = out.checkError(); | |
| 76 if (error) { | |
| 77 System.out.println("Connection error. Quitting ScrollView Server..."); | |
| 78 System.exit(0); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 /** Read one message from client (assuming there are any). */ | |
| 83 public static String receiveMessage() throws IOException { | |
| 84 return in.readLine(); | |
| 85 } | |
| 86 | |
| 87 /** | |
| 88 * The main program loop. Basically loops through receiving messages and | |
| 89 * processing them and then sending messages (if there are any). | |
| 90 */ | |
| 91 private static void IOLoop() { | |
| 92 String inputLine; | |
| 93 | |
| 94 try { | |
| 95 while (!socket.isClosed() && !socket.isInputShutdown() && | |
| 96 !socket.isOutputShutdown() && | |
| 97 socket.isConnected() && socket.isBound()) { | |
| 98 inputLine = receiveMessage(); | |
| 99 if (inputLine == null) { | |
| 100 // End of stream reached. | |
| 101 break; | |
| 102 } | |
| 103 nrInputLines++; | |
| 104 if (debugViewNetworkTraffic) { | |
| 105 System.out.println("(c->S," + nrInputLines + ")" + inputLine); | |
| 106 } | |
| 107 | |
| 108 if (polylineSize > polylineScanned) { | |
| 109 // We are processing a polyline. | |
| 110 // Read pairs of coordinates separated by commas. | |
| 111 boolean first = true; | |
| 112 for (String coordStr : inputLine.split(",")) { | |
| 113 int coord = Integer.parseInt(coordStr); | |
| 114 if (first) { | |
| 115 polylineXCoords[polylineScanned] = coord; | |
| 116 } else { | |
| 117 polylineYCoords[polylineScanned++] = coord; | |
| 118 } | |
| 119 first = !first; | |
| 120 } | |
| 121 assert first; | |
| 122 } else { | |
| 123 // Process this normally. | |
| 124 processInput(inputLine); | |
| 125 } | |
| 126 } | |
| 127 } | |
| 128 // Some connection error | |
| 129 catch (IOException e) { | |
| 130 System.out.println("Connection error. Quitting ScrollView Server..."); | |
| 131 } | |
| 132 System.exit(0); | |
| 133 } | |
| 134 | |
| 135 // Parse a comma-separated list of arguments into ArrayLists of the | |
| 136 // possible types. Each type is stored in order, but the order | |
| 137 // distinction between types is lost. | |
| 138 // Note that the format is highly constrained to what the client used | |
| 139 // to send to LUA: | |
| 140 // Quoted string -> String. | |
| 141 // true or false -> Boolean. | |
| 142 // %f format number -> Float (no %e allowed) | |
| 143 // Sequence of digits -> Integer | |
| 144 // Nothing else allowed. | |
| 145 private static void parseArguments(String argList, | |
| 146 ArrayList<Integer> intList, | |
| 147 ArrayList<Float> floatList, | |
| 148 ArrayList<String> stringList, | |
| 149 ArrayList<Boolean> boolList) { | |
| 150 // str is only non-null if an argument starts with a single or double | |
| 151 // quote. str is set back to null on completion of the string with a | |
| 152 // matching quote. If the string contains a comma then str will stay | |
| 153 // non-null across multiple argStr values until a matching closing quote. | |
| 154 // Backslash escaped quotes do not count as terminating the string. | |
| 155 String str = null; | |
| 156 for (String argStr : argList.split(",")) { | |
| 157 if (str != null) { | |
| 158 // Last string was incomplete. Append argStr to it and restore comma. | |
| 159 // Execute str += "," + argStr in Java. | |
| 160 int length = str.length() + 1 + argStr.length(); | |
| 161 StringBuilder appended = new StringBuilder(length); | |
| 162 appended.append(str); | |
| 163 appended.append(","); | |
| 164 appended.append(argStr); | |
| 165 str = appended.toString(); | |
| 166 } else if (argStr.length() == 0) { | |
| 167 continue; | |
| 168 } else { | |
| 169 char quote = argStr.charAt(0); | |
| 170 // If it begins with a quote then it is a string, but may not | |
| 171 // end this time if it contained a comma. | |
| 172 if (quote == '\'' || quote == '"') { | |
| 173 str = argStr; | |
| 174 } | |
| 175 } | |
| 176 if (str != null) { | |
| 177 // It began with a quote. Check that it still does. | |
| 178 assert str.charAt(0) == '\'' || str.charAt(0) == '"'; | |
| 179 int len = str.length(); | |
| 180 if (len > 1 && str.charAt(len - 1) == str.charAt(0)) { | |
| 181 // We have an ending quote of the right type. Now check that | |
| 182 // it is not escaped. Must have an even number of slashes before. | |
| 183 int slash = len - 1; | |
| 184 while (slash > 0 && str.charAt(slash - 1) == '\\') | |
| 185 --slash; | |
| 186 if ((len - 1 - slash) % 2 == 0) { | |
| 187 // It is now complete. Chop off the quotes and save. | |
| 188 // TODO(rays) remove the first backslash of each pair. | |
| 189 stringList.add(str.substring(1, len - 1)); | |
| 190 str = null; | |
| 191 } | |
| 192 } | |
| 193 // If str is not null here, then we have a string with a comma in it. | |
| 194 // Append, and the next argument at the next iteration, but check | |
| 195 // that str is null after the loop terminates in case it was an | |
| 196 // unterminated string. | |
| 197 } else if (floatPattern.matcher(argStr).matches()) { | |
| 198 // It is a float. | |
| 199 floatList.add(Float.parseFloat(argStr)); | |
| 200 } else if (argStr.equals("true")) { | |
| 201 boolList.add(true); | |
| 202 } else if (argStr.equals("false")) { | |
| 203 boolList.add(false); | |
| 204 } else if (intPattern.matcher(argStr).matches()) { | |
| 205 // Only contains digits so must be an int. | |
| 206 intList.add(Integer.parseInt(argStr)); | |
| 207 } | |
| 208 // else ignore all incompatible arguments for forward compatibility. | |
| 209 } | |
| 210 // All strings must have been terminated. | |
| 211 assert str == null; | |
| 212 } | |
| 213 | |
| 214 /** Executes the LUA command parsed as parameter. */ | |
| 215 private static void processInput(String inputLine) { | |
| 216 if (inputLine == null) { | |
| 217 return; | |
| 218 } | |
| 219 // Execute a function encoded as a LUA statement! Yuk! | |
| 220 if (inputLine.charAt(0) == 'w') { | |
| 221 // This is a method call on a window. Parse it. | |
| 222 String noWLine = inputLine.substring(1); | |
| 223 String[] idStrs = noWLine.split("[ :]", 2); | |
| 224 int windowID = Integer.parseInt(idStrs[0]); | |
| 225 // Find the parentheses. | |
| 226 int start = inputLine.indexOf('('); | |
| 227 int end = inputLine.lastIndexOf(')'); | |
| 228 // Parse the args. | |
| 229 ArrayList<Integer> intList = new ArrayList<Integer>(4); | |
| 230 ArrayList<Float> floatList = new ArrayList<Float>(2); | |
| 231 ArrayList<String> stringList = new ArrayList<String>(4); | |
| 232 ArrayList<Boolean> boolList = new ArrayList<Boolean>(3); | |
| 233 parseArguments(inputLine.substring(start + 1, end), | |
| 234 intList, floatList, stringList, boolList); | |
| 235 int colon = inputLine.indexOf(':'); | |
| 236 if (colon > 1 && colon < start) { | |
| 237 // This is a regular function call. Look for the name and call it. | |
| 238 String func = inputLine.substring(colon + 1, start); | |
| 239 if (func.equals("drawLine")) { | |
| 240 windows.get(windowID).drawLine(intList.get(0), intList.get(1), | |
| 241 intList.get(2), intList.get(3)); | |
| 242 } else if (func.equals("createPolyline")) { | |
| 243 windows.get(windowID).createPolyline(intList.get(0)); | |
| 244 } else if (func.equals("drawPolyline")) { | |
| 245 windows.get(windowID).drawPolyline(); | |
| 246 } else if (func.equals("drawRectangle")) { | |
| 247 windows.get(windowID).drawRectangle(intList.get(0), intList.get(1), | |
| 248 intList.get(2), intList.get(3)); | |
| 249 } else if (func.equals("setVisible")) { | |
| 250 windows.get(windowID).setVisible(boolList.get(0)); | |
| 251 } else if (func.equals("setAlwaysOnTop")) { | |
| 252 windows.get(windowID).setAlwaysOnTop(boolList.get(0)); | |
| 253 } else if (func.equals("addMessage")) { | |
| 254 windows.get(windowID).addMessage(stringList.get(0)); | |
| 255 } else if (func.equals("addMessageBox")) { | |
| 256 windows.get(windowID).addMessageBox(); | |
| 257 } else if (func.equals("clear")) { | |
| 258 windows.get(windowID).clear(); | |
| 259 } else if (func.equals("setStrokeWidth")) { | |
| 260 windows.get(windowID).setStrokeWidth(floatList.get(0)); | |
| 261 } else if (func.equals("drawEllipse")) { | |
| 262 windows.get(windowID).drawEllipse(intList.get(0), intList.get(1), | |
| 263 intList.get(2), intList.get(3)); | |
| 264 } else if (func.equals("pen")) { | |
| 265 if (intList.size() == 4) { | |
| 266 windows.get(windowID).pen(intList.get(0), intList.get(1), | |
| 267 intList.get(2), intList.get(3)); | |
| 268 } else { | |
| 269 windows.get(windowID).pen(intList.get(0), intList.get(1), | |
| 270 intList.get(2)); | |
| 271 } | |
| 272 } else if (func.equals("brush")) { | |
| 273 if (intList.size() == 4) { | |
| 274 windows.get(windowID).brush(intList.get(0), intList.get(1), | |
| 275 intList.get(2), intList.get(3)); | |
| 276 } else { | |
| 277 windows.get(windowID).brush(intList.get(0), intList.get(1), | |
| 278 intList.get(2)); | |
| 279 } | |
| 280 } else if (func.equals("textAttributes")) { | |
| 281 windows.get(windowID).textAttributes(stringList.get(0), | |
| 282 intList.get(0), | |
| 283 boolList.get(0), | |
| 284 boolList.get(1), | |
| 285 boolList.get(2)); | |
| 286 } else if (func.equals("drawText")) { | |
| 287 windows.get(windowID).drawText(intList.get(0), intList.get(1), | |
| 288 stringList.get(0)); | |
| 289 } else if (func.equals("addMenuBarItem")) { | |
| 290 if (boolList.size() > 0) { | |
| 291 windows.get(windowID).addMenuBarItem(stringList.get(0), | |
| 292 stringList.get(1), | |
| 293 intList.get(0), | |
| 294 boolList.get(0)); | |
| 295 } else if (intList.size() > 0) { | |
| 296 windows.get(windowID).addMenuBarItem(stringList.get(0), | |
| 297 stringList.get(1), | |
| 298 intList.get(0)); | |
| 299 } else { | |
| 300 windows.get(windowID).addMenuBarItem(stringList.get(0), | |
| 301 stringList.get(1)); | |
| 302 } | |
| 303 } else if (func.equals("addPopupMenuItem")) { | |
| 304 if (stringList.size() == 4) { | |
| 305 windows.get(windowID).addPopupMenuItem(stringList.get(0), | |
| 306 stringList.get(1), | |
| 307 intList.get(0), | |
| 308 stringList.get(2), | |
| 309 stringList.get(3)); | |
| 310 } else { | |
| 311 windows.get(windowID).addPopupMenuItem(stringList.get(0), | |
| 312 stringList.get(1)); | |
| 313 } | |
| 314 } else if (func.equals("update")) { | |
| 315 windows.get(windowID).update(); | |
| 316 } else if (func.equals("showInputDialog")) { | |
| 317 windows.get(windowID).showInputDialog(stringList.get(0)); | |
| 318 } else if (func.equals("showYesNoDialog")) { | |
| 319 windows.get(windowID).showYesNoDialog(stringList.get(0)); | |
| 320 } else if (func.equals("zoomRectangle")) { | |
| 321 windows.get(windowID).zoomRectangle(intList.get(0), intList.get(1), | |
| 322 intList.get(2), intList.get(3)); | |
| 323 } else if (func.equals("readImage")) { | |
| 324 PImage image = SVImageHandler.readImage(intList.get(2), in); | |
| 325 windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); | |
| 326 } else if (func.equals("drawImage")) { | |
| 327 PImage image = new PImage(stringList.get(0)); | |
| 328 windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); | |
| 329 } else if (func.equals("destroy")) { | |
| 330 windows.get(windowID).destroy(); | |
| 331 } | |
| 332 // else for forward compatibility purposes, silently ignore any | |
| 333 // unrecognized function call. | |
| 334 } else { | |
| 335 // No colon. Check for create window. | |
| 336 if (idStrs[1].startsWith("= luajava.newInstance")) { | |
| 337 while (windows.size() <= windowID) { | |
| 338 windows.add(null); | |
| 339 } | |
| 340 windows.set(windowID, new SVWindow(stringList.get(1), | |
| 341 intList.get(0), intList.get(1), | |
| 342 intList.get(2), intList.get(3), | |
| 343 intList.get(4), intList.get(5), | |
| 344 intList.get(6))); | |
| 345 } | |
| 346 // else for forward compatibility purposes, silently ignore any | |
| 347 // unrecognized function call. | |
| 348 } | |
| 349 } else if (inputLine.startsWith("svmain")) { | |
| 350 // Startup or end. Startup is a lua bind, which is now a no-op. | |
| 351 if (inputLine.startsWith("svmain:exit")) { | |
| 352 exit(); | |
| 353 } | |
| 354 // else for forward compatibility purposes, silently ignore any | |
| 355 // unrecognized function call. | |
| 356 } | |
| 357 // else for forward compatibility purposes, silently ignore any | |
| 358 // unrecognized function call. | |
| 359 } | |
| 360 | |
| 361 /** Called from the client to make the server exit. */ | |
| 362 public static void exit() { | |
| 363 System.exit(0); | |
| 364 } | |
| 365 | |
| 366 /** | |
| 367 * The main function. Sets up LUA and the server connection and then calls the | |
| 368 * IOLoop. | |
| 369 */ | |
| 370 public static void main(String[] args) { | |
| 371 if (args.length > 0) { | |
| 372 SERVER_PORT = Integer.parseInt(args[0]); | |
| 373 } | |
| 374 windows = new ArrayList<SVWindow>(100); | |
| 375 intPattern = Pattern.compile("[0-9-][0-9]*"); | |
| 376 floatPattern = Pattern.compile("[0-9-][0-9]*\\.[0-9]*"); | |
| 377 | |
| 378 // Open a socket to listen on. | |
| 379 try (ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) { | |
| 380 System.out.println("Socket started on port " + SERVER_PORT); | |
| 381 | |
| 382 // Wait (blocking) for an incoming connection | |
| 383 socket = serverSocket.accept(); | |
| 384 System.out.println("Client connected"); | |
| 385 | |
| 386 // Setup the streams | |
| 387 out = new PrintStream(socket.getOutputStream(), true, "UTF-8"); | |
| 388 in = | |
| 389 new BufferedReader(new InputStreamReader(socket.getInputStream(), | |
| 390 "UTF8")); | |
| 391 } catch (IOException e) { | |
| 392 // Something went wrong and we were unable to set up a connection. This is | |
| 393 // pretty much a fatal error. | |
| 394 // Note: The server does not get restarted automatically if this happens. | |
| 395 e.printStackTrace(); | |
| 396 System.exit(1); | |
| 397 } | |
| 398 | |
| 399 // Enter the main program loop. | |
| 400 IOLoop(); | |
| 401 } | |
| 402 } |
