javacv 图片合成

/**
 * 图片组合
 */
@Slf4j
public class ComposeImageUtil {

    /**
     * 合成商品链接
     *
     * @param composeGoodsImageCmd
     * @param oSSUtil
     * @return
     */
    public static String handleComposeGoodsImage(ComposeGoodsImageCmd composeGoodsImageCmd, OSSUtil oSSUtil) {
        //图片上传路径
        String keyName = composeGoodsImageCmd.getKeyName();
        //合成图宽高
        Long imgWidth = composeGoodsImageCmd.getImgWidth();
        Long imgHigh = composeGoodsImageCmd.getImgHigh();
        //修正规则
        String amendmentRules = composeGoodsImageCmd.getAmendmentRules();
        //主商品有效面积(英文逗号隔开)
        String effectiveArea = composeGoodsImageCmd.getEffectiveArea();
        //主商品中心点坐标(x_y,x_y,x_y)
        String centralPoint = composeGoodsImageCmd.getCentralPoint();
        //主商品合成顺序(英文逗号隔开)
        String order = composeGoodsImageCmd.getOrder();
        //前置商品数
        Integer frontGoodsNum = composeGoodsImageCmd.getFrontGoodsNum() == null ? 0 : composeGoodsImageCmd.getFrontGoodsNum();
        List<DubboWeimobCollocationGoodsBaseDTO> collocationGoodsBaseList = composeGoodsImageCmd.getCollocationGoodsBaseDTOList();
        if (
                ObjectUtils.isEmpty(imgWidth) || imgWidth < 1 ||
                        ObjectUtils.isEmpty(imgHigh) || imgHigh < 1 ||
                        StringUtils.isBlank(amendmentRules) || StringUtils.isBlank(effectiveArea) ||
                        StringUtils.isBlank(centralPoint) || StringUtils.isBlank(order) ||
                        ObjectUtils.isEmpty(collocationGoodsBaseList) || StringUtils.isBlank(keyName)
        ) {
            log.error("handleComposeGoodsImage attribute is null. imgWidth ={},imgHigh ={},amendmentRules ={},EffectiveArea ={},CentralPoint ={},Order ={},collocationGoodsBaseList size={}",
                    imgWidth, imgHigh, amendmentRules, effectiveArea, centralPoint, order, collocationGoodsBaseList.size());
            return null;
        }
        //修正规则
        Map<Integer, List<AmendmentRule>> aidaCollocateAmendmentRuleMap = JSONObject.parseObject(amendmentRules, HashMap.class);
        //主商品有效面积转换
        String[] EffectiveAreaStr = effectiveArea.split(",");
        long[] EffectiveAreaArray = new long[EffectiveAreaStr.length];
        for (int EffectiveAreaindex = 0; EffectiveAreaindex < EffectiveAreaStr.length; EffectiveAreaindex++) {
            EffectiveAreaArray[EffectiveAreaindex] = Integer.parseInt(EffectiveAreaStr[EffectiveAreaindex]);
        }
        //主商品中心点坐标(x_y,x_y,x_y)转换
        String[] CentralPointStr = centralPoint.split(",");
        int[][] CentralPointArray = new int[CentralPointStr.length][2];
        for (int CentralPointindex = 0; CentralPointindex < CentralPointStr.length; CentralPointindex++) {
            String[] point = CentralPointStr[CentralPointindex].split("_");
            CentralPointArray[CentralPointindex] = new int[]{Integer.parseInt(point[0]), Integer.parseInt(point[1])};
        }
        //组合顺序转换
        String[] orderStr = order.split(",");
        int[] orderArray = new int[orderStr.length];
        for (int Orderindex = 0; Orderindex < orderStr.length; Orderindex++) {
            orderArray[Orderindex] = Integer.parseInt(orderStr[Orderindex]);
        }
        if (
                collocationGoodsBaseList.size() != EffectiveAreaArray.length ||
                        collocationGoodsBaseList.size() != CentralPointArray.length || collocationGoodsBaseList.size() != orderArray.length
        ) {
            log.error("handleComposeGoodsImage data Num fail. collocationGoodsBaseList size={},EffectiveAreaArray size ={},aidaCollocateAmendmentRuleMap size ={},CentralPointArray size ={},orderArray size={}",
                    collocationGoodsBaseList.size(), EffectiveAreaArray.length, aidaCollocateAmendmentRuleMap.size(), CentralPointArray.length, orderArray.length);
            //素材数量不足退出
            return null;
        }
        //时间统计
        StopWatch clock = new StopWatch();
        clock.start(" <=== 图片【" + keyName + "】初始化png透明背景时间 ");
        //初始化png透明背景
        BufferedImage bufferedImage = createPng(imgWidth.intValue(), imgHigh.intValue());
        clock.stop();
        //遍历组合顺序下标
        for (int orderIndex : orderArray) {
            int position = orderIndex - 1;
            //获取修正规则
            List<AmendmentRule> amendmentRulesList = aidaCollocateAmendmentRuleMap.get(position);
            position = position - frontGoodsNum;
            clock.start(" <=== 图片【" + keyName + "】商品下标【" + position + "】时间 ");
            //得到商品
            DubboWeimobCollocationGoodsBaseDTO collocationGoodsBase = collocationGoodsBaseList.get(position);
            //得到商品理应的有限
            Long meffectiveArea = EffectiveAreaArray[position];
            //得到中心点坐标
            int[] point = CentralPointArray[position];
            //旋转角度
            int angle = 0;
            //计算
            int[] calculate = AmendmentRuleUtil.calculate(amendmentRulesList, meffectiveArea.intValue(),
                    angle,
                    collocationGoodsBase.getWidth(), collocationGoodsBase.getHigh(),
                    point[0], point[1]);
            //计算出缩放比
            double scale = Math.sqrt(((double) calculate[0]) / collocationGoodsBase.getEffectiveArea());
            //角度
            angle = calculate[1];


            //宽高计算、压缩
            int width = (int) (collocationGoodsBase.getWidth() * scale);
            int high = (int) (collocationGoodsBase.getHigh() * scale);
            //旋转后
            int[] calcRotatedSize = calcRotatedSize(width, high, angle);
            width = calcRotatedSize[0];
            high = calcRotatedSize[1];
            //计算中心点
            int centerPointX = (width / 2);
            int centerPointY = (high / 2);
            //计算左上角坐标
            int x = calculate[2] - centerPointX;
            int y = calculate[3] - centerPointY;
            //图片Url处理

            String imgUrl = collocationGoodsBase.getCuttingDiagramImageIntranetUrl();
            imgUrl = OSSUrlUtil.rotate(imgUrl, angle);
            imgUrl = OSSUrlUtil.specifyWidthAndHeight(imgUrl, width, high);
            try {
                stickImg(bufferedImage, ImgUtil.read(new URL(imgUrl)), x, y);
            } catch (Exception e) {
                e.printStackTrace();
            }
            clock.stop();
        }
        clock.start(" <=== 图片【" + keyName + "】bufferedImage转InputStream时间 ");
        //上传
        InputStream inputStream = BufferedImageCollocateUtil.bufferedImageInputStreamBGRA(bufferedImage);
        clock.stop();
        //上传云存储
        clock.start(" <=== 图片【" + keyName + "】上传云存储时间 ");
        oSSUtil.internalPutFileByInputStream(keyName, inputStream);
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        clock.stop();
        log.debug("图片【" + keyName + "】耗时统计:{}", clock.prettyPrint());
        //获取云存储地址
        return oSSUtil.getURLOfTheFileInternalCheck(keyName);

    }


    /**
     * 贴按顺序贴图返回整图
     *
     * @param stickImgOrderCmd 配饰参数
     */
    public static BufferedImage stickImgOrderToBufferedImage(StickImgOrderCmd stickImgOrderCmd) {
        if (ObjectUtils.isEmpty(stickImgOrderCmd)) {
            return null;
        }
        Long width = stickImgOrderCmd.getWidth();
        Long heigh = stickImgOrderCmd.getHeigh();
        if (ObjectUtils.isEmpty(width) || ObjectUtils.isEmpty(heigh)) {
            return null;
        }
        //贴图顺序
        Byte[] layerOrderArray = {0, 1, 2};
        if (StringUtils.isNotBlank(stickImgOrderCmd.getLayerOrder())) {
            String[] layerOrderSplit = stickImgOrderCmd.getLayerOrder().split(",");
            layerOrderArray = new Byte[layerOrderSplit.length];
            for (int layerOrderIndex = 0; layerOrderIndex < layerOrderSplit.length; layerOrderIndex++) {
                layerOrderArray[layerOrderIndex] = Byte.parseByte(layerOrderSplit[layerOrderIndex]);
            }
        }
        //图片的图片地址
        Map<Byte, String> imageUrlMap = new HashMap<>();
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_0, stickImgOrderCmd.getBackGroundUrl());
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_1, stickImgOrderCmd.getGoodsImageMasterUrl());
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_2, stickImgOrderCmd.getGoodsImageSlaveUrl());
        //合成图片
        BufferedImage bufferedImage = ComposeImageUtil.createPng(width.intValue(), heigh.intValue());
        for (Byte layer : layerOrderArray) {
            String imageUrl = imageUrlMap.get(layer);
            if (StringUtils.isNotBlank(imageUrl)) {
                try {
                    stickImg(bufferedImage, ImgUtil.read(new URL(imageUrl)), 0, 0);
                } catch (Exception e) {
                }
            }
        }
        return bufferedImage;
    }


    /**
     * 贴按顺序贴图返回组装对象
     *
     * @param stickImgOrderCmd 配饰参数
     */
    public static List<ComposeImageCoordinateDTO> stickImgOrderToJson(StickImgOrderCmd stickImgOrderCmd) {
        if (ObjectUtils.isEmpty(stickImgOrderCmd)) {
            return null;
        }
        Long width = stickImgOrderCmd.getWidth();
        Long heigh = stickImgOrderCmd.getHeigh();
        //贴图顺序
        Byte[] layerOrderArray = {0, 1, 2};
        if (StringUtils.isNotBlank(stickImgOrderCmd.getLayerOrder())) {
            String[] layerOrderSplit = stickImgOrderCmd.getLayerOrder().split(",");
            layerOrderArray = new Byte[layerOrderSplit.length];
            for (int layerOrderIndex = 0; layerOrderIndex < layerOrderSplit.length; layerOrderIndex++) {
                layerOrderArray[layerOrderIndex] = Byte.parseByte(layerOrderSplit[layerOrderIndex]);
            }
        }
        //图片的图片地址
        Map<Byte, String> imageUrlMap = new HashMap<>();
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_0, stickImgOrderCmd.getBackGroundUrl());
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_1, stickImgOrderCmd.getGoodsImageMasterUrl());
        imageUrlMap.put(AidaCompositeConstant.AIDACOMPOSE_LAYERORDER_2, stickImgOrderCmd.getGoodsImageSlaveUrl());
        //合成图片
        //中心点坐标x
        Long centerPointX = width / 2;
        //中心点坐标y
        Long centerPointY = heigh / 2;
        //数据组装
        List<ComposeImageCoordinateDTO> coordinateList = new ArrayList<>();
        for (int layerOrder = 0; layerOrder < layerOrderArray.length; layerOrder++) {
            Byte layer = layerOrderArray[layerOrder];
            String imageUrl = imageUrlMap.get(layer);
            if (StringUtils.isNotBlank(imageUrl)) {
                ComposeImageCoordinateDTO composeImageCoordinate = new ComposeImageCoordinateDTO();
                composeImageCoordinate.setWidth(width);
                composeImageCoordinate.setHeigh(heigh);
                composeImageCoordinate.setCenterPointX(centerPointX.intValue());
                composeImageCoordinate.setCenterPointY(centerPointY.intValue());
                composeImageCoordinate.setImageUrl(OSSUrlUtil.specifyWidthAndHeight(imageUrl, width.intValue(), heigh.intValue()));
                composeImageCoordinate.setLayer(layerOrder);
                coordinateList.add(composeImageCoordinate);
            }
        }
        return coordinateList;
    }


    /**
     * 创建透明图
     *
     * @param width
     * @param height
     * @return
     */
    public static BufferedImage createPng(int width, int height) {
        // 创建BufferedImage对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取Graphics2D
        Graphics2D g2d = image.createGraphics();
        // ----------  背景透明开始  -----------------
        image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2d.dispose();
        // ----------  背景透明代码结束  -----------------
        return image;
    }

    /**
     * 计算转换后目标矩形的宽高
     *
     * @param width
     * @param height
     * @param angle  角度
     * @return 目标矩形
     */
    private static int[] calcRotatedSize(int width, int height, int angle) {
        if (angle == 0 || angle % 360 == 0) {
            return new int[]{width, height};
        }
        double cos = Math.abs(Math.cos(Math.toRadians(angle)));
        double sin = Math.abs(Math.sin(Math.toRadians(angle)));
        int des_width = (int) (width * cos) + (int) (height * sin);
        int des_height = (int) (height * cos) + (int) (width * sin);
        return new int[]{des_width, des_height};
    }


    /**
     * 贴图片
     *
     * @param srcImage 底图
     * @param pressImg 贴图
     * @param x        坐标x(必填)
     * @param y        坐标y(必填)
     */
    public static void stickImg(BufferedImage srcImage, BufferedImage pressImg, int x, int y) {
        if (ObjectUtils.isEmpty(srcImage) || ObjectUtils.isEmpty(pressImg)) {
            return;
        }
        //将图片放到指定位置
        Graphics2D graphics2D = srcImage.createGraphics();
        graphics2D.drawImage(pressImg, x, y, null);
        graphics2D.dispose();
    }

    /**
     * 贴文字
     *
     * @param srcImage 底图
     * @param color    颜色
     * @param font     字体
     * @param text     文本
     * @param x        坐标x(必填)
     * @param y        坐标y(必填)
     */
    public static void stickText(BufferedImage srcImage, Color color, Font font, String text, int x, int y) {
        if (ObjectUtils.isEmpty(srcImage) || ObjectUtils.isEmpty(font) || StringUtils.isBlank(text)) {
            return;
        }
        // 创建画笔
        Graphics2D graphics2D = srcImage.createGraphics();
        // 设置画笔颜色为白色
        // pen.setColor(Color.WHITE);
        graphics2D.setColor(color);
        // 设置画笔字体样式为微软雅黑,斜体,文字大小为20px
        graphics2D.setFont(font);
        // 写上水印文字和坐标
        graphics2D.drawString(text, x, y);
        graphics2D.dispose();

    }

}

  

posted @ 2022-06-24 16:46  随风而逝,只是飘零  阅读(299)  评论(0编辑  收藏  举报