Java tutorial
/////////////////////////////////////////////////////////////////////////////// //Copyright (C) 2012 Assaf Urieli // //This file is part of Jochre. // //Jochre is free software: you can redistribute it and/or modify //it under the terms of the GNU Affero General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. // //Jochre is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU Affero General Public License for more details. // //You should have received a copy of the GNU Affero General Public License //along with Jochre. If not, see <http://www.gnu.org/licenses/>. ////////////////////////////////////////////////////////////////////////////// package com.joliciel.jochre.graphics; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ArrayList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.math.stat.descriptive.DescriptiveStatistics; import com.joliciel.jochre.EntityImpl; import com.joliciel.jochre.doc.DocumentService; import com.joliciel.jochre.doc.JochrePage; import com.joliciel.jochre.graphics.util.ImagePixelGrabber; import com.joliciel.jochre.graphics.util.ImagePixelGrabberImpl; import com.joliciel.jochre.security.SecurityService; import com.joliciel.jochre.security.User; import com.joliciel.talismane.utils.Monitorable; import com.joliciel.talismane.utils.ProgressMonitor; import com.joliciel.talismane.utils.SimpleProgressMonitor; class JochreImageImpl extends EntityImpl implements JochreImageInternal, Monitorable { private static final Log LOG = LogFactory.getLog(JochreImageImpl.class); int blackThreshold; int separationThreshold; String name; int width; int height; List<Paragraph> paragraphs; int pageId; JochrePage page; int index; int whiteLimit; int blackLimit; private int ownerId; private User owner; int[] normalizedBrightnessValues; int whiteGapFillFactor; double averageRowHeight = 0; boolean originalImageChanged = false; private BufferedImage originalImage = null; int shapeCount = -1; private ImagePixelGrabber pixelGrabber; GraphicsServiceInternal graphicsService; DocumentService documentService; SecurityService securityService; ImageStatus imageStatus; private Map<String, Shape> shapeMap = null; SimpleProgressMonitor currentMonitor = null; int shapesSaved = 0; JochreImageImpl() { } public JochreImageImpl(BufferedImage originalImage) { this.originalImage = originalImage; } ImagePixelGrabber getPixelGrabber() { if (this.pixelGrabber == null) { this.pixelGrabber = new ImagePixelGrabberImpl(this.getOriginalImage()); } return this.pixelGrabber; } @Override public int getAbsolutePixel(int x, int y) { int brightness = this.getRawAbsolutePixel(x, y); // brightness now gives us a greyscale value // all we need to do is normalise it return this.normalize(brightness); } @Override public int getPixel(int x, int y) { return this.getAbsolutePixel(x, y); } @Override public int getRawPixel(int x, int y) { return this.getRawAbsolutePixel(x, y); } @Override public int getRawAbsolutePixel(int x, int y) { return this.getPixelGrabber().getPixelBrightness(x, y); } @Override public boolean isPixelBlack(int x, int y, int threshold) { if (x < 0 || y < 0 || x >= this.getWidth() || y >= this.getHeight()) return false; if (this.getPixel(x, y) <= threshold) return true; else return false; } public int getBlackThreshold() { return blackThreshold; } public void setBlackThreshold(int blackThreshold) { this.blackThreshold = blackThreshold; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } @Override public List<Paragraph> getParagraphs() { if (paragraphs == null) { if (this.isNew()) paragraphs = new ArrayList<Paragraph>(); else paragraphs = graphicsService.findParagraphs(this); } return paragraphs; } public GraphicsServiceInternal getGraphicsService() { return graphicsService; } public void setGraphicsService(GraphicsServiceInternal graphicsService) { this.graphicsService = graphicsService; } @Override public void saveInternal() { if (this.currentMonitor != null) this.currentMonitor.setCurrentAction("imageMonitor.savingImage"); if (this.pageId == 0 && this.page != null) this.pageId = this.page.getId(); this.graphicsService.saveJochreImage(this); if (this.paragraphs != null) { int index = 0; for (Paragraph paragraph : this.paragraphs) { paragraph.setIndex(index++); paragraph.save(); } } if (this.originalImageChanged) { this.graphicsService.saveOriginalImage(this); } } @Override public Paragraph newParagraph() { ParagraphInternal paragraph = graphicsService.getEmptyParagraphInternal(); this.getParagraphs().add(paragraph); paragraph.setImage(this); return paragraph; } @Override public int getPageId() { return pageId; } @Override public void setPageId(int pageId) { this.pageId = pageId; } @Override public JochrePage getPage() { if (this.page == null && this.pageId != 0) this.page = this.documentService.loadJochrePage(this.pageId); return page; } public void setPage(JochrePage page) { this.page = page; this.pageId = page.getId(); } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public int getSeparationThreshold() { return separationThreshold; } public void setSeparationThreshold(int separationThreshold) { this.separationThreshold = separationThreshold; } @Override public int getWhiteLimit() { return whiteLimit; } @Override public void setWhiteLimit(int whiteLimit) { this.whiteLimit = whiteLimit; } @Override public int getBlackLimit() { return blackLimit; } @Override public void setBlackLimit(int blackLimit) { this.blackLimit = blackLimit; } @Override public final int normalize(int brightness) { if (normalizedBrightnessValues == null) { normalizedBrightnessValues = new int[256]; double greyscaleMultiplier = (255.0 / (double) (whiteLimit - blackLimit)); for (int i = 0; i < 256; i++) { if (i < blackLimit) normalizedBrightnessValues[i] = 0; if (i > whiteLimit) normalizedBrightnessValues[i] = 255; normalizedBrightnessValues[i] = (int) Math.round((double) (i - blackLimit) * greyscaleMultiplier); } } return normalizedBrightnessValues[brightness]; } public int getWhiteGapFillFactor() { return whiteGapFillFactor; } public void setWhiteGapFillFactor(int whiteGapFillFactor) { this.whiteGapFillFactor = whiteGapFillFactor; } public ImageStatus getImageStatus() { return imageStatus; } public void setImageStatus(ImageStatus imageStatus) { this.imageStatus = imageStatus; } @Override public void clearMemory() { this.paragraphs = null; this.originalImage = null; this.pixelGrabber = null; this.shapeMap = null; System.gc(); } public void recalculate() { this.averageRowHeight = 0; } public double getAverageRowHeight() { if (averageRowHeight == 0) { DescriptiveStatistics rowHeightStats = new DescriptiveStatistics(); for (Paragraph paragraph : this.getParagraphs()) { for (RowOfShapes row : paragraph.getRows()) { int height = row.getXHeight(); rowHeightStats.addValue(height); } } averageRowHeight = rowHeightStats.getPercentile(50); LOG.debug("averageRowHeight: " + averageRowHeight); } return averageRowHeight; } public BufferedImage getOriginalImage() { if (this.originalImage == null) { this.getGraphicsService().loadOriginalImage(this); } return originalImage; } public void setOriginalImage(BufferedImage originalImage) { this.originalImage = originalImage; originalImageChanged = true; } public void setOriginalImageDB(BufferedImage originalImage) { this.originalImage = originalImage; } public DocumentService getDocumentService() { return documentService; } public void setDocumentService(DocumentService documentService) { this.documentService = documentService; } public int getShapeCount() { if (shapeCount < 0) { shapeCount = this.graphicsService.getShapeCount(this); } return shapeCount; } public void setShapeCount(int shapeCount) { this.shapeCount = shapeCount; } @Override public int hashCode() { if (this.isNew()) return super.hashCode(); else return ((Integer) this.getId()).hashCode(); } @Override public boolean equals(Object obj) { if (this.isNew()) { return super.equals(obj); } else { JochreImage other = (JochreImage) obj; return (this.getId() == other.getId()); } } @Override public int getOwnerId() { return ownerId; } @Override public void setOwnerId(int ownerId) { this.ownerId = ownerId; this.owner = null; } @Override public User getOwner() { if (this.owner == null && this.ownerId != 0) this.owner = this.getSecurityService().loadUser(this.ownerId); return owner; } @Override public void setOwner(User owner) { this.setOwnerId(owner.getId()); this.owner = owner; } public SecurityService getSecurityService() { return securityService; } public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } @Override public Shape getShape(int left, int top, int right, int bottom) { String key = left + "," + top + "," + right + "," + bottom; if (this.shapeMap == null) this.shapeMap = new HashMap<String, Shape>(); Shape shape = this.shapeMap.get(key); if (shape == null) { ShapeInternal shapeInternal = this.graphicsService.getEmptyShapeInternal(); shapeInternal.setJochreImage(this); shapeInternal.setLeft(left); shapeInternal.setTop(top); shapeInternal.setRight(right); shapeInternal.setBottom(bottom); this.shapeMap.put(key, shapeInternal); shape = shapeInternal; } return shape; } @Override public boolean isLeftToRight() { return this.getPage().getDocument().isLeftToRight(); } @Override public ProgressMonitor monitorTask() { currentMonitor = new SimpleProgressMonitor(); shapesSaved = 0; return currentMonitor; } @Override public void onSaveShape(Shape shape) { if (this.currentMonitor != null) { shapesSaved++; int shapeCount = this.getShapeCount(); if (shapeCount == 0) shapeCount = 1; this.currentMonitor.setPercentComplete((double) shapesSaved / (double) shapeCount); } } }