首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring + JS + HTML 圖片上傳與裁切完整實作(含 Lodop 列印)

     編輯:Java 相關知識

功能概覽

使用者上傳頭像 → 前端裁切預覽 → 後端按座標裁切縮放 → 回存資料庫 → 整合 Lodop 列印預覽。技術棧:Spring MVC、jQuery imgAreaSelect 裁切插件、ajaxFileUpload 非同步上傳、Java ImageIO 處理圖片。

前端關鍵實作

1. 頁面引入資源

<link rel="stylesheet" href="${frontRes}/imgareaselect/css/imgareaselect-animated.css" />
<script src="${frontRes}/imgareaselect/jquery-1.4.2.min.js"></script>
<script src="${frontRes}/imgareaselect/jquery.imgareaselect.pack.js"></script>
<script src="${frontRes}/imgareaselect/ajaxfileupload.js"></script>

2. 非同步上傳並即時預覽

function addFile(obj) {
    $.ajaxFileUpload({
        url: '${huluUrl}/trainer/upload/ajaxUpload',
        secureuri: false,
        fileElementId: 'photoFile',
        dataType: 'json',
        success: function(data) {
            var info = eval("(" + data + ")");
            var arr = info.data;
            $("#img").attr("src", "/images/" + arr.photo); // 更新大圖
            initCropper(arr.photo); // 初始化裁切區
        },
        error: function() { alert('上傳失敗'); }
    });
}

3. 裁切區初始化與預覽同步

function initCropper(photoName) {
    var $photo = $('#photo').attr('src', '/images/' + photoName);
    $photo.one('load', function() {
        var imgW = $photo.width(), imgH = $photo.height();
        var size = Math.min(imgW, imgH); // 正方形裁切區
        var ias = $photo.imgAreaSelect({
            aspectRatio: '1:1', handles: true, fadeSpeed: 200,
            onSelectChange: preview, instance: true
        });
        ias.setSelection(0, 0, size-1, size-1);
        ias.setOptions({show: true}); ias.update();
        // 同步座標到隱藏欄位供後端使用
        $('#x1s').val(0); $('#y1s').val(0);
        $('#x2s').val(size-1); $('#y2s').val(size-1);
        $('#imgx').val(imgW); $('#imgy').val(imgH);
    });
}

function preview(img, sel) {
    if (!sel.width || !sel.height) return;
    var scaleX = 100 / sel.width, scaleY = 100 / sel.height;
    var imgW = parseInt($('#photo').css('width')), imgH = parseInt($('#photo').css('height'));
    $('#preview img').css({
        width: Math.round(scaleX * imgW), height: Math.round(scaleY * imgH),
        marginLeft: -Math.round(scaleX * sel.x1), marginTop: -Math.round(scaleY * sel.y1)
    });
    // 回填座標
    $('#x1').val(sel.x1); $('#y1').val(sel.y1);
    $('#x2').val(sel.x2); $('#y2').val(sel.y2);
    $('#w').val(sel.width); $('#h').val(sel.height);
    $('#x1s').val(sel.x1); $('#y1s').val(sel.y1);
    $('#x2s').val(sel.x2); $('#y2s').val(sel.y2);
}

後端核心 Controller

1. 非同步上傳暫存原圖

@RequestMapping("/ajaxUpload")
@ResponseBody
public AjaxResult ajaxUpload(MultipartHttpServletRequest request) {
    MultipartFile file = request.getFile("photoFile");
    if (file.isEmpty()) return AjaxResult.error();

    String ext = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
    String saveName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ext;
    File dest = new File("E:/rudongImage/photo/", saveName);
    FileCopyUtils.copy(file.getBytes(), dest);

    Trainer trainer = new Trainer();
    trainer.setPhoto("photo/" + saveName);
    trainer.setUserId(FrontShiroUtil.getUserId());
    trainerDbSvc.updateTrainerPhoto(trainer); // 先存暫存路徑
    return AjaxResult.success(trainer);
}

2. 裁切確認:按比例映射座標並裁切

@RequestMapping(value = "uploadPhotoTest", method = RequestMethod.POST)
public ModelAndView uploadPhotoTest(
        @RequestParam("x1s") int x1, @RequestParam("y1s") int y1,
        @RequestParam("x2s") int x2, @RequestParam("y2s") int y2,
        @RequestParam("imgx") int imgW, @RequestParam("imgy") int imgH) {

    Trainer trainer = trainerRepo.findOne(FrontShiroUtil.getUserId());
    File src = new File("E:/rudongImage/" + trainer.getPhoto());
    BufferedImage bi = ImageIO.read(src);
    int srcW = bi.getWidth(), srcH = bi.getHeight();

    // 前端預覽圖可能被縮放,需按比例換算回原圖座標
    int base = Math.min(srcW, srcH); // 原圖裁切基準邊
    int previewBase = Math.min(imgW, imgH); // 前端預覽基準邊
    int sx = x1 * base / previewBase;
    int sy = y1 * base / previewBase;
    int ex = x2 * base / previewBase;
    int ey = y2 * base / previewBase;

    // 呼叫工具類裁切
    ImageUtil util = new ImageUtil();
    String newName = util.cutImage(src, "E:/rudongImage/photo/", sx, sy, ex - sx, ey - sy);
    trainer.setPhoto("photo/" + newName);
    trainerDbSvc.updateTrainerPhoto(trainer);
    return new ModelAndView("redirect:/trainer/upload/toUploadPhoto");
}

ImageUtil 核心裁切邏輯

public void cutImage(File src, String destDir, int x, int y, int w, int h) {
    FileInputStream fis = new FileInputStream(src);
    ImageInputStream iis = ImageIO.createImageInputStream(fis);
    ImageReader reader = ImageIO.getImageReadersBySuffix(getSuffix(src)).next();
    reader.setInput(iis, true);
    ImageReadParam param = reader.getDefaultReadParam();
    param.setSourceRegion(new Rectangle(x, y, w, h)); // 關鍵:只讀取指定區域
    BufferedImage bi = reader.read(0, param);
    String outName = "cut_" + System.currentTimeMillis() + "_" + src.getName();
    ImageIO.write(bi, getSuffix(src), new File(destDir, outName));
    // 關閉流...
    return outName;
}

Lodop 列印整合(補充)

<object id="LODOP_OB" classid="clsid:2105C259-1E0C-4534-8141-A753534CB4CA" width=0 height=0>
    <embed id="LODOP_EM" type="application/x-print-lodop" width=0 height=0></embed>
</object>
<script src="/js/Lodop/LodopFuncs.js"></script>

function PrintURL() {
    var LODOP = getLodop(document.getElementById('LODOP_OB'), document.getElementById('LODOP_EM'));
    LODOP.PRINT_INIT("");
    LODOP.ADD_PRINT_HTM(45, 55, 770, 1004, document.getElementById("print").innerHTML);
    LODOP.PREVIEW(); // 或 PRINT()
}

Tomcat 需配置虛擬目錄映射圖片儲存路徑:server.xml 加入 <Context docBase="G:\Image" path="/images" />。

總結

本方案完整串聯:非同步上傳 → 前端裁切預覽 → 座標比例換算 → 後端高效裁切(ImageReadParam 只讀取目標區域,記憶體友善) → 列印輸出。適合需求「上傳即裁切、列印輸出」的實名認證、證照上傳等業務場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved