From 99e1f059521a9c3cb031350712ed09c1bfb194f7 Mon Sep 17 00:00:00 2001 From: "theraysmith@gmail.com" Date: Wed, 29 Jan 2014 02:24:32 +0000 Subject: [PATCH] Fixed bugs in scrollview and upgraded piccolo to 3.0 git-svn-id: https://tesseract-ocr.googlecode.com/svn/trunk@1026 d0cd1f9f-072b-0410-8dd7-cf729c803f20 --- java/Makefile.am | 6 +- java/com/google/scrollview/ScrollView.java | 43 +--- .../scrollview/events/SVEventHandler.java | 10 +- .../google/scrollview/ui/SVImageHandler.java | 233 +++--------------- java/com/google/scrollview/ui/SVWindow.java | 62 ++--- viewer/scrollview.cpp | 110 +++------ viewer/svutil.cpp | 4 +- 7 files changed, 122 insertions(+), 346 deletions(-) diff --git a/java/Makefile.am b/java/Makefile.am index a6d18ac369..3ed962dfcc 100644 --- a/java/Makefile.am +++ b/java/Makefile.am @@ -36,10 +36,10 @@ SCROLLVIEW_CLASSES = \ com/google/scrollview/ScrollView.class SCROLLVIEW_LIBS = \ - $(srcdir)/piccolo-1.2.jar \ - $(srcdir)/piccolox-1.2.jar + $(srcdir)/piccolo2d-core-3.0.jar \ + $(srcdir)/piccolo2d-extras-3.0.jar -CLASSPATH = $(srcdir)/piccolo-1.2.jar:$(srcdir)/piccolox-1.2.jar +CLASSPATH = $(srcdir)/piccolo2d-core-3.0.jar:$(srcdir)/piccolo2d-extras-3.0.jar ScrollView.jar : $(SCROLLVIEW_CLASSES) $(JAR) cf $@ com/google/scrollview/*.class \ diff --git a/java/com/google/scrollview/ScrollView.java b/java/com/google/scrollview/ScrollView.java index ef12114e70..66dd398feb 100644 --- a/java/com/google/scrollview/ScrollView.java +++ b/java/com/google/scrollview/ScrollView.java @@ -13,6 +13,7 @@ import com.google.scrollview.events.SVEvent; import com.google.scrollview.ui.SVImageHandler; import com.google.scrollview.ui.SVWindow; +import org.piccolo2d.nodes.PImage; import java.io.BufferedReader; import java.io.IOException; @@ -23,7 +24,6 @@ import java.util.ArrayList; import java.util.regex.Pattern; - /** * The ScrollView class is the main class which gets started from the command * line. It sets up LUA and handles the network processing. @@ -115,29 +115,10 @@ private static void IOLoop() { first = !first; } assert first; - } else if (SVImageHandler.getReadImageData() == false) { - // If we are currently not transmitting an image, process this - // normally. + } else { + // Process this normally. processInput(inputLine); } - // We are still transmitting image data, but there seems to be some - // command at the - // end of the message attached as well. Thus, we have to split it - // accordingly and - // first generate the image and afterwards process the remaining - // message. - else if (inputLine.length() > - SVImageHandler.getMissingRemainingBytes()) { - String luaCmd = inputLine.substring( - SVImageHandler.getMissingRemainingBytes()); - String imgData = inputLine.substring(0, - SVImageHandler.getMissingRemainingBytes()); - SVImageHandler.parseData(imgData); - processInput(luaCmd); - } else { // We are still in the middle of image data and have not - // reached the end yet. - SVImageHandler.parseData(inputLine); - } } } // Some connection error @@ -228,6 +209,9 @@ private static void parseArguments(String argList, /** Executes the LUA command parsed as parameter. */ private static void processInput(String inputLine) { + if (inputLine == null) { + return; + } // Execute a function encoded as a LUA statement! Yuk! if (inputLine.charAt(0) == 'w') { // This is a method call on a window. Parse it. @@ -298,11 +282,6 @@ private static void processInput(String inputLine) { } else if (func.equals("drawText")) { windows.get(windowID).drawText(intList.get(0), intList.get(1), stringList.get(0)); - } else if (func.equals("openImage")) { - windows.get(windowID).openImage(stringList.get(0)); - } else if (func.equals("drawImage")) { - windows.get(windowID).drawImage(stringList.get(0), - intList.get(0), intList.get(1)); } else if (func.equals("addMenuBarItem")) { if (boolList.size() > 0) { windows.get(windowID).addMenuBarItem(stringList.get(0), @@ -337,12 +316,12 @@ private static void processInput(String inputLine) { } else if (func.equals("zoomRectangle")) { windows.get(windowID).zoomRectangle(intList.get(0), intList.get(1), intList.get(2), intList.get(3)); - } else if (func.equals("createImage")) { - windows.get(windowID).createImage(stringList.get(0), intList.get(0), - intList.get(1), intList.get(2)); + } else if (func.equals("readImage")) { + PImage image = SVImageHandler.readImage(intList.get(2), in); + windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); } else if (func.equals("drawImage")) { - windows.get(windowID).drawImage(stringList.get(0), - intList.get(0), intList.get(1)); + PImage image = new PImage(stringList.get(0)); + windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); } else if (func.equals("destroy")) { windows.get(windowID).destroy(); } diff --git a/java/com/google/scrollview/events/SVEventHandler.java b/java/com/google/scrollview/events/SVEventHandler.java index 2ad4cd880c..4a4fa2686c 100644 --- a/java/com/google/scrollview/events/SVEventHandler.java +++ b/java/com/google/scrollview/events/SVEventHandler.java @@ -25,11 +25,11 @@ import javax.swing.Timer; -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.event.PBasicInputEventHandler; -import edu.umd.cs.piccolo.event.PInputEvent; -import edu.umd.cs.piccolo.nodes.PPath; +import org.piccolo2d.PCamera; +import org.piccolo2d.PNode; +import org.piccolo2d.event.PBasicInputEventHandler; +import org.piccolo2d.event.PInputEvent; +import org.piccolo2d.nodes.PPath; /** * The ScrollViewEventHandler takes care of any events which might happen on the diff --git a/java/com/google/scrollview/ui/SVImageHandler.java b/java/com/google/scrollview/ui/SVImageHandler.java index 8c685e0720..8eabd87045 100644 --- a/java/com/google/scrollview/ui/SVImageHandler.java +++ b/java/com/google/scrollview/ui/SVImageHandler.java @@ -1,5 +1,5 @@ // Copyright 2007 Google Inc. All Rights Reserved. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); You may not // use this file except in compliance with the License. You may obtain a copy of // the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by @@ -10,219 +10,60 @@ package com.google.scrollview.ui; -import edu.umd.cs.piccolo.nodes.PImage; +import org.piccolo2d.nodes.PImage; -import java.awt.image.BufferedImage; -import java.util.HashMap; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.xml.bind.DatatypeConverter; /** * The ScrollViewImageHandler is a helper class which takes care of image * processing. It is used to construct an Image from the message-stream and * basically consists of a number of utility functions to process the input * stream. - * + * * @author wanke@google.com */ public class SVImageHandler { - /** - * Stores a mapping from the name of the string to its actual image. It - * enables us to re-use images without having to load or transmit them again - */ - static HashMap images = new HashMap(); - - /** A global flag stating whether we are currently expecting Image data */ - static boolean readImageData = false; - - // TODO(wanke) Consider moving all this into an SVImage class. - /** These are all values belonging to the image which is currently being read */ - static String imageName = null; // Image name - static int bytesRead = 0; // Nr. of bytes already read - static int bpp = 0; // Bit depth - static int pictureArray[]; // The array holding the actual image - - static int bytePerPixel = 0; // # of used bytes to transmit a pixel (32 bpp - // -> 7 BPP) - static int width = 0; - static int height = 0; - /* All methods are static, so we forbid to construct SVImageHandler objects */ private SVImageHandler() { } /** - * Takes a binary input string (consisting of '0' and '1' characters) and - * converts it to an integer representation usable as image data. + * Reads size bytes from the stream in and interprets it as an image file, + * encoded as png, and then text-encoded as base 64, returning the decoded + * bitmap. + * + * @param size The size of the image file. + * @param in The input stream from which to read the bytes. */ - private static int[] processBinaryImage(String inputLine) { - int BLACK = 0; - int WHITE = Integer.MAX_VALUE; - - int[] imgData = new int[inputLine.length()]; - - for (int i = 0; i < inputLine.length(); i++) { - if (inputLine.charAt(i) == '0') { - imgData[i] = WHITE; - } else if (inputLine.charAt(i) == '1') { - imgData[i] = BLACK; - } // BLACK is default anyway - else { // Something is wrong: We did get unexpected data - System.out.println("Error: unexpected non-image-data: (" - + SVImageHandler.bytesRead + "," + inputLine.length() + "," - + (SVImageHandler.height * SVImageHandler.width) + ")"); - System.exit(1); + public static PImage readImage(int size, BufferedReader in) { + char[] charbuffer = new char[size]; + int numRead = 0; + while (numRead < size) { + int newRead = -1; + try { + newRead = in.read(charbuffer, numRead, size - numRead); + } catch (IOException e) { + System.out.println("Failed to read image data from socket" + e.getMessage()); } + if (newRead < 0) { + return null; + } + numRead += newRead; } - return imgData; - } - - /** - * Takes an input string with pixel depth of 8 (represented by 2 bytes in - * hexadecimal format, e.g. FF for white) and converts it to an - * integer representation usable as image data - */ - private static int[] processGrayImage(String inputLine) { - int[] imgData = new int[inputLine.length() / 2]; - // Note: This is really inefficient, splitting it 2-byte-arrays in one pass - // would be wa faster than substring everytime. - for (int i = 0; i < inputLine.length(); i +=2) { - String s = inputLine.substring(i, i+1); - imgData[i] = Integer.parseInt(s, 16); - } - - return imgData; - } - - /** - * Takes an input string with pixel depth of 32 (represented by HTML-like - * colors in hexadecimal format, e.g. #00FF00 for green) and converts it to an - * integer representation usable as image data - */ - private static int[] process32bppImage(String inputLine) { - - String[] strData = inputLine.split("#"); - int[] imgData = new int[strData.length - 1]; - - for (int i = 1; i < strData.length; i++) { - imgData[i - 1] = Integer.parseInt(strData[i], 16); - } - - return imgData; - } - - /** - * Called when all image data is transmitted. Generates the actual image used - * by java and puts it into the images-hashmap. - */ - private static void closeImage() { - - BufferedImage bi = null; - if (bpp == 1) { - bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); - } else if (bpp == 8) { - bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); - } else if (bpp == 32) { - bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - } else { - System.out.println("Unsupported Image Type: " + bpp + " bpp"); - System.exit(1); - } - - bi.setRGB(0, 0, width, height, pictureArray, 0, width); - - PImage img = new PImage(bi); - - images.put(imageName, img); - - imageName = null; - readImageData = false; - - System.out.println("(server, #Bytes:" + bytesRead + ") Image Completed"); - - bytesRead = 0; - bpp = 0; - } - - /** Starts creation of a new image. */ - public static void createImage(String name, int width, int height, - int bitsPerPixel) { - // Create buffered image that does not support transparency - bpp = bitsPerPixel; - if (bpp == 1) { - bytePerPixel = 1; - } else if (bpp == 8) { - bytePerPixel = 2; - } else if (bpp == 32) { - bytePerPixel = 7; - } else { - throw new IllegalArgumentException( - "bpp should be 1 (binary), 8 (gray) or 32 (argb), is " + bpp); - } - if (imageName != null) { - throw new IllegalArgumentException("Image " + imageName + " already opened!"); - } - else { - imageName = name; - bytesRead = 0; - readImageData = true; - SVImageHandler.height = height; - SVImageHandler.width = width; - pictureArray = new int[width * height]; - } - - System.out.println("Processing Image with " + bpp + " bpp, size " + width + "x" + height); - } - - /** - * Opens an Image from location. This means the image does not have to be - * actually transfered over the network. Thus, it is a lot faster than using - * the createImage method. - * - * @param location The (local) location from where to open the file. This is - * also the internal name associated with the image (if you want to draw it). - */ - public static void openImage(String location) { - PImage img = new PImage(location); - images.put(location, img); - } - - /** Find the image corresponding to a given name */ - public static PImage getImage(String name) { - return images.get(name); - } - - /** - * Gets called while currently reading image data. Decides, how to process it - * (which image type, whether all data is there). - */ - public static void parseData(String inputLine) { - int[] data = null; - - if (bpp == 1) { - data = processBinaryImage(inputLine); - } else if (bpp == 8) { - data = processGrayImage(inputLine); - } else if (bpp == 32) { - data = process32bppImage(inputLine); - } else { - System.out.println("Unsupported Bit Type: " + bpp); - } - - System.arraycopy(data, 0, pictureArray, bytesRead, data.length); - bytesRead += data.length; - - // We have read all image data - close the image - if (bytesRead == (height * width)) { - closeImage(); + // Convert the character data to binary. + byte[] binarydata = DatatypeConverter.parseBase64Binary(new String(charbuffer)); + // Convert the binary data to a byte stream and parse to image. + ByteArrayInputStream byteStream = new ByteArrayInputStream(binarydata); + try { + PImage img = new PImage(ImageIO.read(byteStream)); + return img; + } catch (IOException e) { + System.out.println("Failed to decode image data from socket" + e.getMessage()); } - } - - /** Returns whether we a currently reading image data or not */ - public static boolean getReadImageData() { - return readImageData; - } - - /** Computes how many bytes of the image data are still missing */ - public static int getMissingRemainingBytes() { - return (height * width * bytePerPixel) - bytesRead; + return null; } } diff --git a/java/com/google/scrollview/ui/SVWindow.java b/java/com/google/scrollview/ui/SVWindow.java index c41fb2f570..2e3a354e3a 100644 --- a/java/com/google/scrollview/ui/SVWindow.java +++ b/java/com/google/scrollview/ui/SVWindow.java @@ -14,19 +14,18 @@ import com.google.scrollview.events.SVEvent; import com.google.scrollview.events.SVEventHandler; import com.google.scrollview.events.SVEventType; -import com.google.scrollview.ui.SVImageHandler; import com.google.scrollview.ui.SVMenuBar; import com.google.scrollview.ui.SVPopupMenu; -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PCanvas; -import edu.umd.cs.piccolo.PLayer; +import org.piccolo2d.PCamera; +import org.piccolo2d.PCanvas; +import org.piccolo2d.PLayer; -import edu.umd.cs.piccolo.nodes.PImage; -import edu.umd.cs.piccolo.nodes.PPath; -import edu.umd.cs.piccolo.nodes.PText; -import edu.umd.cs.piccolo.util.PPaintContext; -import edu.umd.cs.piccolox.swing.PScrollPane; +import org.piccolo2d.nodes.PImage; +import org.piccolo2d.nodes.PPath; +import org.piccolo2d.nodes.PText; +import org.piccolo2d.util.PPaintContext; +import org.piccolo2d.extras.swing.PScrollPane; import java.awt.BasicStroke; import java.awt.BorderLayout; @@ -136,21 +135,6 @@ public void clear() { layer.removeAllChildren(); } - /** - * Start setting up a new image. The server will now expect image data until - * the image is complete. - * - * @param internalName The unique name of the new image - * @param width Image width - * @param height Image height - * @param bitsPerPixel The bit depth (currently supported: 1 (binary) and 32 - * (ARGB)) - */ - public void createImage(String internalName, int width, int height, - int bitsPerPixel) { - SVImageHandler.createImage(internalName, width, height, bitsPerPixel); - } - /** * Start setting up a new polyline. The server will now expect * polyline data until the polyline is complete. @@ -168,8 +152,20 @@ public void createPolyline(int length) { * Draw the now complete polyline. */ public void drawPolyline() { - PPath pn = PPath.createPolyline(ScrollView.polylineXCoords, - ScrollView.polylineYCoords); + int numCoords = ScrollView.polylineXCoords.length; + if (numCoords < 2) { + return; + } + PPath pn = PPath.createLine(ScrollView.polylineXCoords[0], + ScrollView.polylineYCoords[0], + ScrollView.polylineXCoords[1], + ScrollView.polylineYCoords[1]); + pn.reset(); + pn.moveTo(ScrollView.polylineXCoords[0], ScrollView.polylineYCoords[0]); + for (int p = 1; p < numCoords; ++p) { + pn.lineTo(ScrollView.polylineXCoords[p], ScrollView.polylineYCoords[p]); + } + pn.closePath(); ScrollView.polylineSize = 0; pn.setStrokePaint(currentPenColor); pn.setPaint(null); // Don't fill the polygon - this is just a polyline. @@ -323,8 +319,7 @@ public void drawEllipse(int x, int y, int width, int height) { * memory, so if you intend to redraw an image, you do not have to use * createImage again. */ - public void drawImage(String internalName, int x_pos, int y_pos) { - PImage img = SVImageHandler.getImage(internalName); + public void drawImage(PImage img, int x_pos, int y_pos) { img.setX(x_pos); img.setY(y_pos); layer.addChild(img); @@ -629,15 +624,4 @@ public void destroy() { setVisible(false); // dispose(); } - - /** - * Open an image from a given file location and store it in memory. Pro: - * Faster than createImage. Con: Works only on the local file system. - * - * @param filename The path to the image. - */ - public void openImage(String filename) { - SVImageHandler.openImage(filename); - } - } diff --git a/viewer/scrollview.cpp b/viewer/scrollview.cpp index 5a8bc4ff2c..bcf3a75b89 100644 --- a/viewer/scrollview.cpp +++ b/viewer/scrollview.cpp @@ -172,6 +172,8 @@ void* ScrollView::MessageReceiver(void* a) { sv->Signal(); sv->Signal(); } + } else { + delete cur; // Applied to no window. } svmap_mu->Unlock(); @@ -382,6 +384,9 @@ ScrollView::~ScrollView() { delete mutex_; delete semaphore_; delete points_; + for (int i = 0; i < SVET_COUNT; i++) { + delete event_table_[i]; + } #endif // GRAPHICS_DISABLED } @@ -766,77 +771,44 @@ void ScrollView::ZoomToRectangle(int x1, int y1, int x2, int y2) { // Send an image of type Pix. void ScrollView::Image(struct Pix* image, int x_pos, int y_pos) { - int width = image->w; - int height = image->h; - l_uint32 bpp = image->d; - ++image_index_; - // PIX* do not have a unique identifier/name associated, so name them "lept". - SendMsg("createImage('lept%d',%d,%d,%d)", image_index_, width, height, bpp); - - if (bpp == 32) { - Transfer32bppImage(image); - } else if (bpp == 8) { - TransferGrayImage(image); - } else if (bpp == 1) { - TransferBinaryImage(image); - } - // PIX* do not have a unique identifier/name associated, so name them "lept". - SendMsg("drawImage('lept%d',%d,%d)", image_index_, x_pos, y_pos); -} - -// Sends each pixel as hex value like html, e.g. #00FF00 for green. -void ScrollView::Transfer32bppImage(PIX* image) { - int ppL = pixGetWidth(image); - int h = pixGetHeight(image); - int wpl = pixGetWpl(image); - int transfer_size= ppL * 7 + 2; - char* pixel_data = new char[transfer_size]; - for (int y = 0; y < h; ++y) { - l_uint32* data = pixGetData(image) + y*wpl; - for (int x = 0; x < ppL; ++x, ++data) { - snprintf(&pixel_data[x*7], 7, "#%.2x%.2x%.2x", - GET_DATA_BYTE(data, COLOR_RED), - GET_DATA_BYTE(data, COLOR_GREEN), - GET_DATA_BYTE(data, COLOR_BLUE)); - } - pixel_data[transfer_size - 2] = '\n'; - pixel_data[transfer_size - 1] = '\0'; - SendRawMessage(pixel_data); - } - delete[] pixel_data; -} - -// Sends for each pixel either '1' or '0'. -void ScrollView::TransferGrayImage(PIX* image) { - char* pixel_data = new char[image->w * 2 + 2]; - for (int y = 0; y < image->h; y++) { - l_uint32* data = pixGetData(image) + y * pixGetWpl(image); - for (int x = 0; x < image->w; x++) { - snprintf(&pixel_data[x*2], 2, "%.2x", (GET_DATA_BYTE(data, x))); - pixel_data[image->w * 2] = '\n'; - pixel_data[image->w * 2 + 1] = '\0'; - SendRawMessage(pixel_data); - } - } - delete [] pixel_data; -} - -// Sends for each pixel either '1' or '0'. -void ScrollView::TransferBinaryImage(PIX* image) { - char* pixel_data = new char[image->w + 2]; - for (int y = 0; y < image->h; y++) { - l_uint32* data = pixGetData(image) + y * pixGetWpl(image); - for (int x = 0; x < image->w; x++) { - if (GET_DATA_BIT(data, x)) - pixel_data[x] = '1'; - else - pixel_data[x] = '0'; + l_uint8* data; + size_t size; + pixWriteMem(&data, &size, image, IFF_PNG); + int base64_len = (size + 2) / 3 * 4; + SendMsg("readImage(%d,%d,%d)", x_pos, y_pos, base64_len); + // Base64 encode the data. + const char kBase64Table[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + }; + char* base64 = new char[base64_len + 1]; + memset(base64, '=', base64_len); + base64[base64_len] = '\0'; + int remainder = 0; + int bits_left = 0; + int code_len = 0; + for (int i = 0; i < size; ++i) { + int code = (data[i] >> (bits_left + 2)) | remainder; + base64[code_len++] = kBase64Table[code & 63]; + bits_left += 2; + remainder = data[i] << (6 - bits_left); + if (bits_left == 6) { + base64[code_len++] = kBase64Table[remainder & 63]; + bits_left = 0; + remainder = 0; } - pixel_data[image->w] = '\n'; - pixel_data[image->w + 1] = '\0'; - SendRawMessage(pixel_data); } - delete [] pixel_data; + if (bits_left > 0) + base64[code_len++] = kBase64Table[remainder & 63]; + SendRawMessage(base64); + delete [] base64; + free(data); } // Escapes the ' character with a \, so it can be processed by LUA. diff --git a/viewer/svutil.cpp b/viewer/svutil.cpp index 5aa34e5f57..a660b0f00a 100644 --- a/viewer/svutil.cpp +++ b/viewer/svutil.cpp @@ -297,12 +297,12 @@ static std::string ScrollViewCommand(std::string scrollview_path) { // Also the path has to be separated by ; on windows and : otherwise. #ifdef _WIN32 const char* cmd_template = "-Djava.library.path=%s -cp %s/ScrollView.jar;" - "%s/piccolo-1.2.jar;%s/piccolox-1.2.jar" + "%s/piccolo2d-core-3.0.jar:%s/piccolo2d-extras-3.0.jar" " com.google.scrollview.ScrollView"; #else const char* cmd_template = "-c \"trap 'kill %%1' 0 1 2 ; java " "-Xms1024m -Xmx2048m -Djava.library.path=%s -cp %s/ScrollView.jar:" - "%s/piccolo-1.2.jar:%s/piccolox-1.2.jar" + "%s/piccolo2d-core-3.0.jar:%s/piccolo2d-extras-3.0.jar" " com.google.scrollview.ScrollView" " & wait\""; #endif