001package top.cenze.utils.file;
002
003import lombok.extern.slf4j.Slf4j;
004import net.coobird.thumbnailator.Thumbnails;
005import org.apache.commons.lang.StringUtils;
006import sun.misc.BASE64Encoder;
007
008import java.io.ByteArrayInputStream;
009import java.io.ByteArrayOutputStream;
010import java.io.FileInputStream;
011import java.io.InputStream;
012import java.net.HttpURLConnection;
013import java.net.URL;
014
015@Slf4j
016public class ImageUtil {
017    private static final Integer ZERO = 0;
018    private static final Integer ONE_ZERO_TWO_FOUR = 1024;
019    private static final Integer NINE_ZERO_ZERO = 900;
020    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
021    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
022    private static final Double ZERO_EIGHT_FIVE = 0.85;
023    private static final Double ZERO_SIX = 0.6;
024    private static final Double ZERO_FOUR_FOUR = 0.44;
025    private static final Double ZERO_FOUR = 0.4;
026
027    /**
028     * 根据指定大小压缩图片
029     *
030     * @param imageBytes  源图片字节数组
031     * @param desFileSize 指定图片大小,单位kb
032     * @return 压缩质量后的图片字节数组
033     */
034    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
035        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
036            return imageBytes;
037        }
038
039        long srcSize = imageBytes.length;
040        double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
041
042        try {
043            while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
044                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
045                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
046
047                Thumbnails.of(inputStream)
048                        .scale(accuracy)
049                        .outputQuality(accuracy)
050                        .toOutputStream(outputStream);
051
052                imageBytes = outputStream.toByteArray();
053            }
054
055            log.info("图片原大小={}kb | 压缩后大小={}kb",
056                    srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
057        } catch (Exception e) {
058            log.error("【图片压缩】msg=图片压缩失败!", e);
059        }
060
061        return imageBytes;
062    }
063
064    /**
065     * 自动调节精度(经验数值)
066     *
067     * @param size 源图片大小
068     * @return 图片压缩质量比
069     */
070    private static double getAccuracy(long size) {
071        double accuracy;
072        if (size < NINE_ZERO_ZERO) {
073            accuracy = ZERO_EIGHT_FIVE;
074        } else if (size < TWO_ZERO_FOUR_SEVEN) {
075            accuracy = ZERO_SIX;
076        } else if (size < THREE_TWO_SEVEN_FIVE) {
077            accuracy = ZERO_FOUR_FOUR;
078        } else {
079            accuracy = ZERO_FOUR;
080        }
081        return accuracy;
082    }
083
084    /**
085     * 判断是否为网络图片
086     * @param image
087     * @return
088     */
089    public static boolean isNetImage(String image) {
090        if (StringUtils.isBlank(image)) {
091            return false;
092        }
093
094        String str = image.substring(0, 10).toLowerCase();
095        if (str.contains("http:") || str.contains("https:")) {
096            return true;
097        }
098
099        return false;
100    }
101
102    /**
103     * 网络图片转byte[]
104     * @param imageUrl
105     * @return
106     */
107    public static byte[] netImageToByte(String imageUrl) {
108        if (org.apache.commons.lang3.StringUtils.isBlank(imageUrl)) {
109            return null;
110        }
111
112        try {
113            URL url = new URL(imageUrl);
114            byte[] b = new byte[10240];
115
116            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
117            conn.setRequestMethod("GET");
118            conn.setConnectTimeout(5000);
119
120            InputStream is = conn.getInputStream();
121            ByteArrayOutputStream os = new ByteArrayOutputStream();
122
123            int len = -1;
124            while ((len = is.read(b)) != -1) {
125                os.write(b, 0, len);
126            }
127
128            is.close();
129
130            return os.toByteArray();
131        } catch (Exception e) {
132            log.error(e.getMessage());
133        }
134
135        return null;
136    }
137
138    /**
139     * 网络图片转base64(网络图片地址、图片类型png、不需要base64头信息)
140     * @param imageUrl
141     * @return
142     */
143    public static String netImage2Base64(String imageUrl) {
144        return netImage2Base64(imageUrl, false);
145    }
146
147    /**
148     * 网络图片转base64(网络图片地址、图片类型png、是否需要base64头信息、不限制图片大小)
149     * @param imageUrl
150     * @param head      是否需要base64头
151     * @return
152     */
153    public static String netImage2Base64(String imageUrl, boolean head) {
154        return netImage2Base64(imageUrl, head, 0L);
155    }
156
157    /**
158     * 网络图片转base64(网络图片地址、图片类型png、是否需要base64头信息、压缩图片限制压缩后的图片大小)
159     * @param imageUrl
160     * @param head          是否需要base64头
161     * @param desFileSize   压缩图片,限制压缩后的图片大小
162     * @return
163     */
164    public static String netImage2Base64(String imageUrl, boolean head, long desFileSize) {
165        if (org.apache.commons.lang3.StringUtils.isBlank(imageUrl)) {
166            return null;
167        }
168
169        String[] split = imageUrl.split(".");
170
171        String type = "png";
172        if (null != split && split.length > 0) {
173            type = split[split.length - 1];
174        }
175
176        byte[] imageBytes = netImageToByte(imageUrl);
177
178        if (desFileSize > 0) {
179            imageBytes = compressPicForScale(imageBytes, desFileSize);
180        }
181
182        return netImage2Base64(imageBytes, type, head);
183    }
184
185    private static String netImage2Base64(byte[] imageBytes, String type, boolean head) {
186        if (imageBytes == null || imageBytes.length <= ZERO) {
187            return null;
188        }
189
190        try {
191            BASE64Encoder encoder = new BASE64Encoder();
192            if (head) {
193                return "data:image/" + type + ";base64," + encoder.encode(imageBytes);
194            } else {
195                return encoder.encode(imageBytes);
196            }
197        } catch (Exception e) {
198            log.error(e.getMessage());
199        }
200
201        return null;
202    }
203
204    /**
205     * 网络图片转base64(网络图片地址、图片类型默认、不需要base64头信息)
206     * @param imageUrl
207     * @return
208     */
209    public static String NetImage2Base64(String imageUrl) {
210        return NetImage2Base64(imageUrl, null, false);
211    }
212
213    /**
214     * 网络图片转base64(网络图片地址、图片类型png、需要base64头信息)
215     * @param imageUrl
216     * @return
217     */
218    public static String NetImage2FullBase64(String imageUrl) {
219        return NetImage2Base64(imageUrl, "png", true);
220    }
221
222    /**
223     * 网络图片转base64(网络图片地址、图片类型png/jpg、需要base64头信息)
224     * @param imageUrl
225     * @param type
226     * @return
227     */
228    public static String NetImage2Base64(String imageUrl, String type) {
229        return NetImage2Base64(imageUrl, type, true);
230    }
231
232    /**
233     * 网络图片转base64(网络图片地址、图片类型png/jpg、是否需要base64头信息)
234     * @param imageUrl
235     * @param type
236     * @param head
237     * @return
238     */
239    public static String NetImage2Base64(String imageUrl, String type, boolean head) {
240        if (StringUtils.isBlank(imageUrl)) {
241            return null;
242        }
243
244        try {
245            URL url = new URL(imageUrl);
246            byte[] b = new byte[1024];
247
248            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
249            conn.setRequestMethod("GET");
250            conn.setConnectTimeout(5000);
251
252            InputStream is = conn.getInputStream();
253            ByteArrayOutputStream os = new ByteArrayOutputStream();
254
255            int len = -1;
256            while ((len = is.read(b)) != -1) {
257                os.write(b, 0, len);
258            }
259
260            is.close();
261
262            BASE64Encoder encoder = new BASE64Encoder();
263            if (head) {
264                if (StringUtils.isBlank(type)) {
265                    type = "png";
266                }
267
268                return "data:image/" + type + ";base64," + encoder.encode(os.toByteArray());
269            } else {
270                return encoder.encode(os.toByteArray());
271            }
272        } catch (Exception e) {
273            log.error(e.getMessage());
274        }
275
276        return null;
277    }
278
279    /**
280     * 本地图片转base64(本地图片绝对路径)
281     * @param imagePath
282     * @return
283     */
284    public static String LocalImage2Base64(String imagePath) {
285        if (StringUtils.isBlank(imagePath)) {
286            return null;
287        }
288
289        try {
290            InputStream is = new FileInputStream(imagePath);
291            byte[] b = new byte[is.available()];
292            is.read(b);
293
294            is.close();
295
296            BASE64Encoder encoder = new BASE64Encoder();
297            return encoder.encode(b);
298        } catch (Exception e) {
299            log.error(e.getMessage());
300        }
301
302        return null;
303    }
304}