package fr.unistra.pelican.util.largeImages; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import fr.unistra.pelican.PelicanException; /** * Concrete Units must have getPixel(int loc),setPixel(int loc, ? value) and * setPixels(?[] newPixels) methods */ public abstract class Unit { /** * Image which contains this unit. */ public transient LargeImageInterface parentImage; /** * id of the unit in the image. */ public transient int id; /** * Indicates whether the unit was modified or not. */ public transient boolean modified; /** * Indicates the offset concerning the bands so you can easily work on individual band. */ public transient Integer bOffset=null; /** * Indicates the end of the used pixels, the whole array is used when end is null. */ public transient Integer end = null; /** * Constructor */ public Unit() { LargeImageMemoryManager.getInstance().checkMemory(); this.modified = false; } /** * Sets the modification flag to true. */ public void setModified() { this.modified = true; } /** * Sets the modification flag to the given value. * * @param flag * New value for the modification flag */ public void setModified(boolean flag) { this.modified = flag; } /** * Gets the modification flag. * * @return The modification flag */ public boolean isModified() { return this.modified; } /** * Set the index of the unit. * * @param newId * index of the unit in its image */ public void setId(int newId) { this.id = newId; } /** * Sets the parentImage to which these unit belongs. * * @param img * The image to which these unit belongs. */ public void setParentImage(LargeImageInterface img) { this.parentImage = img; } /** * Saves the unit in the file of its image if it has been modified */ public void discard() { if (this.isModified() && (this.parentImage != null)) { File currentFile = this.parentImage.getFile(); long unitLength = this.parentImage.getUnitLength(); try { RandomAccessFile randomAccess = new RandomAccessFile( currentFile, "rw"); try { randomAccess.seek((long) this.id * unitLength); FileOutputStream fileOutput = new FileOutputStream( randomAccess.getFD()); try { ObjectOutputStream objectOutput = new ObjectOutputStream( fileOutput); objectOutput.writeUnshared(this); } finally { fileOutput.close(); } } finally { randomAccess.close(); } } catch (IOException e) { throw new PelicanException("Unable to work in the file " + currentFile.getAbsolutePath()); } this.setModified(false); } } @Override public abstract Unit clone(); /** * Computes the bOffset to be able to work easily by band.</br> * It also sets the end field when the unit is the last one in the image. */ public void computeOffsets(){ this.bOffset = (int)(((long)this.parentImage.getUnitSize()*(long)this.id)%((long)this.parentImage.getBDim())); if (id == (this.parentImage.getUnitDim()-1)){ this.end = (int)(this.parentImage.size()-((long)(id)*(long)this.parentImage.getUnitSize())); } } /** * This method is used to work on one band in a LargeImageInterface.</br> * Just use this kind of loops : for (int p = this.checkForBandWork(bandNumber); p < this.pixels.length; p+=this.parentImage.getBDim()) * @param band * Band in which you want to work. * @return * The first index of this band in the unit. Integer.MAX_VALUE if there is no pixel corresponding at this band in the unit. */ public int checkForBandWork(int band){ if (this.bOffset==null||this.parentImage==null){ throw new PelicanException("Cannot use maximum(int band) on an unit which was not set on a parent Image"); } int debut; if (this.bOffset>band){ debut = this.parentImage.getBDim()-this.bOffset+band; if(debut <0){ return Integer.MAX_VALUE; } }else{ debut = band-bOffset; } return debut; } /** * Gets the size of the unit (the number of pixels that are stored in this unit) * @return * the end value if one has been defined, defaultSize() otherwise. */ public int size(){ if (end!=null){ return end; } return defaultSize(); } /** * Gets the default size of the unit (the size of its array). * @return * the size of the unit array */ public abstract int defaultSize(); public boolean equals(Object o){ if(o==null||!(o instanceof Unit)){ return false; } return equals((Unit)o); } /** * Compares with the given Unit * * @param im * image to compare * @return <code>true</code> if and only if the given unit has the same * pixel values as this unit */ public abstract boolean equals(Unit u); }