/******************************************************************************* * Copyright (c) MOBAC developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ /* ********************************************* * Copyright: Andreas Sander * * * ********************************************* */ package mobac.program.atlascreators.impl.rmp; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; import java.util.List; import mobac.gui.AtlasProgress; import mobac.program.atlascreators.AtlasCreator; import mobac.program.atlascreators.impl.rmp.interfaces.RmpFileEntry; import org.apache.log4j.Logger; /** * Class for building a TLM file from image and writing the file to a stream * */ public class RmpLayer { private static final Logger log = Logger.getLogger(RmpLayer.class); private List<Tiledata> tiles; private TLMEntry tlmFile = null; private final AtlasCreator atlasCreator; /** * Constructor */ public RmpLayer(AtlasCreator atlasCreator) { tiles = new LinkedList<Tiledata>(); this.atlasCreator = atlasCreator; } /** * Return the content of the A00 file as byte array */ public RmpFileEntry getA00File(String image_name) { return new A00Entry(image_name); } /** * Return the content of the TLM file as byte array * * @throws IOException */ public TLMEntry getTLMFile(String image_name) { tlmFile.setImageName(image_name); return tlmFile; } public void addPreparedImage(Tiledata tileData) throws IOException { tiles.add(tileData); } /** * distribute the tiles over containers of max 256 tiles */ private TileContainer buildTileTree() { TileContainer[] container; TileContainer indexContainer = null; int containerCount; /* * --- Calculate the number of tiles and tiles per container. 99 would * be possible but we limit ourselves to 80 - That's enough --- */ int count = tiles.size(); containerCount = count / 80; if (count % 80 != 0) containerCount++; int tilesPerContainer = count / containerCount; /* --- Create containers --- */ container = new TileContainer[containerCount]; for (int i = 0; i < containerCount; i++) container[i] = new TileContainer(); /* * --- We need an index container if there is more than one container. * Container 0 is the previous of the index container --- */ if (containerCount > 1) indexContainer = new TileContainer(container[0]); /* --- Place the tiles into the container --- */ int tileCount = 0; int totalTileCount = 0; int containerNumber = 0; for (Tiledata tiledata : tiles) { /* * --- Starting with the second container, the first element is * moved to the index container --- */ if (tileCount == 0 && containerNumber != 0) indexContainer.addTile(tiledata, container[containerNumber]); else container[containerNumber].addTile(tiledata, null); /* --- Switch to next container if we reach end of container --- */ tileCount++; if (tileCount == tilesPerContainer) { containerNumber++; tileCount = 0; /* * --- Recalculate the number of tiles per container because of * rounding issues */ if (containerCount != containerNumber) tilesPerContainer = (count - (totalTileCount + 1)) / (containerCount - containerNumber); } totalTileCount++; } /* * --- If we have multiple containers, then the index container is the * result, otherwise the single container. */ if (indexContainer == null) return container[0]; else return indexContainer; } /** * Create the TLM file from the TileContainer infos * * @throws IOException */ public void buildTLMFile(double tile_width, double tile_height, double left, double right, double top, double bottom) throws IOException { tlmFile = new TLMEntry(tile_width, tile_height, left, right, top, bottom); tlmFile.updateContent(); } public class TLMEntry implements RmpFileEntry { private byte[] data = null; String imageName; final double tile_width; final double tile_height; final double left; final double right; final double top; final double bottom; public TLMEntry(double tile_width, double tile_height, double left, double right, double top, double bottom) { super(); this.tile_width = tile_width; this.tile_height = tile_height; this.left = left; this.right = right; this.top = top; this.bottom = bottom; } public void updateContent() throws IOException { // calculate offset of each tile in A00 file int totaloffset = 4; for (Tiledata tile : tiles) { tile.totalOffset = totaloffset; totaloffset += tile.getTileDataSize() + 4; } /* --- Build the tile container --- */ TileContainer container = buildTileTree(); log.debug("Number of output tiles: " + container.getTileCount()); /* --- Create Output file --- */ ByteArrayOutputStream bos = new ByteArrayOutputStream(16384); /* --- header --- */ RmpTools.writeValue(bos, 1, 4); // Start of block RmpTools.writeValue(bos, container.getTileCount(), 4); // Number of // tiles in files RmpTools.writeValue(bos, 256, 2); // Hor. size of tile in pixel RmpTools.writeValue(bos, 256, 2); // Vert. size of tile in pixel RmpTools.writeValue(bos, 1, 4); // Start of block RmpTools.writeDouble(bos, tile_height); // Height of tile in degree RmpTools.writeDouble(bos, tile_width); // Tile width in degree RmpTools.writeDouble(bos, left); // Frame RmpTools.writeDouble(bos, top); // Frame RmpTools.writeDouble(bos, right); // Frame RmpTools.writeDouble(bos, bottom); // Frame RmpTools.writeValue(bos, 0, 88); // Filler RmpTools.writeValue(bos, 256, 2); // Tile size ???? RmpTools.writeValue(bos, 0, 2); // Filler int size = 256 + 1940 + 3 * 1992; size += container.getContainerCount() * 1992; if (container.getContainerCount() != 1) size += 1992; RmpTools.writeValue(bos, size, 4); // File size RmpTools.writeValue(bos, 0, 96); // Filler RmpTools.writeValue(bos, 1, 4); // Start of block RmpTools.writeValue(bos, 99, 4); // Number of tiles in block int firstBlockOffset = 0x0f5c + ((container.getContainerCount() == 1) ? 0 : 1992); RmpTools.writeValue(bos, firstBlockOffset, 4); // offset for first // block RmpTools.writeValue(bos, 0, 3920); // Filler /* --- Write the Tiledata --- */ container.writeTree(bos); /* --- Add two empty blocks --- */ RmpTools.writeValue(bos, 0, 1992 * 2); data = bos.toByteArray(); } public void setImageName(String imageName) { this.imageName = imageName; } public String getFileExtension() { return "tlm"; } public String getFileName() { return imageName; } public void writeFileContent(OutputStream out) throws IOException { out.write(data); } } protected class A00Entry implements RmpFileEntry { protected String name; public A00Entry(String name) { super(); this.name = name; } public String getFileExtension() { return "a00"; } public String getFileName() { return name; } public void writeFileContent(OutputStream os) throws IOException, InterruptedException { BufferedOutputStream bos = new BufferedOutputStream(os, 32768); /* --- Number of tiles --- */ RmpTools.writeValue(bos, tiles.size(), 4); AtlasProgress atlasProgress = atlasCreator.getAtlasProgress(); /* --- The tiles --- */ int x = 0; int xMax = tiles.size(); for (Tiledata tile : tiles) { tile.writeTileData(bos); atlasCreator.checkUserAbort(); atlasProgress.setMapCreationProgress((1000 * x++ / xMax)); } bos.flush(); } @Override public String toString() { return "A00Entry"; } } }