All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sikuli.script.Image Maven / Gradle / Ivy

There is a newer version: 2.0.5
Show newest version
/*
 * Copyright (c) 2010-2019, sikuli.org, sikulix.com - MIT license
 */
package org.sikuli.script;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;

import org.apache.commons.io.FilenameUtils;
import org.sikuli.basics.Debug;
import org.sikuli.basics.FileManager;
import org.sikuli.basics.Settings;

/**
 * This class hides the complexity behind image names given as string.
 * 
Image does not have public nor public constructors: use create() *
It's companion is {@link ImagePath} that maintains a list of places, where image files are * loaded from.
* An Image object:
* - has a name, either given or taken from the basename
* - keeps it's in memory buffered image in a configurable cache avoiding reload * from source
* - remembers, where it was found when searched the last time
* - can be sourced from the filesystem, from jars, from the web and from other * in memory images
* - will have features for basic image manipulation and presentation
* - contains the stuff to communicate with the underlying OpenCV based search * engine
*

* This class maintains
* - a list of all images ever loaded in this session with their source * reference and a ref to the image object
* - a list of all images currently having their content in memory (buffered * image) (managed as a configurable cache)
* The caching can be configured using {@link Settings#setImageCache(int)} */ public class Image { private static String me = "Image: "; private static int lvl = 3; private static void log(int level, String message, Object... args) { Debug.logx(level, me + message, args); } private static List images = Collections.synchronizedList(new ArrayList()); private static Map imageFiles = Collections.synchronizedMap(new HashMap()); private static Map imageNames = Collections.synchronizedMap(new HashMap()); // public static Image getDefaultInstance4py() { return new Image(new Screen().capture()); } private Image() { } private Image(String fname, URL fURL) { init(fname, fURL); } private Image(URL fURL) { if ("file".equals(fURL.getProtocol())) { init(fURL.getPath(), fURL); } else { init(getNameFromURL(fURL), fURL); } } private void init(String fileName, URL fURL) { imageName = fileName; if (imageName.isEmpty() || fURL == null) { return; } fileURL = fURL; if (ImagePath.isImageBundled(fURL)) { imageIsBundled = true; imageName = new File(imageName).getName(); } load(); } public static void reinit(Image img) { URL fURL = null; File imgFile = new File(img.getName()); if (imgFile.isAbsolute()) { if (imgFile.exists()) { fURL = FileManager.makeURL(img.getName()); } } else { fURL = imageNames.get(img.getName()); if (fURL == null) { fURL = ImagePath.find(img.getName()); } } if (fURL != null) { img.init(img.getName(), fURL); } } private Image copy() { Image imgTarget = new Image(); imgTarget.setName(imageName); imgTarget.setFileURL(fileURL); imgTarget.setBimg(bimg); imgTarget.setIsAbsolute(imageIsAbsolute); imgTarget.setIsText(imageIsText); imgTarget.setIsBundled(imageIsBundled); imgTarget.setLastSeen(getLastSeen(), getLastSeenScore()); imgTarget.setHasIOException(hasIOException()); if (isPattern()) { imgTarget.setSimilarity(similarity); imgTarget.setOffset(offset); imgTarget.setWaitAfter(waitAfter); imgTarget.setIsPattern(true); } return imgTarget; } /** * create a new image from a buffered image
* can only be reused with the object reference * * @param img BufferedImage */ public Image(BufferedImage img) { this(img, null); } /** * create a new image from a buffered image
* giving it a descriptive name for printout and logging
* can only be reused with the object reference * * @param img BufferedImage * @param name descriptive name */ public Image(BufferedImage img, String name) { imageName = isBImg; if (name != null) { imageName += name; } bimg = img; bwidth = bimg.getWidth(); bheight = bimg.getHeight(); log(lvl, "BufferedImage: (%d, %d)%s", bwidth, bheight, (name == null ? "" : " with name: " + name)); } /** * create a new image from a Sikuli ScreenImage (captured)
* can only be reused with the object reference * * @param img ScreenImage */ public Image(ScreenImage img) { this(img.getImage(), null); } /** * create a new image from a Sikuli ScreenImage (captured)
* giving it a descriptive name for printout and logging
* can only be reused with the object reference * * @param img ScreenImage * @param name descriptive name */ public Image(ScreenImage img, String name) { this(img.getImage(), name); } /** * check whether image is available for Finder.find()
* This is for backward compatibility
* The new ImageFinder uses isUsable() * * @return true if lodable from file or is an in memory image */ public boolean isValid() { return fileURL != null || getName().contains(isBImg); } /** * checks, wether the Image can be used with the new ImageFinder * * @return true/false */ public boolean isUseable() { return isValid() || imageIsPattern; } @Override public String toString() { return String.format( (imageName != null ? imageName : "__UNKNOWN__") + ": (%dx%d)", bwidth, bheight) + (lastSeen == null ? "" : String.format(" seen at (%d, %d) with %.2f", lastSeen.x, lastSeen.y, lastScore)); } //
// /** * @return the image's absolute filename or null if jar, http or in memory * image */ public String getFilename() { if (fileURL != null && "file".equals(fileURL.getProtocol())) { return new File(fileURL.getPath()).getAbsolutePath(); } else { return imageName; } } private boolean bHasIOException = false; public boolean hasIOException() { return bHasIOException; } public void setHasIOException(boolean state) { bHasIOException = state; } /** * Get the image's descriptive name * * @return the name */ public String getName() { if (isText()) { return imageNameGiven; } return imageName; } public Image setName(String imageName) { this.imageName = imageName; return this; } private String imageName = null; private String imageNameGiven = null; // // /** * @return the evaluated url for this image (might be null) */ public URL getURL() { return fileURL; } public Image setFileURL(URL fileURL) { this.fileURL = fileURL; return this; } private URL fileURL = null; private static Image get(URL imgURL) { return imageFiles.get(imgURL); } private static String getNameFromURL(URL fURL) { //TODO add handling for http if ("jar".equals(fURL.getProtocol())) { int n = fURL.getPath().lastIndexOf(".jar!/"); int k = fURL.getPath().substring(0, n).lastIndexOf("/"); if (n > -1) { return "JAR:" + fURL.getPath().substring(k + 1, n) + fURL.getPath().substring(n + 5); } } return "???:" + fURL.getPath(); } public boolean isFile() { if (isValid()) { URL furl = getURL(); if ("file".equals(furl.getProtocol())) { return true; } } return false; } private boolean imageIsAbsolute = false; /** * @return true if image was given with absolute filepath */ public boolean isAbsolute() { return imageIsAbsolute; } public Image setIsAbsolute(boolean val) { imageIsAbsolute = val; return this; } // // public Image setBimg(BufferedImage bimg) { this.bimg = bimg; if (bimg != null) { bwidth = bimg.getWidth(); bheight = bimg.getHeight(); bsize = bimg.getData().getDataBuffer().getSize(); } else { bsize = 0; bwidth = -1; bheight = -1; } return this; } private BufferedImage bimg = null; private int bsize = 0; private int bwidth = -1; private int bheight = -1; public static BufferedImage getSubimage(BufferedImage bimg, Rectangle rect) { return bimg.getSubimage(rect.x, rect.y, (int) rect.getWidth(), (int) rect.getHeight()); } /** * return the image's BufferedImage (load it if not in cache) * * @return BufferedImage (might be null) */ public BufferedImage get() { if (bimg != null) { if (fileURL == null) { log(lvl + 1, "getImage inMemory: %s", imageName); } else { log(lvl + 1, "getImage from cache: %s", imageName); } return bimg; } else { return load(); } } /** * @return size of image */ public Dimension getSize() { return new Dimension(bwidth, bheight); } private int getKB() { if (bimg == null) { return 0; } return (int) bsize / KB; } /** * resize the loaded image with factor using Graphics2D.drawImage * * @param factor resize factor * @return a new BufferedImage resized (width*factor, height*factor) */ public BufferedImage resize(float factor) { int type; return resize(get(), factor); } public static BufferedImage resize(BufferedImage bimg, float factor) { int type = bimg.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bimg.getType(); int width = (int) (bimg.getWidth() * factor); int height = (int) (bimg.getHeight() * factor); BufferedImage resizedImage = new BufferedImage(width, height, type); Graphics2D g = resizedImage.createGraphics(); g.drawImage(bimg, 0, 0, width, height, null); g.dispose(); return resizedImage; } /** * create a sub image from this image * * @param x pixel column * @param y pixel row * @param w width * @param h height * @return the new image */ public Image getSub(int x, int y, int w, int h) { BufferedImage bi = createBufferedImage(w, h); Graphics2D g = bi.createGraphics(); g.drawImage(get().getSubimage(x, y, w, h), 0, 0, null); g.dispose(); return new Image(bi); } private static BufferedImage createBufferedImage(int w, int h) { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); int[] nBits = {8, 8, 8, 8}; ColorModel cm = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); SampleModel sm = cm.createCompatibleSampleModel(w, h); DataBufferByte db = new DataBufferByte(w * h * 4); WritableRaster r = WritableRaster.createWritableRaster(sm, db, new Point(0, 0)); BufferedImage bm = new BufferedImage(cm, r, false, null); return bm; } // // private boolean imageIsText = false; /** * @return true if the given image name did not give a valid image so it might * be text to search */ public boolean isText() { return imageIsText; } public Image setIsText(boolean val) { imageIsText = val; return this; } public String getNameAsText() { return imageNameGiven; } // // private boolean imageIsBundled = false; private Image setIsBundled(boolean imageIsBundled) { this.imageIsBundled = imageIsBundled; return this; } /** * INTERNAL USE: image is contained in a bundle (.sikuli) * * @return true/false */ public boolean isBundled() { return imageIsBundled; } // // private boolean imageIsPattern = false; /** * true if this image contains pattern aspects
* only useable with the new ImageFinder * * @return true if yes, false otherwise */ public boolean isPattern() { return imageIsPattern; } public Image setIsPattern(boolean imageIsPattern) { this.imageIsPattern = imageIsPattern; return this; } private Location offset = new Location(0, 0); /** * Get the value of offset * * @return the value of offset */ public Location getOffset() { return offset; } /** * Set the value of offset * * @param offset new value of offset * @return the image */ public Image setOffset(Location offset) { this.offset = offset; return this; } private double similarity = Settings.MinSimilarity; /** * Get the value of similarity * * @return the value of similarity */ public double getSimilarity() { return similarity; } /** * Set the value of similarity * * @param similarity new value of similarity * @return the image */ public Image setSimilarity(double similarity) { this.similarity = similarity; return this; } //
// /** * create a sub image from this image * * @param part (the constants Region.XXX as used with {@link Region#get(int)}) * @return the sub image */ public Image getSub(int part) { Rectangle r = Region.getRectangle(new Rectangle(0, 0, getSize().width, getSize().height), part); return getSub(r.x, r.y, r.width, r.height); } /** * create a new Image as copy of the given Image * * @param imgSrc given Image * @return new Image */ public static Image create(Image imgSrc) { return imgSrc.copy(); } /** * create a new image from a filename
* file ending .png is added if missing (currently valid: png, jpg, jpeg)
* relative filename: [...path.../]name[.png] is searched on current image path
* absolute filename is taken as is * if image exists, it is loaded to cache
* already loaded image with same name (given path) is reused (taken from cache)
*

* if image not found, it might be a text to be searched (imageIsText = true) * * @param fName image filename * @return an Image object (might not be valid - check with isValid()) */ public static Image create(String fName) { Image img = get(fName); return createImageValidate(img); } /** * create a new Image with Pattern aspects from an existing Pattern * * @param p a Pattern * @return the new Image */ public static Image create(Pattern p) { Image img = p.getImage().copy(); img.setIsPattern(true); img.setSimilarity(p.getSimilar()); img.setOffset(p.getTargetOffset()); img.setWaitAfter(p.getTimeAfter()); return img; } /** * create a new image from the given url
* file ending .png is added if missing
* filename: ...url-path.../name[.png] is loaded from the url and and cached *
* already loaded image with same url is reused (reference) and taken from * cache * * @param url image file URL * @return the image */ public static Image create(URL url) { Image img = get(url); if (img == null) { img = new Image(url); } return createImageValidate(img); } public static Image getImageFromTarget(PSI target) { if (target instanceof Pattern) { return ((Pattern) target).getImage(); } else if (target instanceof String) { Image img = get((String) target); img = createImageValidate(img); return img; } else if (target instanceof Image) { return (Image) target; } else if (target instanceof ScreenImage) { return new Image(((ScreenImage) target).getImage()); } else { throw new RuntimeException(String.format("SikuliX: find, wait, exists: invalid parameter: %s", target)); } } /** * FOR INTERNAL USE: from IDE - suppresses load error message * * @param fName image filename * @return this */ public static Image createThumbNail(String fName) { Image img = get(fName); return createImageValidate(img); } private static Image createImageValidate(Image img) { if (img == null) { return new Image("", null); } if (!img.isValid()) { if (Settings.OcrTextSearch || Settings.SwitchToText) { if (isValidImageFilename(img.getName())) { img.setIsText(false); } else { img.setIsText(true); } } else { log(-1, "Image not valid, but TextSearch is switched off!"); } } return img; } public static boolean isValidImageFilename(String fname) { String validEndings = ".png.jpg.jpeg"; String ending = FilenameUtils.getExtension(fname); return !ending.isEmpty() && validEndings.contains(ending.toLowerCase()); } public static String getValidImageFilename(String fname) { if (isValidImageFilename(fname)) { return fname; } return fname + ".png"; } // // private static final int KB = 1024; private static final int MB = KB * KB; private final static String isBImg = "__BufferedImage__"; private static long currentMemory = 0; private static synchronized long currentMemoryChange(long size, long max) { long maxMemory = max; if (max < 0) { maxMemory = Settings.getImageCache() * MB; currentMemory += size; } if (currentMemory > maxMemory) { Image first; while (images.size() > 0 && currentMemory > maxMemory) { first = images.remove(0); first.bimg = null; currentMemory -= first.bsize; } if (maxMemory == 0) { currentMemory = 0; } else { currentMemory = Math.max(0, currentMemory); } } if (size < 0) { currentMemory = Math.max(0, currentMemory); } return currentMemory; } private static long currentMemoryUp(long size) { return currentMemoryChange(size, -1); } private static long currentMemoryDown(long size) { currentMemory -= size; currentMemory = Math.max(0, currentMemory); return currentMemoryChange(-size, -1); } private static long currentMemoryDownUp(int sizeOld, int sizeNew) { currentMemoryDown(sizeOld); return currentMemoryUp(sizeNew); } private static boolean isCaching() { return Settings.getImageCache() > 0; } public static void clearCache(int maxSize) { currentMemoryChange(0, maxSize); } public static void purge() { purge(ImagePath.getBundle()); } public static void purge(ImagePath.PathEntry path) { if (path == null) { return; } purge(path.pathURL); } private static synchronized void purge(URL pathURL) { List imagePurgeList = new ArrayList<>(); List imageNamePurgeList = new ArrayList<>(); URL imgURL; Image img; log(lvl + 1, "purge: ImagePath: %s", pathURL.getPath()); Iterator> it = imageFiles.entrySet().iterator(); Map.Entry entry; while (it.hasNext()) { entry = it.next(); imgURL = entry.getKey(); if (imgURL.toString().startsWith(pathURL.toString())) { log(lvl + 1, "purge: URL: %s", imgURL.toString()); img = entry.getValue(); imagePurgeList.add(img); imageNamePurgeList.add(img.imageName); it.remove(); } } if (!imagePurgeList.isEmpty()) { Iterator bit = images.iterator(); while (bit.hasNext()) { img = bit.next(); if (imagePurgeList.contains(img)) { bit.remove(); log(lvl + 1, "purge: bimg: %s", img); currentMemoryDown(img.bsize); } } } for (String name : imageNamePurgeList) { imageNames.remove(name); } } private static void unCache(URL imgURL) { Image img = imageFiles.get(imgURL); if (img == null) { return; } currentMemoryDown(img.bsize); img.setBimg(null); images.remove(img); } //TODO make obsolete public static void unCache(String fileName) { unCache(FileManager.makeURL(new File(fileName).getAbsolutePath())); } /** * Print the current state of the cache */ public static void dump() { dump(0); } /** * Print the current state of the cache, verbosity depends on debug level * * @param lvl debug level used here */ public static void dump(int lvl) { log(lvl, "--- start of Image dump ---"); ImagePath.dump(lvl); log(lvl, "ImageFiles entries: %d", imageFiles.size()); Iterator> it = imageFiles.entrySet().iterator(); Map.Entry entry; while (it.hasNext()) { entry = it.next(); log(lvl, entry.getKey().toString()); } log(lvl, "ImageNames entries: %d", imageNames.size()); Iterator> nit = imageNames.entrySet().iterator(); Map.Entry name; while (nit.hasNext()) { name = nit.next(); log(lvl, "%s %d KB (%s)", new File(name.getKey()).getName(), imageFiles.get(name.getValue()).getKB(), name.getValue()); } if (Settings.getImageCache() == 0) { log(lvl, "Cache state: switched off!"); } else { log(lvl, "Cache state: Max %d MB (entries: %d used: %d %% %d KB)", Settings.getImageCache(), images.size(), (int) (100 * currentMemory / (Settings.getImageCache() * MB)), (int) (currentMemory / KB)); } log(lvl, "--- end of Image dump ---"); } /** * clears all caches (should only be needed for debugging) */ public static void reset() { clearCache(0); imageNames.clear(); imageFiles.clear(); } public File remove() { URL furl = null; if (isFile()) { furl = getURL(); unCache(furl); return new File(furl.getPath()); } return null; } public void delete() { File fImg = remove(); if (null != fImg) FileManager.deleteFileOrFolder(fImg); } private String hasBackup = ""; public boolean backup() { if (isValid()) { File fOrg = new File(fileURL.getPath()); File fBack = new File(fOrg.getParentFile(), "_BACKUP_" + fOrg.getName()); if (FileManager.xcopy(fOrg, fBack)) { hasBackup = fBack.getPath(); log(lvl, "backup: %s created", fBack.getName()); return true; } log(-1, "backup: %s did not work", fBack.getName()); } return false; } public boolean restore() { if (!hasBackup.isEmpty()) { File fBack = new File(hasBackup); File fOrg = new File(hasBackup.replace("_BACKUP_", "")); if (FileManager.xcopy(fBack, fOrg)) { log(lvl, "restore: %s restored", fOrg.getName()); FileManager.deleteFileOrFolder(fBack); hasBackup = ""; return true; } log(-1, "restore: %s did not work", fBack.getName()); } return false; } // // /** * FOR INTERNAL USE: tries to get the image from the cache, if not cached yet: * create and load a new image * * @param fName image filename * @return this */ private static Image get(String fName) { if (fName == null || fName.isEmpty()) { return null; } Image image = null; if (fName.startsWith("\t") && fName.endsWith("\t")) { fName = fName.substring(1, fName.length() - 1); image = new Image(); image.setIsText(true); } else { URL imageURL = null; String imageFileName = getValidImageFilename(fName); if (imageFileName.isEmpty()) { log(-1, "not a valid image type: " + fName); imageFileName = fName; } File imageFile = new File(imageFileName); if (imageFile.isAbsolute() && imageFile.exists()) { try { imageURL = new URL("file", null, imageFile.getPath()); } catch (MalformedURLException e) { } } else { imageURL = imageNames.get(imageFileName); if (imageURL == null) { imageURL = ImagePath.find(imageFileName); } } if (imageURL != null) { image = imageFiles.get(imageURL); if (image != null && null == imageNames.get(image.imageName)) { imageNames.put(image.imageName, imageURL); } } if (image == null) { image = new Image(imageFileName, imageURL); image.setIsAbsolute(imageFile.isAbsolute()); } else { if (image.bimg != null) { log(3, "reused: %s (%s)", image.imageName, image.fileURL); } else { if (Settings.getImageCache() > 0) { image.load(); } } } } image.imageNameGiven = fName; return image; } private BufferedImage load() { BufferedImage bImage = null; if (fileURL != null) { bimg = null; try { bImage = ImageIO.read(fileURL); } catch (Exception e) { log(-1, "load: failed: %s", fileURL); bHasIOException = true; fileURL = null; return null; } if (imageName != null) { imageFiles.put(fileURL, this); imageNames.put(imageName, fileURL); bwidth = bImage.getWidth(); bheight = bImage.getHeight(); bsize = bImage.getData().getDataBuffer().getSize(); log(lvl, "loaded: %s (%s)", imageName, fileURL); if (isCaching()) { int maxMemory = Settings.getImageCache() * MB; currentMemoryUp(bsize); bimg = bImage; images.add(this); log(lvl, "cached: %s (%d KB) (# %d KB %d -- %d %% of %d MB)", imageName, getKB(), images.size(), (int) (currentMemory / KB), (int) (100 * currentMemory / maxMemory), (int) (maxMemory / MB)); } } else { log(-1, "invalid! not loaded! %s", fileURL); } } return bImage; } private BufferedImage loadAgain() { BufferedImage bImage = null; if (fileURL != null) { bimg = null; try { bImage = ImageIO.read(fileURL); } catch (Exception e) { log(-1, "loadAgain: failed: %s", fileURL); bHasIOException = true; imageFiles.remove(fileURL); return null; } imageFiles.put(fileURL, this); imageNames.put(imageName, fileURL); bwidth = bImage.getWidth(); bheight = bImage.getHeight(); bsize = bImage.getData().getDataBuffer().getSize(); log(lvl, "loaded again: %s (%s)", imageName, fileURL); } return bImage; } public static void reload(String fpImage) { // URL uImage = FileManager.makeURL(fpImage); URL uImage = imageNames.get(fpImage); if (imageFiles.containsKey(uImage)) { Image image = imageFiles.get(uImage); int sizeOld = image.bsize; if (null != image.loadAgain()) { currentMemoryDownUp(sizeOld, image.bsize); image.setLastSeen(null, 0); } } } public static void setIDEshouldReload(Image img) { ideShouldReload = true; img.wasRecaptured = true; img.lastSeen = null; } public static boolean getIDEshouldReload() { boolean state = ideShouldReload; ideShouldReload = false; return state; } private static boolean ideShouldReload = false; public boolean isRecaptured() { boolean state = wasRecaptured; wasRecaptured = false; return state; } public boolean wasRecaptured = false; // // private int waitAfter; /** * Get the value of waitAfter * * @return the value of waitAfter */ public int getWaitAfter() { return waitAfter; } /** * Set the value of waitAfter * * @param waitAfter new value of waitAfter * @return the image */ public Image setWaitAfter(int waitAfter) { this.waitAfter = waitAfter; return this; } // // private Rectangle lastSeen = null; private double lastScore = 0.0; /** * if the image was already found before * * @return the rectangle where it was found */ public Rectangle getLastSeen() { return lastSeen; } /** * if the image was already found before * * @return the similarity score */ public double getLastSeenScore() { return lastScore; } /** * Internal Use: set the last seen info after a find * * @param lastSeen Match * @param sim SimilarityScore * @return the image */ public Image setLastSeen(Rectangle lastSeen, double sim) { this.lastSeen = lastSeen; this.lastScore = sim; return this; } // // /** * to support a raster over the image */ private int rows = 0; private int cols = 0; private int rowH = 0; private int colW = 0; private int rowHd = 0; private int colWd = 0; /** * store info: this image is divided vertically into n even rows
* a preparation for using getRow() * * @param n number of rows * @return the top row */ public Image setRows(int n) { return setRaster(n, 0); } /** * store info: this image is divided horizontally into n even columns
* a preparation for using getCol() * * @param n number of Columns * @return the leftmost column */ public Image setCols(int n) { return setRaster(0, n); } /** * @return number of eventually defined rows in this image or 0 */ public int getRows() { return rows; } /** * @return height of eventually defined rows in this image or 0 */ public int getRowH() { return rowH; } /** * @return number of eventually defined columns in this image or 0 */ public int getCols() { return cols; } /** * @return width of eventually defined columns in this image or 0 */ public int getColW() { return colW; } /** * store info: this image is divided into a raster of even cells
* a preparation for using getCell() * * @param r number of rows * @param c number of columns * @return the top left cell */ public Image setRaster(int r, int c) { rows = r; cols = c; if (r > 0) { rowH = (int) (getSize().height / r); rowHd = getSize().height - r * rowH; } if (c > 0) { colW = (int) (getSize().width / c); colWd = getSize().width - c * colW; } return getCell(0, 0); } /** * get the specified row counting from 0, if rows or raster are setup
negative * counts reverse from the end (last = -1)
values outside range are 0 or last * respectively * * @param r row number * @return the row as new image or the image itself, if no rows are setup */ public Image getRow(int r) { if (rows == 0) { return this; } if (r < 0) { r = rows + r; } r = Math.max(0, r); r = Math.min(r, rows - 1); return getSub(0, r * rowH, getSize().width, rowH); } /** * get the specified column counting from 0, if columns or raster are setup
* negative counts reverse from the end (last = -1)
values outside range are 0 * or last respectively * * @param c column number * @return the column as new image or the image itself, if no columns are * setup */ public Image getCol(int c) { if (cols == 0) { return this; } if (c < 0) { c = cols + c; } c = Math.max(0, c); c = Math.min(c, cols - 1); return getSub(c * colW, 0, colW, getSize().height); } /** * get the specified cell counting from (0, 0), if a raster is setup
* negative counts reverse from the end (last = -1)
values outside range are 0 * or last respectively * * @param r row number * @param c column number * @return the cell as new image or the image itself, if no raster is setup */ public Image getCell(int r, int c) { if (rows == 0) { return getCol(c); } if (cols == 0) { return getRow(r); } if (rows == 0 && cols == 0) { return this; } if (r < 0) { r = rows - r; } if (c < 0) { c = cols - c; } r = Math.max(0, r); r = Math.min(r, rows - 1); c = Math.max(0, c); c = Math.min(c, cols - 1); return getSub(c * colW, r * rowH, colW, rowH); } //
/** * OCR-read the text from the image * * @return the text or empty string */ public String text() { return TextRecognizer.doOCR(get()); } /** * convenience method: get text from given image file * * @param imgFile image filename * @return the text or null */ public static String text(String imgFile) { return create(imgFile).text(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy