list = new LinkedList<>();
76 | while (!stack.empty()) {
77 | File f = stack.pop();
78 | if (f.isDirectory()) {
79 | for (File sub : f.listFiles()) {
80 | stack.push(sub);
81 | }
82 | } else {
83 | String fileName = f.getName();
84 | fileName = fileName.substring(fileName.lastIndexOf(".") + 1);
85 | if ("tif".equals(fileName) || "tiff".equals(fileName)) {
86 | String path = f.getPath();
87 | try {
88 | TileableTiff[] tileableTiffs = new TileableTiff[coreSize];
89 | for (int i = 0; i < coreSize; i++) {
90 | tileableTiffs[i] = new TileableTiff(path);
91 | }
92 | list.add(tileableTiffs);
93 | System.out.println("加载tiff文件完成:" + path);
94 | } catch (Exception e) {
95 | e.printStackTrace();
96 | }
97 | }
98 | }
99 | }
100 | allTiff = new TileableTiff[list.size()][];
101 | list.toArray(allTiff);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/web/src/main/java/org/wowtools/fasttiff/web/controller/TileServiceController.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.fasttiff.web.controller;
2 |
3 | import org.json.JSONObject;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
6 | import org.springframework.web.bind.annotation.PathVariable;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RequestParam;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import org.wowtools.fasttiff.core.TileableTiff;
11 | import org.wowtools.fasttiff.web.service.MapServerMeta;
12 | import org.wowtools.fasttiff.web.util.PngEncoder;
13 |
14 | import javax.imageio.ImageIO;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.awt.image.BufferedImage;
17 | import java.io.IOException;
18 | import java.io.OutputStream;
19 | import java.util.Random;
20 |
21 | /**
22 | * 切片服务Controller
23 | *
24 | * @author liuyu
25 | * @date 2018/2/24
26 | */
27 | @RestController()
28 | @RequestMapping("/tiled")
29 | public class TileServiceController {
30 |
31 | @Autowired
32 | private TileService tileService;
33 |
34 | @RequestMapping({"/{layer}"})
35 | public String getilemetainfo(@PathVariable("layer") String layer, @RequestParam("f") String form,
36 | HttpServletResponse response) {
37 | MapServerMeta meta = new MapServerMeta(layer);
38 | return meta.getMapServerMetainfo().toString();
39 | }
40 |
41 |
42 | @RequestMapping({"/{layer}/tile/{level}/{row}/{col}"})
43 | public void getile(@PathVariable("layer") String layer, @PathVariable("level") int level, @PathVariable("row") int row, @PathVariable("col") int col, HttpServletResponse response) {
44 | /* 允许跨域的主机地址 */
45 | response.setHeader("Access-Control-Allow-Origin", "*");
46 | /* 允许跨域的请求方法GET, POST, HEAD 等 */
47 | response.setHeader("Access-Control-Allow-Methods", "*");
48 | /* 重新预检验跨域的缓存时间 (s) */
49 | response.setHeader("Access-Control-Max-Age", "3600");
50 | /* 允许跨域的请求头 */
51 | response.setHeader("Access-Control-Allow-Headers", "*");
52 | /* 是否携带cookie */
53 | response.setHeader("Access-Control-Allow-Credentials", "true");
54 |
55 | BufferedImage img = tileService.getTile(level,row,col);
56 | response.setContentType("image/png");
57 | OutputStream os = null;
58 | try {
59 | os = response.getOutputStream();
60 | ImageIO.write(img,"png",os);
61 | //这种写法性能较高,但图片压缩率低,给客户端压力打
62 | // byte[] bt = new PngEncoder(img,true).pngEncode();
63 | // os.write(bt);
64 | os.flush();
65 | } catch (Exception e) {
66 | throw new RuntimeException(e);
67 | }finally{
68 | if(null!=os){
69 | try {
70 | os.close();
71 | } catch (IOException e) {
72 | }
73 | }
74 |
75 | }
76 | }
77 |
78 | @RequestMapping({"/{layer}/tilemap/{level}/{row}/{col}/{width}/{height}"})
79 | public String getileN(@PathVariable("layer") String layer, @PathVariable("level") int level, @PathVariable("row") int row,
80 | @PathVariable("col") int col, @PathVariable("width") int w, @PathVariable("height") int h,
81 | HttpServletResponse response) {
82 | JSONObject jo = new JSONObject();
83 | jo.put("valid", true);
84 | JSONObject joLocation = new JSONObject();
85 | joLocation.put("left", col);
86 | joLocation.put("top", row);
87 | joLocation.put("width", w);
88 | joLocation.put("height", h);
89 | int n = w * h;
90 | int[] arr = new int[n];
91 | for (int i = 0; i < n; i++) {
92 | arr[i] = 1;
93 | }
94 | jo.put("location", joLocation);
95 | jo.put("data", arr);
96 | return jo.toString();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/web/src/main/java/org/wowtools/fasttiff/web/service/MapServerMeta.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.fasttiff.web.service;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONObject;
5 |
6 | public class MapServerMeta {
7 | private static class LayerExtent {
8 | int minLevel;
9 | int maxLevel;
10 | double[] minxy;
11 | double[] maxxy;
12 | }
13 |
14 |
15 | private String layername;
16 |
17 | private int dpi = 96;
18 |
19 | private double[] originlonlat;
20 | private JSONArray lyrs = new JSONArray();
21 |
22 | private double minScale = 0;
23 | private double maxScale = 0;
24 | private int minLevel;
25 | private int maxLevel;
26 |
27 | double[] minxy;
28 | double[] maxxy;
29 |
30 | private String layerName;
31 |
32 | public MapServerMeta(String layerName) {
33 | this.originlonlat = new double[]{-2.0037508342787E7, 2.0037508342787E7};
34 | this.layerName = layerName;
35 | minxy = new double[]{10848780.278959094, 2364183.440747929};
36 | maxxy = new double[]{11841311.259604478, 3462945.6138322023};
37 | minLevel = 0;
38 | maxLevel = 29;
39 | }
40 |
41 | public JSONObject getMapServerMetainfo() {
42 |
43 | JSONObject data = new JSONObject();
44 |
45 | data.put("currentVersion", "10.3");
46 | data.put("serviceDescription", layerName);
47 | data.put("mapName", layerName);
48 | data.put("description", "xxxxxxxxx");
49 | data.put("copyrightText", "xxxxxxxx");
50 | data.put("supportsDynamicLayers", false);
51 |
52 | JSONObject spatialReference = new JSONObject();
53 | spatialReference.put("wkid", 102100);
54 | spatialReference.put("latestWkid", 3857);
55 | data.put("spatialReference", spatialReference);
56 |
57 | data.put("singleFusedMapCache", true);
58 |
59 | data.put("layers", getlayers());
60 |
61 | data.put("tileInfo", gettileinfo());
62 |
63 | data.put("initialExtent", getinitialExtent());
64 |
65 | data.put("fullExtent", getfullExtent());
66 |
67 | data.put("minScale", getminScale());
68 |
69 | data.put("maxScale", getmaxScale());
70 |
71 | data.put("units", getunits());
72 |
73 | data.put("supportedImageFormatTypes", supportedImageFormatTypes());
74 |
75 | data.put("documentInfo", getdocumentInfo());
76 |
77 | data.put("capabilities", "Map,Tilemap");
78 |
79 | data.put("supportedQueryFormats", "JSON");
80 |
81 | data.put("exportTilesAllowed", false);
82 |
83 | data.put("maxRecordCount", 1000);
84 | data.put("maxImageHeight", 4096);
85 | data.put("maxImageWidth", 4096);
86 |
87 | return data;
88 |
89 | }
90 |
91 | private JSONObject gettileinfo() {
92 | JSONObject tileInfo = new JSONObject();
93 |
94 | tileInfo.put("rows", 256);
95 | tileInfo.put("cols", 256);
96 | tileInfo.put("dpi", this.dpi);
97 | tileInfo.put("format", "JPEG");
98 | tileInfo.put("compressionQuality", 90);
99 |
100 | JSONObject origin = new JSONObject();
101 | origin.put("x", this.originlonlat[0]);
102 | origin.put("y", this.originlonlat[1]);
103 | tileInfo.put("origin", origin);
104 |
105 | JSONObject spatialReference2 = new JSONObject();
106 | spatialReference2.put("wkid", 102100);
107 | spatialReference2.put("latestWkid", 3857);
108 | tileInfo.put("spatialReference", spatialReference2);
109 |
110 | tileInfo.put("lods", getlods());
111 |
112 | return tileInfo;
113 | }
114 |
115 | private JSONArray getlods() {
116 | double resolution = 156543.03392800014;
117 | double scale = 5.91657527591555E8;
118 |
119 | for (int i1 = minLevel; i1 <= maxLevel; i1++) {
120 | JSONObject lod = new JSONObject();
121 | lod.put("level", i1);
122 | lod.put("resolution", resolution / (Math.pow(2, i1)));
123 | lod.put("scale", scale / (Math.pow(2, i1)));
124 | lyrs.put(lod);
125 | double Scale = scale / (Math.pow(2, i1));
126 | minScale = minScale > 0 ? Math.max(minScale, Scale) : Scale;
127 | maxScale = maxScale > 0 ? Math.min(maxScale, Scale) : Scale;
128 | }
129 | return lyrs;
130 | }
131 |
132 | private JSONArray getlayers() {
133 | JSONArray lyrs = new JSONArray();
134 |
135 | JSONObject layerinfo = new JSONObject();
136 | layerinfo.put("id", 0);
137 | layerinfo.put("name", this.layername);
138 | layerinfo.put("parentLayerId", -1);
139 | layerinfo.put("defaultVisibility", true);
140 | layerinfo.put("subLayerIds", JSONObject.NULL);
141 | layerinfo.put("minScale", 0);
142 | layerinfo.put("maxScale", 0);
143 | lyrs.put(0, layerinfo);
144 | return lyrs;
145 |
146 | }
147 |
148 | private JSONObject getinitialExtent() {
149 | JSONObject data = new JSONObject();
150 | data.put("xmin", this.minxy[0]);
151 | data.put("ymin", this.minxy[1]);
152 | data.put("xmax", this.maxxy[0]);
153 | data.put("ymax", this.maxxy[1]);
154 | JSONObject spatialReference = new JSONObject();
155 | spatialReference.put("wkid", 102100);
156 | spatialReference.put("latestWkid", 3857);
157 | data.put("spatialReference", spatialReference);
158 |
159 | return data;
160 |
161 | }
162 |
163 | private JSONObject getfullExtent() {
164 |
165 | JSONObject data = new JSONObject();
166 | data.put("xmin", this.minxy[0]);
167 | data.put("ymin", this.minxy[1]);
168 | data.put("xmax", this.maxxy[0]);
169 | data.put("ymax", this.maxxy[1]);
170 |
171 | JSONObject spatialReference = new JSONObject();
172 | spatialReference.put("wkid", 102100);
173 | spatialReference.put("latestWkid", 3857);
174 | data.put("spatialReference", spatialReference);
175 | return data;
176 |
177 | }
178 |
179 | private double getminScale() {
180 | return minScale;
181 | }
182 |
183 | private double getmaxScale() {
184 | return maxScale;
185 | }
186 |
187 | private String getunits() {
188 | return "esriMeters";
189 | }
190 |
191 | private String supportedImageFormatTypes() {
192 | return "PNG";
193 | }
194 |
195 | private JSONObject getdocumentInfo() {
196 | JSONObject data = new JSONObject();
197 | data.put("Author", "xxxxxx");
198 | data.put("Comments", "");
199 | data.put("Subject", "");
200 | data.put("Category", "");
201 | data.put("AntialiasingMode", "None");
202 | data.put("TextAntialiasingMode", "Force");
203 |
204 | return data;
205 | }
206 |
207 | }
208 |
--------------------------------------------------------------------------------
/web/src/main/java/org/wowtools/fasttiff/web/service/TileConfig.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.fasttiff.web.service;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.boot.CommandLineRunner;
5 | import org.springframework.context.annotation.PropertySource;
6 | import org.springframework.core.annotation.Order;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * @author liuyu
11 | * @date 2018/2/26
12 | */
13 | @Component
14 | @PropertySource(value = "classpath:/tile.properties",encoding="utf-8")
15 | @Order(value=1)
16 | public class TileConfig implements CommandLineRunner {
17 | public static TileConfig install;
18 | @Value("${tiffRoot}")
19 | private String tiffRoot;
20 | @Value("${coreSize}")
21 | private int coreSize;
22 |
23 | public String getTiffRoot() {
24 | return tiffRoot;
25 | }
26 |
27 | public int getCoreSize() {
28 | return coreSize;
29 | }
30 |
31 | @Override
32 | public void run(String... args) throws Exception {
33 | install = this;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/web/src/main/java/org/wowtools/fasttiff/web/util/PngEncoder.java:
--------------------------------------------------------------------------------
1 | package org.wowtools.fasttiff.web.util;
2 |
3 |
4 | import java.awt.Image;
5 | import java.awt.image.ImageObserver;
6 | import java.awt.image.PixelGrabber;
7 | import java.io.ByteArrayOutputStream;
8 | import java.io.IOException;
9 | import java.util.zip.CRC32;
10 | import java.util.zip.Deflater;
11 | import java.util.zip.DeflaterOutputStream;
12 |
13 | /**
14 | * PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file.
15 | * The Image is presumed to use the DirectColorModel.
16 | *
17 | * Thanks to Jay Denny at KeyPoint Software
18 | * http://www.keypoint.com/
19 | * who let me develop this code on company time.
20 | *
21 | * You may contact me with (probably very-much-needed) improvements,
22 | * comments, and bug fixes at:
23 | *
24 | * david@catcode.com
25 | *
26 | * This library is free software; you can redistribute it and/or
27 | * modify it under the terms of the GNU Lesser General Public
28 | * License as published by the Free Software Foundation; either
29 | * version 2.1 of the License, or (at your option) any later version.
30 | *
31 | * This library is distributed in the hope that it will be useful,
32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34 | * Lesser General Public License for more details.
35 | *
36 | * You should have received a copy of the GNU Lesser General Public
37 | * License along with this library; if not, write to the Free Software
38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39 | * A copy of the GNU LGPL may be found at
40 | * http://www.gnu.org/copyleft/lesser.html
41 | *
42 | * @author J. David Eisenberg
43 | * @version 1.5, 19 Oct 2003
44 | *
45 | * CHANGES:
46 | * --------
47 | * 19-Nov-2002 : CODING STYLE CHANGES ONLY (by David Gilbert for Object Refinery Limited);
48 | * 19-Sep-2003 : Fix for platforms using EBCDIC (contributed by Paulo Soares);
49 | * 19-Oct-2003 : Change private fields to protected fields so that
50 | * PngEncoderB can inherit them (JDE)
51 | * Fixed bug with calculation of nRows
52 | */
53 |
54 | public class PngEncoder {
55 |
56 | /** Constant specifying that alpha channel should be encoded. */
57 | public static final boolean ENCODE_ALPHA = true;
58 |
59 | /** Constant specifying that alpha channel should not be encoded. */
60 | public static final boolean NO_ALPHA = false;
61 |
62 | /** Constants for filter (NONE) */
63 | public static final int FILTER_NONE = 0;
64 |
65 | /** Constants for filter (SUB) */
66 | public static final int FILTER_SUB = 1;
67 |
68 | /** Constants for filter (UP) */
69 | public static final int FILTER_UP = 2;
70 |
71 | /** Constants for filter (LAST) */
72 | public static final int FILTER_LAST = 2;
73 |
74 | /** IHDR tag. */
75 | protected static final byte IHDR[] = {73, 72, 68, 82};
76 |
77 | /** IDAT tag. */
78 | protected static final byte IDAT[] = {73, 68, 65, 84};
79 |
80 | /** IEND tag. */
81 | protected static final byte IEND[] = {73, 69, 78, 68};
82 |
83 | /** The png bytes. */
84 | protected byte[] pngBytes;
85 |
86 | /** The prior row. */
87 | protected byte[] priorRow;
88 |
89 | /** The left bytes. */
90 | protected byte[] leftBytes;
91 |
92 | /** The image. */
93 | protected Image image;
94 |
95 | /** The width. */
96 | protected int width, height;
97 |
98 | /** The byte position. */
99 | protected int bytePos, maxPos;
100 |
101 | /** CRC. */
102 | protected CRC32 crc = new CRC32();
103 |
104 | /** The CRC value. */
105 | protected long crcValue;
106 |
107 | /** Encode alpha? */
108 | protected boolean encodeAlpha;
109 |
110 | /** The filter type. */
111 | protected int filter;
112 |
113 | /** The bytes-per-pixel. */
114 | protected int bytesPerPixel;
115 |
116 | /** The compression level. */
117 | protected int compressionLevel;
118 |
119 | /**
120 | * Class constructor
121 | */
122 | public PngEncoder() {
123 | this(null, false, FILTER_NONE, 0);
124 | }
125 |
126 | /**
127 | * Class constructor specifying Image to encode, with no alpha channel encoding.
128 | *
129 | * @param image A Java Image object which uses the DirectColorModel
130 | * @see java.awt.Image
131 | */
132 | public PngEncoder(Image image) {
133 | this(image, false, FILTER_NONE, 0);
134 | }
135 |
136 | /**
137 | * Class constructor specifying Image to encode, and whether to encode alpha.
138 | *
139 | * @param image A Java Image object which uses the DirectColorModel
140 | * @param encodeAlpha Encode the alpha channel? false=no; true=yes
141 | * @see java.awt.Image
142 | */
143 | public PngEncoder(Image image, boolean encodeAlpha) {
144 | this(image, encodeAlpha, FILTER_NONE, 0);
145 | }
146 |
147 | /**
148 | * Class constructor specifying Image to encode, whether to encode alpha, and filter to use.
149 | *
150 | * @param image A Java Image object which uses the DirectColorModel
151 | * @param encodeAlpha Encode the alpha channel? false=no; true=yes
152 | * @param whichFilter 0=none, 1=sub, 2=up
153 | * @see java.awt.Image
154 | */
155 | public PngEncoder(Image image, boolean encodeAlpha, int whichFilter) {
156 | this(image, encodeAlpha, whichFilter, 0);
157 | }
158 |
159 |
160 | /**
161 | * Class constructor specifying Image source to encode, whether to encode alpha, filter to use,
162 | * and compression level.
163 | *
164 | * @param image A Java Image object
165 | * @param encodeAlpha Encode the alpha channel? false=no; true=yes
166 | * @param whichFilter 0=none, 1=sub, 2=up
167 | * @param compLevel 0..9
168 | * @see java.awt.Image
169 | */
170 | public PngEncoder(Image image, boolean encodeAlpha, int whichFilter, int compLevel) {
171 | this.image = image;
172 | this.encodeAlpha = encodeAlpha;
173 | setFilter(whichFilter);
174 | if (compLevel >= 0 && compLevel <= 9) {
175 | this.compressionLevel = compLevel;
176 | }
177 | }
178 |
179 | /**
180 | * Set the image to be encoded
181 | *
182 | * @param image A Java Image object which uses the DirectColorModel
183 | * @see java.awt.Image
184 | * @see java.awt.image.DirectColorModel
185 | */
186 | public void setImage(Image image) {
187 | this.image = image;
188 | pngBytes = null;
189 | }
190 |
191 | /**
192 | * Creates an array of bytes that is the PNG equivalent of the current image, specifying
193 | * whether to encode alpha or not.
194 | *
195 | * @param encodeAlpha boolean false=no alpha, true=encode alpha
196 | * @return an array of bytes, or null if there was a problem
197 | */
198 | public byte[] pngEncode(boolean encodeAlpha) {
199 | byte[] pngIdBytes = {-119, 80, 78, 71, 13, 10, 26, 10};
200 |
201 | if (image == null) {
202 | return null;
203 | }
204 | width = image.getWidth(null);
205 | height = image.getHeight(null);
206 |
207 | /*
208 | * start with an array that is big enough to hold all the pixels
209 | * (plus filter bytes), and an extra 200 bytes for header info
210 | */
211 | pngBytes = new byte[((width + 1) * height * 3) + 200];
212 |
213 | /*
214 | * keep track of largest byte written to the array
215 | */
216 | maxPos = 0;
217 |
218 | bytePos = writeBytes(pngIdBytes, 0);
219 | //hdrPos = bytePos;
220 | writeHeader();
221 | //dataPos = bytePos;
222 | if (writeImageData()) {
223 | writeEnd();
224 | pngBytes = resizeByteArray(pngBytes, maxPos);
225 | }
226 | else {
227 | pngBytes = null;
228 | }
229 | return pngBytes;
230 | }
231 |
232 | /**
233 | * Creates an array of bytes that is the PNG equivalent of the current image.
234 | * Alpha encoding is determined by its setting in the constructor.
235 | *
236 | * @return an array of bytes, or null if there was a problem
237 | */
238 | public byte[] pngEncode() {
239 | return pngEncode(encodeAlpha);
240 | }
241 |
242 | /**
243 | * Set the alpha encoding on or off.
244 | *
245 | * @param encodeAlpha false=no, true=yes
246 | */
247 | public void setEncodeAlpha(boolean encodeAlpha) {
248 | this.encodeAlpha = encodeAlpha;
249 | }
250 |
251 | /**
252 | * Retrieve alpha encoding status.
253 | *
254 | * @return boolean false=no, true=yes
255 | */
256 | public boolean getEncodeAlpha() {
257 | return encodeAlpha;
258 | }
259 |
260 | /**
261 | * Set the filter to use
262 | *
263 | * @param whichFilter from constant list
264 | */
265 | public void setFilter(int whichFilter) {
266 | this.filter = FILTER_NONE;
267 | if (whichFilter <= FILTER_LAST) {
268 | this.filter = whichFilter;
269 | }
270 | }
271 |
272 | /**
273 | * Retrieve filtering scheme
274 | *
275 | * @return int (see constant list)
276 | */
277 | public int getFilter() {
278 | return filter;
279 | }
280 |
281 | /**
282 | * Set the compression level to use
283 | *
284 | * @param level 0 through 9
285 | */
286 | public void setCompressionLevel(int level) {
287 | if (level >= 0 && level <= 9) {
288 | this.compressionLevel = level;
289 | }
290 | }
291 |
292 | /**
293 | * Retrieve compression level
294 | *
295 | * @return int in range 0-9
296 | */
297 | public int getCompressionLevel() {
298 | return compressionLevel;
299 | }
300 |
301 | /**
302 | * Increase or decrease the length of a byte array.
303 | *
304 | * @param array The original array.
305 | * @param newLength The length you wish the new array to have.
306 | * @return Array of newly desired length. If shorter than the
307 | * original, the trailing elements are truncated.
308 | */
309 | protected byte[] resizeByteArray(byte[] array, int newLength) {
310 | byte[] newArray = new byte[newLength];
311 | int oldLength = array.length;
312 |
313 | System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength));
314 | return newArray;
315 | }
316 |
317 | /**
318 | * Write an array of bytes into the pngBytes array.
319 | * Note: This routine has the side effect of updating
320 | * maxPos, the largest element written in the array.
321 | * The array is resized by 1000 bytes or the length
322 | * of the data to be written, whichever is larger.
323 | *
324 | * @param data The data to be written into pngBytes.
325 | * @param offset The starting point to write to.
326 | * @return The next place to be written to in the pngBytes array.
327 | */
328 | protected int writeBytes(byte[] data, int offset) {
329 | maxPos = Math.max(maxPos, offset + data.length);
330 | if (data.length + offset > pngBytes.length) {
331 | pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, data.length));
332 | }
333 | System.arraycopy(data, 0, pngBytes, offset, data.length);
334 | return offset + data.length;
335 | }
336 |
337 | /**
338 | * Write an array of bytes into the pngBytes array, specifying number of bytes to write.
339 | * Note: This routine has the side effect of updating
340 | * maxPos, the largest element written in the array.
341 | * The array is resized by 1000 bytes or the length
342 | * of the data to be written, whichever is larger.
343 | *
344 | * @param data The data to be written into pngBytes.
345 | * @param nBytes The number of bytes to be written.
346 | * @param offset The starting point to write to.
347 | * @return The next place to be written to in the pngBytes array.
348 | */
349 | protected int writeBytes(byte[] data, int nBytes, int offset) {
350 | maxPos = Math.max(maxPos, offset + nBytes);
351 | if (nBytes + offset > pngBytes.length) {
352 | pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, nBytes));
353 | }
354 | System.arraycopy(data, 0, pngBytes, offset, nBytes);
355 | return offset + nBytes;
356 | }
357 |
358 | /**
359 | * Write a two-byte integer into the pngBytes array at a given position.
360 | *
361 | * @param n The integer to be written into pngBytes.
362 | * @param offset The starting point to write to.
363 | * @return The next place to be written to in the pngBytes array.
364 | */
365 | protected int writeInt2(int n, int offset) {
366 | byte[] temp = {(byte) ((n >> 8) & 0xff), (byte) (n & 0xff)};
367 | return writeBytes(temp, offset);
368 | }
369 |
370 | /**
371 | * Write a four-byte integer into the pngBytes array at a given position.
372 | *
373 | * @param n The integer to be written into pngBytes.
374 | * @param offset The starting point to write to.
375 | * @return The next place to be written to in the pngBytes array.
376 | */
377 | protected int writeInt4(int n, int offset) {
378 | byte[] temp = {(byte) ((n >> 24) & 0xff),
379 | (byte) ((n >> 16) & 0xff),
380 | (byte) ((n >> 8) & 0xff),
381 | (byte) (n & 0xff)};
382 | return writeBytes(temp, offset);
383 | }
384 |
385 | /**
386 | * Write a single byte into the pngBytes array at a given position.
387 | *
388 | * @param b The integer to be written into pngBytes.
389 | * @param offset The starting point to write to.
390 | * @return The next place to be written to in the pngBytes array.
391 | */
392 | protected int writeByte(int b, int offset) {
393 | byte[] temp = {(byte) b};
394 | return writeBytes(temp, offset);
395 | }
396 |
397 | /**
398 | * Write a PNG "IHDR" chunk into the pngBytes array.
399 | */
400 | protected void writeHeader() {
401 | int startPos;
402 |
403 | startPos = bytePos = writeInt4(13, bytePos);
404 | bytePos = writeBytes(IHDR, bytePos);
405 | width = image.getWidth(null);
406 | height = image.getHeight(null);
407 | bytePos = writeInt4(width, bytePos);
408 | bytePos = writeInt4(height, bytePos);
409 | bytePos = writeByte(8, bytePos); // bit depth
410 | bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model
411 | bytePos = writeByte(0, bytePos); // compression method
412 | bytePos = writeByte(0, bytePos); // filter method
413 | bytePos = writeByte(0, bytePos); // no interlace
414 | crc.reset();
415 | crc.update(pngBytes, startPos, bytePos - startPos);
416 | crcValue = crc.getValue();
417 | bytePos = writeInt4((int) crcValue, bytePos);
418 | }
419 |
420 | /**
421 | * Perform "sub" filtering on the given row.
422 | * Uses temporary array leftBytes to store the original values
423 | * of the previous pixels. The array is 16 bytes long, which
424 | * will easily hold two-byte samples plus two-byte alpha.
425 | *
426 | * @param pixels The array holding the scan lines being built
427 | * @param startPos Starting position within pixels of bytes to be filtered.
428 | * @param width Width of a scanline in pixels.
429 | */
430 | protected void filterSub(byte[] pixels, int startPos, int width) {
431 | int i;
432 | int offset = bytesPerPixel;
433 | int actualStart = startPos + offset;
434 | int nBytes = width * bytesPerPixel;
435 | int leftInsert = offset;
436 | int leftExtract = 0;
437 |
438 | for (i = actualStart; i < startPos + nBytes; i++) {
439 | leftBytes[leftInsert] = pixels[i];
440 | pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
441 | leftInsert = (leftInsert + 1) % 0x0f;
442 | leftExtract = (leftExtract + 1) % 0x0f;
443 | }
444 | }
445 |
446 | /**
447 | * Perform "up" filtering on the given row.
448 | * Side effect: refills the prior row with current row
449 | *
450 | * @param pixels The array holding the scan lines being built
451 | * @param startPos Starting position within pixels of bytes to be filtered.
452 | * @param width Width of a scanline in pixels.
453 | */
454 | protected void filterUp(byte[] pixels, int startPos, int width) {
455 | int i, nBytes;
456 | byte currentByte;
457 |
458 | nBytes = width * bytesPerPixel;
459 |
460 | for (i = 0; i < nBytes; i++) {
461 | currentByte = pixels[startPos + i];
462 | pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
463 | priorRow[i] = currentByte;
464 | }
465 | }
466 |
467 | /**
468 | * Write the image data into the pngBytes array.
469 | * This will write one or more PNG "IDAT" chunks. In order
470 | * to conserve memory, this method grabs as many rows as will
471 | * fit into 32K bytes, or the whole image; whichever is less.
472 | *
473 | *
474 | * @return true if no errors; false if error grabbing pixels
475 | */
476 | protected boolean writeImageData() {
477 | int rowsLeft = height; // number of rows remaining to write
478 | int startRow = 0; // starting row to process this time through
479 | int nRows; // how many rows to grab at a time
480 |
481 | byte[] scanLines; // the scan lines to be compressed
482 | int scanPos; // where we are in the scan lines
483 | int startPos; // where this line's actual pixels start (used for filtering)
484 |
485 | byte[] compressedLines; // the resultant compressed lines
486 | int nCompressed; // how big is the compressed area?
487 |
488 | //int depth; // color depth ( handle only 8 or 32 )
489 |
490 | PixelGrabber pg;
491 |
492 | bytesPerPixel = (encodeAlpha) ? 4 : 3;
493 |
494 | Deflater scrunch = new Deflater(compressionLevel);
495 | ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
496 |
497 | DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch);
498 | try {
499 | while (rowsLeft > 0) {
500 | nRows = Math.min(32767 / (width * (bytesPerPixel + 1)), rowsLeft);
501 | nRows = Math.max( nRows, 1 );
502 |
503 | int[] pixels = new int[width * nRows];
504 |
505 | pg = new PixelGrabber(image, 0, startRow,
506 | width, nRows, pixels, 0, width);
507 | try {
508 | pg.grabPixels();
509 | }
510 | catch (Exception e) {
511 | System.err.println("interrupted waiting for pixels!");
512 | return false;
513 | }
514 | if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
515 | System.err.println("image fetch aborted or errored");
516 | return false;
517 | }
518 |
519 | /*
520 | * Create a data chunk. scanLines adds "nRows" for
521 | * the filter bytes.
522 | */
523 | scanLines = new byte[width * nRows * bytesPerPixel + nRows];
524 |
525 | if (filter == FILTER_SUB) {
526 | leftBytes = new byte[16];
527 | }
528 | if (filter == FILTER_UP) {
529 | priorRow = new byte[width * bytesPerPixel];
530 | }
531 |
532 | scanPos = 0;
533 | startPos = 1;
534 | for (int i = 0; i < width * nRows; i++) {
535 | if (i % width == 0) {
536 | scanLines[scanPos++] = (byte) filter;
537 | startPos = scanPos;
538 | }
539 | scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
540 | scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
541 | scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
542 | if (encodeAlpha) {
543 | scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
544 | }
545 | if ((i % width == width - 1) && (filter != FILTER_NONE)) {
546 | if (filter == FILTER_SUB) {
547 | filterSub(scanLines, startPos, width);
548 | }
549 | if (filter == FILTER_UP) {
550 | filterUp(scanLines, startPos, width);
551 | }
552 | }
553 | }
554 |
555 | /*
556 | * Write these lines to the output area
557 | */
558 | compBytes.write(scanLines, 0, scanPos);
559 |
560 | startRow += nRows;
561 | rowsLeft -= nRows;
562 | }
563 | compBytes.close();
564 |
565 | /*
566 | * Write the compressed bytes
567 | */
568 | compressedLines = outBytes.toByteArray();
569 | nCompressed = compressedLines.length;
570 |
571 | crc.reset();
572 | bytePos = writeInt4(nCompressed, bytePos);
573 | bytePos = writeBytes(IDAT, bytePos);
574 | crc.update(IDAT);
575 | bytePos = writeBytes(compressedLines, nCompressed, bytePos);
576 | crc.update(compressedLines, 0, nCompressed);
577 |
578 | crcValue = crc.getValue();
579 | bytePos = writeInt4((int) crcValue, bytePos);
580 | scrunch.finish();
581 | return true;
582 | }
583 | catch (IOException e) {
584 | System.err.println(e.toString());
585 | return false;
586 | }
587 | }
588 |
589 | /**
590 | * Write a PNG "IEND" chunk into the pngBytes array.
591 | */
592 | protected void writeEnd() {
593 | bytePos = writeInt4(0, bytePos);
594 | bytePos = writeBytes(IEND, bytePos);
595 | crc.reset();
596 | crc.update(IEND);
597 | crcValue = crc.getValue();
598 | bytePos = writeInt4((int) crcValue, bytePos);
599 | }
600 |
601 | }
602 |
--------------------------------------------------------------------------------
/web/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://10.111.58.121:10000/eureka/
5 | enabled: false
6 | server:
7 | tomcat:
8 | uri-encoding: UTF-8
9 | port: 11001
10 | context-path: /fasttiff
11 | spring:
12 | application:
13 | name: fasttiff
14 |
--------------------------------------------------------------------------------
/web/src/main/resources/libgdalconstjni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/fasttiff/d6f9ce8f6d8ad2be8c12a59a9c99456096f2e02d/web/src/main/resources/libgdalconstjni.so
--------------------------------------------------------------------------------
/web/src/main/resources/libgdaljni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/fasttiff/d6f9ce8f6d8ad2be8c12a59a9c99456096f2e02d/web/src/main/resources/libgdaljni.so
--------------------------------------------------------------------------------
/web/src/main/resources/libgnmjni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/fasttiff/d6f9ce8f6d8ad2be8c12a59a9c99456096f2e02d/web/src/main/resources/libgnmjni.so
--------------------------------------------------------------------------------
/web/src/main/resources/libogrjni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/fasttiff/d6f9ce8f6d8ad2be8c12a59a9c99456096f2e02d/web/src/main/resources/libogrjni.so
--------------------------------------------------------------------------------
/web/src/main/resources/libosrjni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingmiao/fasttiff/d6f9ce8f6d8ad2be8c12a59a9c99456096f2e02d/web/src/main/resources/libosrjni.so
--------------------------------------------------------------------------------
/web/src/main/resources/tile.properties:
--------------------------------------------------------------------------------
1 | tiffRoot=D:/BaiduNetdiskDownload/切片Demo/
2 | coreSize=2
3 |
--------------------------------------------------------------------------------