From fa89f5c4b746a41efee0362bd3a42ea2c97e2cff Mon Sep 17 00:00:00 2001
From: rain <167982779@qq.com>
Date: Mon, 22 Apr 2024 18:13:46 +0800
Subject: [PATCH] 在加水印前对文件进行音视频处理,分别执行不同方法。增加图片压缩、视频压缩方法。

---
 src/main/java/com/dji/sample/territory/service/impl/TbFjServiceImpl.java     |   64 ++++++---
 src/main/java/com/dji/sample/territory/utils/VideoZipUtil.java               |   54 +++++++++
 src/main/java/com/dji/sample/territory/controller/TbFjController.java        |   14 +
 src/main/java/com/dji/sample/territory/service/impl/TbDkjbxxServiceImpl.java |    2 
 src/main/java/com/dji/sample/territory/utils/ImgZipUtil.java                 |   42 +++++++
 src/main/java/com/dji/sample/territory/controller/TbDkjbxxController.java    |   24 ++-
 src/main/resources/application-dev.yml                                       |    4 
 src/main/java/com/dji/sample/territory/utils/WaterMark.java                  |  106 +++++++++++++++++
 src/main/resources/tmp/tmp.jpg                                               |    0 
 pom.xml                                                                      |    7 +
 src/main/resources/tmp/mark.jpg                                              |    0 
 11 files changed, 282 insertions(+), 35 deletions(-)

diff --git a/pom.xml b/pom.xml
index 7ceceb8..9e252ad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -263,6 +263,13 @@
             <artifactId>spring-test</artifactId>
             <version>5.0.8.RELEASE</version>
         </dependency>
+        <!--   mp4文件压缩处理    -->
+        <dependency>
+            <groupId>ws.schild</groupId>
+            <artifactId>jave-core</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+
     </dependencies>
 
 
diff --git a/src/main/java/com/dji/sample/territory/controller/TbDkjbxxController.java b/src/main/java/com/dji/sample/territory/controller/TbDkjbxxController.java
index 14fdec2..44e4415 100644
--- a/src/main/java/com/dji/sample/territory/controller/TbDkjbxxController.java
+++ b/src/main/java/com/dji/sample/territory/controller/TbDkjbxxController.java
@@ -53,7 +53,7 @@
     @Autowired
     private ITbDkjbxxService tbDkjbxxService;
     @Autowired
-    private ShpToDataSourceService service;
+    private ShpToDataSourceService shpToDataSourceService;
     @Autowired
     private IWaylineFileService waylineFileService;
 
@@ -63,11 +63,11 @@
         return ResponseResult.success(list);
     }
 
-    /**
-     * 上传文件并保存到数据库
-     * @param file 需要上传的文件,通过multipart/form-data方式提交
-     * @return 返回上传结果的ResponseResult对象,其中包含上传成功的消息
-     */
+//    /**
+//     * 上传文件并保存到数据库
+//     * @param file 需要上传的文件,通过multipart/form-data方式提交
+//     * @return 返回上传结果的ResponseResult对象,其中包含上传成功的消息
+//     */
 //    @PostMapping("/upload")
 //    public ResponseResult<String> uploadFile(@RequestParam("file") MultipartFile file) {
 //        tbDkjbxxService.uploadFile(file);
@@ -76,6 +76,16 @@
 //        return tbDkjbxxService.uploadFile(file);
 //    }
 
+    /**
+     * 将sqlite里的数据入库并生成航线
+     * @param workspaceId
+     * @param waylineName
+     * @param airportLat
+     * @param airportLon
+     * @param request
+     * @return
+     * @throws Exception
+     */
     @PostMapping("/uploadLot")
     public ResponseResult getGeo(@RequestParam String workspaceId,
                                  @RequestParam String waylineName,
@@ -83,7 +93,7 @@
                                  @RequestParam double airportLon,
                                  HttpServletRequest request) throws Exception {
         List<TbDkjbxxEntity> list = tbDkjbxxService.list();
-        service.savaInMysql(list,workspaceId);
+        shpToDataSourceService.savaInMysql(list,workspaceId);
         MultipartFile multipartFile = tbDkjbxxService.listFile(workspaceId, waylineName, airportLat, airportLon);
         CustomClaim customClaim = (CustomClaim) request.getAttribute(TOKEN_CLAIM);
         String creator = customClaim.getUsername();
diff --git a/src/main/java/com/dji/sample/territory/controller/TbFjController.java b/src/main/java/com/dji/sample/territory/controller/TbFjController.java
index c65dbed..3ad1e49 100644
--- a/src/main/java/com/dji/sample/territory/controller/TbFjController.java
+++ b/src/main/java/com/dji/sample/territory/controller/TbFjController.java
@@ -23,15 +23,23 @@
     @Autowired
     private ITbFJService tbFJService;
     @Autowired
-    private GetPatchesService getPatches;
+    private GetPatchesService getPatchesService;
 
+    /**
+     * 将地块所保留的照片、视频信息保存到sqlite
+     *
+     * @param dkbh
+     * @param workspaceId
+     * @return
+     * @throws IOException
+     */
     @PostMapping("/insertDb")
     public ResponseResult insertDb(String dkbh, String workspaceId) throws IOException {
-        List<MediaFileEntity> list = getPatches.listPohto(dkbh, workspaceId);
+        List<MediaFileEntity> list = getPatchesService.listPohto(dkbh, workspaceId);
         if (list.size() == 0) {
             return ResponseResult.error("未找到该照片、视频信息");
         }
-        LotInfo lotInfo = getPatches.getLotinfo(dkbh, workspaceId);
+        LotInfo lotInfo = getPatchesService.getLotinfo(dkbh, workspaceId);
         if (lotInfo == null) {
             return ResponseResult.error("未找到该图斑信息");
         }
diff --git a/src/main/java/com/dji/sample/territory/service/impl/TbDkjbxxServiceImpl.java b/src/main/java/com/dji/sample/territory/service/impl/TbDkjbxxServiceImpl.java
index bb4cd4f..82ec6a2 100644
--- a/src/main/java/com/dji/sample/territory/service/impl/TbDkjbxxServiceImpl.java
+++ b/src/main/java/com/dji/sample/territory/service/impl/TbDkjbxxServiceImpl.java
@@ -18,6 +18,7 @@
 import org.locationtech.jts.geom.Coordinate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.FileCopyUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.multipart.MultipartFile;
@@ -86,6 +87,7 @@
      * @return MultipartFile 对象,包含压缩后的航迹文件。
      * @throws IOException 如果文件操作失败,则抛出IOException。
      */
+    @Transactional
     public MultipartFile listFile(String workspaceId, String waylineName, double airportLat, double airportLon) throws IOException {
         List<TbDkjbxxEntity> list = mapper.selectList(null);
         List<LotInfo> info = dbConvertToEntity(list);
diff --git a/src/main/java/com/dji/sample/territory/service/impl/TbFjServiceImpl.java b/src/main/java/com/dji/sample/territory/service/impl/TbFjServiceImpl.java
index 27724eb..0f534bd 100644
--- a/src/main/java/com/dji/sample/territory/service/impl/TbFjServiceImpl.java
+++ b/src/main/java/com/dji/sample/territory/service/impl/TbFjServiceImpl.java
@@ -4,13 +4,17 @@
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.dji.sample.media.model.MediaFileEntity;
+import com.dji.sample.patches.config.pojo.PatchesConfigPojo;
 import com.dji.sample.patches.model.entity.LotInfo;
+import com.dji.sample.patches.utils.MultipartFileTOFileUtil;
 import com.dji.sample.territory.dao.ITbFjMapper;
 import com.dji.sample.territory.model.entity.TbFjEntity;
 import com.dji.sample.territory.service.ITbFJService;
-import com.google.gson.JsonObject;
+import com.dji.sample.territory.utils.VideoZipUtil;
+import com.dji.sample.territory.utils.WaterMark;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.io.*;
 import java.net.HttpURLConnection;
@@ -23,7 +27,9 @@
 @DS("sqlite-ret")
 public class TbFjServiceImpl implements ITbFJService {
     @Autowired
-    private ITbFjMapper mapper;
+    private ITbFjMapper tbFjMapper;
+    @Autowired
+    private PatchesConfigPojo patchesConfigPojo;
 
     /**
      * 按照地块编号所对应的信息和音视频文件存入sqlite数据库
@@ -33,6 +39,7 @@
      * @return
      * @throws IOException
      */
+    @Transactional
     public int insertData(List<MediaFileEntity> mediaFile, LotInfo lotInfo) throws IOException {
         int count = 0;
         List<TbFjEntity> list = new ArrayList<>();
@@ -41,7 +48,7 @@
             MediaFileEntity file = mediaFile.get(i);
             tbFj = dbConvertToEntity(file, lotInfo);
             list.add(tbFj);
-            mapper.insert(tbFj);
+            tbFjMapper.insert(tbFj);
             count++;
         }
         return count;
@@ -56,6 +63,8 @@
      * @throws IOException
      */
     private TbFjEntity dbConvertToEntity(MediaFileEntity mediaFile, LotInfo lotInfo) throws IOException {
+        File file1 = null;
+        byte[] FJ = null;
         String jsonString = JSONObject.toJSONString(mediaFile.getMetadata());
         JSONObject jsonObject = JSONObject.parseObject(jsonString);
         Double absoluteAltitude = jsonObject.getDouble("absoluteAltitude");
@@ -64,6 +73,7 @@
         JSONObject shootPosition = jsonObject.getJSONObject("shootPosition");
         Double lat = shootPosition.getDouble("lat");
         Double lng = shootPosition.getDouble("lng");
+        //本地数据库没有的数据在FJ表非空用0
         int psjd = 0;
         String fjhxz = "0";
         int pshgj = 0;
@@ -72,15 +82,23 @@
         String zsdm = "0";
         String dklx = "0";
         String xzqdm = "0";
+        int fjlx = 1;
         Long pssj = mediaFile.getCreateTime();
         String bsm = UUID.randomUUID().toString();
         String fjmc = mediaFile.getFileName();
         String key = mediaFile.getObjectKey();
         String head = "http://dev.jxpskj.com:9000/cloud-bucket";
         String url = head + key;
-        File file =downloadFile(url);
-        File file1=WaterMark.addWatermark(file,patchesConfigPojo.getUnzip(),pssj,lat,lng);
-        byte[] FJ = fileToByteArray(file1);
+        File file = downloadFile(url);
+        //对应图片和视频文件进行不同处理
+        boolean endsWith = key.endsWith(".mp4");
+        if (!endsWith) {
+            file1 = WaterMark.addWatermark(file, patchesConfigPojo.getUnzip(), pssj, lat, lng);
+            FJ = fileToByteArray(file1);
+        } else {
+            file1 = VideoZipUtil.compressVideo(file, 800000, 128000, 1280, 720);
+            FJ = fileToByteArray(file1);
+        }
         TbFjEntity.TbFjEntityBuilder builder = TbFjEntity.builder();
         if (lotInfo != null) {
             builder.bsm(bsm)
@@ -91,9 +109,9 @@
                     .jdgd(absoluteAltitude)
                     .Latitude(lat)
                     .longitude(lng)
-//                    .fj(FJ)
+                    .fj(FJ)
                     .fjmc(fjmc)
-                    .fjlx(1)
+                    .fjlx(fjlx)
                     .psfyj(gimbalYawDegree)
                     .pssj(String.valueOf(pssj))
                     .psjd(psjd)
@@ -116,28 +134,22 @@
      * @param fileUrl
      * @return
      */
-    public  File downloadFile(String fileUrl) {
-
+    public File downloadFile(String fileUrl) {
         File downloadedFile = null;
-        String localFilePath =  patchesConfigPojo.getUnzip()+ "tmp.jpg";
+        String localFilePath = patchesConfigPojo.getUnzip() + "tmp.jpg";
         try {
             URL url = new URL(fileUrl);
             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
             connection.setRequestMethod("GET");
-
             downloadedFile = new File(localFilePath);
+            InputStream inputStream = connection.getInputStream();
+            OutputStream outputStream = new FileOutputStream(downloadedFile);
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
 
-            try (InputStream inputStream = connection.getInputStream();
-                 OutputStream outputStream = new FileOutputStream(downloadedFile)) {
-                byte[] buffer = new byte[1024];
-                int bytesRead;
-                while ((bytesRead = inputStream.read(buffer)) != -1) {
-                    outputStream.write(buffer, 0, bytesRead);
-                }
             }
-
-            System.out.println("File downloaded and saved at: " + downloadedFile.getAbsolutePath());
-
         } catch (IOException e) {
             e.printStackTrace();
         }
@@ -145,6 +157,13 @@
         return downloadedFile;
     }
 
+    /**
+     * 将文件转换为字节数组。
+     *
+     * @param file 需要转换的文件对象。
+     * @return 文件内容的字节数组。
+     * @throws IOException 如果读取文件发生错误。
+     */
     public static byte[] fileToByteArray(File file) throws IOException {
         FileInputStream fis = new FileInputStream(file);
         byte[] data = new byte[(int) file.length()];
@@ -152,5 +171,4 @@
         fis.close();
         return data;
     }
-
 }
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/territory/utils/ImgZipUtil.java b/src/main/java/com/dji/sample/territory/utils/ImgZipUtil.java
new file mode 100644
index 0000000..39a842b
--- /dev/null
+++ b/src/main/java/com/dji/sample/territory/utils/ImgZipUtil.java
@@ -0,0 +1,42 @@
+package com.dji.sample.territory.utils;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+
+public class ImgZipUtil {
+    /**
+     * 图片压缩
+     *
+     * @param originalImageFile
+     * @param compressionQuality 图片压缩质量 0-1
+     * @return
+     * @throws IOException
+     */
+    public static File compressImageAndGetFile(File originalImageFile, float compressionQuality) throws IOException {
+        BufferedImage originalImage = ImageIO.read(originalImageFile);
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
+            try (ImageOutputStream ios = new MemoryCacheImageOutputStream(baos)) {
+                writer.setOutput(ios);
+                ImageWriteParam param = writer.getDefaultWriteParam();
+                param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                param.setCompressionQuality(compressionQuality);
+                writer.write(null, new javax.imageio.IIOImage(originalImage, null, null), param);
+            } finally {
+                writer.dispose();
+            }
+            InputStream in = new ByteArrayInputStream(baos.toByteArray());
+            File tempFile = File.createTempFile("compressed-", ".jpg");
+            tempFile.deleteOnExit();
+            Files.copy(in, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            return tempFile;
+        }
+    }
+}
diff --git a/src/main/java/com/dji/sample/territory/utils/VideoZipUtil.java b/src/main/java/com/dji/sample/territory/utils/VideoZipUtil.java
new file mode 100644
index 0000000..34e3765
--- /dev/null
+++ b/src/main/java/com/dji/sample/territory/utils/VideoZipUtil.java
@@ -0,0 +1,54 @@
+package com.dji.sample.territory.utils;
+
+import ws.schild.jave.Encoder;
+import ws.schild.jave.EncoderException;
+import ws.schild.jave.MultimediaObject;
+import ws.schild.jave.encode.AudioAttributes;
+import ws.schild.jave.encode.EncodingAttributes;
+import ws.schild.jave.encode.VideoAttributes;
+import ws.schild.jave.info.VideoSize;
+
+import java.io.File;
+import java.io.IOException;
+
+public class VideoZipUtil {
+    /**
+     * 视频压缩
+     * @param sourceFile 需要压缩的原始视频文件
+     * @param bitRate 视频的比特率,用于控制视频的质量和文件大小
+     * @param audioBitRate 音频的比特率,用于控制音频的质量和文件大小
+     * @param width 压缩后视频的宽度
+     * @param height 压缩后视频的高度
+     */
+    public static File compressVideo(File sourceFile, int bitRate, int audioBitRate, int width, int height) {
+        try {
+            // 创建临时文件来保存压缩后的视频内容
+            File compressedFile = File.createTempFile("compressed_video", ".mp4");
+
+            // 创建音频属性
+            AudioAttributes audio = new AudioAttributes();
+            audio.setCodec("aac");
+            audio.setBitRate(audioBitRate);
+
+            // 创建视频属性
+            VideoAttributes video = new VideoAttributes();
+            video.setCodec("h264");
+            video.setBitRate(bitRate);
+            video.setSize(new VideoSize(width, height));
+
+            // 创建转码属性
+            EncodingAttributes attrs = new EncodingAttributes();
+            attrs.setAudioAttributes(audio);
+            attrs.setVideoAttributes(video);
+
+            // 进行视频转码
+            Encoder encoder = new Encoder();
+            encoder.encode(new MultimediaObject(sourceFile), compressedFile, attrs);
+            // 返回压缩后的临时文件
+            return compressedFile;
+        } catch (IOException | EncoderException e) {
+            e.printStackTrace();
+            throw new IllegalArgumentException("视频压缩失败");
+        }
+    }
+}
diff --git a/src/main/java/com/dji/sample/territory/utils/WaterMark.java b/src/main/java/com/dji/sample/territory/utils/WaterMark.java
new file mode 100644
index 0000000..3fb012a
--- /dev/null
+++ b/src/main/java/com/dji/sample/territory/utils/WaterMark.java
@@ -0,0 +1,106 @@
+package com.dji.sample.territory.utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+
+import static com.dji.sample.territory.utils.ImgZipUtil.compressImageAndGetFile;
+
+public class WaterMark {
+    /**
+     * 将图片加上水印并压缩
+     *
+     * @param file
+     * @param path
+     * @param pssj
+     * @param lat
+     * @param lng
+     * @return 添加水印并压缩后的图片文件。
+     * @throws IOException 如果读取或保存图片失败。
+     */
+    public static File addWatermark(File file, String path, Long pssj, Double lat, Double lng) throws IOException {
+        Long timestamp = pssj; // 例如:Unix 时间戳(以秒为单位)
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String sd = sdf.format(new Date(Long.parseLong(String.valueOf(timestamp))));
+        File originalImageFile = new File(file.toURI());
+        BufferedImage originalImage;
+        try {
+            originalImage = ImageIO.read(originalImageFile);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("读取图片失败"+e.getMessage());
+        }
+
+        // 创建 Graphics2D 对象以在图像上绘制水印
+        Graphics2D g2d = originalImage.createGraphics();
+
+        // 设置水印文字 "国土调查云"
+        String watermarkText = "国土调查云";
+
+        // 设置水印文字样式
+        g2d.setColor(Color.WHITE); // 设置为白色
+        float alpha = 0.5f; // 设置透明度为 0.5
+        AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
+        g2d.setComposite(alphaComposite);
+
+        g2d.setFont(new Font("宋体", Font.BOLD, 200)); // 使用宋体字体
+
+        // 设置水印位置(左上角)
+        int x1 = 400; // 左上角水印位置 x 坐标
+        int y1 = 1200; // 左上角水印位置 y 坐标
+
+        // 旋转35度角
+        double angle = Math.toRadians(35);
+        AffineTransform at = AffineTransform.getRotateInstance(angle, x1, y1);
+        g2d.setTransform(at);
+
+        // 绘制左上角旋转水印文字
+        g2d.drawString(watermarkText, x1, y1);
+        // 设置第一个水印完毕,恢复透明度为不透明状态(透明度为 1.0)
+        alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
+        g2d.setComposite(alphaComposite);
+        String extraInfo = String.format("时间:%s\nlon:%.9f lat:%.6f", sd, lng, lat);
+        g2d.setFont(new Font("宋体", Font.BOLD, 50)); // 使用宋体字体,更小的字号
+        g2d.setBackground(Color.black);
+        // 计算文本宽度和高度
+        FontMetrics fm = g2d.getFontMetrics();
+        int textWidth = fm.stringWidth(extraInfo);
+        int textHeight = fm.getHeight();
+        // 恢复坐标系到正常状态(不旋转)
+        g2d.setTransform(new AffineTransform());
+        // 设置文本位置(右下角)
+        int x2 = originalImage.getWidth() - textWidth - 30; // 右对齐的 x 坐标
+        int y2 = originalImage.getHeight() - textHeight - 65; // 最底部位置 y 坐标
+        // 绘制文本信息
+        String[] lines = extraInfo.split("\n");
+        for (String line : lines) {
+            // 计算每行文本的宽度
+            int lineWidth = fm.stringWidth(line);
+            // 将文本的起始位置设置为图像宽度减去文本的宽度
+            g2d.drawString(line, x2 + textWidth - lineWidth, y2);
+            y2 += g2d.getFontMetrics().getHeight(); // 增加行高
+        }
+        // 释放 Graphics2D 对象
+        g2d.dispose();
+        // 保存添加水印后的图片
+        File outputFile = new File(path + "mark.jpg");
+        File originalImageFiles = new File(outputFile.toURI());
+        float compressionQuality = 0.5f; // 0.0 - 1.0, higher value means better quality
+        File compressedImageFile = compressImageAndGetFile(originalImageFiles, compressionQuality);
+        try {
+            ImageIO.write(originalImage, "jpg", outputFile);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("水印图片保存失败");
+        }
+        return compressedImageFile;
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index e467728..80e4a08 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -17,12 +17,12 @@
           password: jxpskj_2018
         sqlite-resource:
           driver-class-name: org.sqlite.JDBC
-          url: jdbc:sqlite:D:\汇图信息\空天一体检测系统\图斑\resource_db.db
+          url: jdbc:sqlite:DB/resource_db.db
           username:
           password:
         sqlite-ret:
           driver-class-name: org.sqlite.JDBC
-          url: jdbc:sqlite:D:\汇图信息\空天一体检测系统\图斑\result_db.db
+          url: jdbc:sqlite:DB/result_db.db
           username:
           password:
 #    url: jdbc:mysql://192.168.2.104:3306/drone_test?useSSL=false&allowPublicKeyRetrieval=true
diff --git a/src/main/resources/tmp/mark.jpg b/src/main/resources/tmp/mark.jpg
new file mode 100644
index 0000000..024c101
--- /dev/null
+++ b/src/main/resources/tmp/mark.jpg
Binary files differ
diff --git a/src/main/resources/tmp/tmp.jpg b/src/main/resources/tmp/tmp.jpg
new file mode 100644
index 0000000..3df14e6
--- /dev/null
+++ b/src/main/resources/tmp/tmp.jpg
Binary files differ

--
Gitblit v1.9.3