Browse Source

feat: 生成融合动画 & 遮罩缩放能力

hexleo 5 years ago
parent
commit
33db211bc4

+ 1 - 1
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java

@@ -85,7 +85,7 @@ public class AnimTool {
             }
             for (SrcSet.Src src : commonArg.srcSet.srcs) {
                 if (src.w <=0 || src.h <= 0) {
-                    TLog.i(TAG, "vapx error: src.w=" + src.w + ",src.h=" + src.h);
+                    TLog.i(TAG, "vapx error: src.id=" + src.srcId + ",src.w=" + src.w + ",src.h=" + src.h);
                     return false;
                 }
             }

+ 2 - 0
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArgTool.java

@@ -62,6 +62,8 @@ class CommonArgTool {
 
         // srcId自动生成 & 融合动画路径检查 & z序
         if (commonArg.isVapx) {
+            // vapx 强制缩小
+            commonArg.scale = 0.5f;
             int size = commonArg.srcSet.srcs.size();
             SrcSet.Src src;
             for (int i=0; i<size; i++) {

+ 10 - 2
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java

@@ -152,6 +152,14 @@ public class ToolUI {
             commonArg.audioPath = textAudioPath.getText();
         }
 
+        if (vapxUI.isVapxEnable()) {
+            commonArg.isVapx = true;
+            commonArg.srcSet = vapxUI.getSrcSet();
+            if (commonArg.srcSet == null) {
+                return;
+            }
+        }
+
         TLog.i(TAG, commonArg.toString());
 
         AnimTool animTool = new AnimTool();
@@ -396,8 +404,8 @@ public class ToolUI {
         JScrollPane areaScrollPane = new JScrollPane(txtAreaLog);
         areaScrollPane.setVerticalScrollBarPolicy(
                 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
-        areaScrollPane.setPreferredSize(new Dimension(WIDTH, 150));
-        areaScrollPane.setMinimumSize(new Dimension(WIDTH, 150));
+        areaScrollPane.setPreferredSize(new Dimension(WIDTH, 100));
+        areaScrollPane.setMinimumSize(new Dimension(WIDTH, 100));
 
         panel.add(areaScrollPane);
         panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));

+ 83 - 6
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/VapxUI.java

@@ -1,12 +1,14 @@
 package com.tencent.qgame.playerproj.animtool.ui;
 
+import com.tencent.qgame.playerproj.animtool.TLog;
 import com.tencent.qgame.playerproj.animtool.vapx.SrcSet;
 
 import java.awt.Dimension;
 import java.awt.FlowLayout;
-import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
@@ -14,9 +16,11 @@ import java.util.List;
 
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JLabel;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JSeparator;
@@ -24,6 +28,7 @@ import javax.swing.JTextField;
 
 public class VapxUI {
 
+    private static final String TAG = "VapxUI";
 
     private final Dimension labelSize = new Dimension(100, 20);
     private final JPanel controlPanel = new JPanel();
@@ -41,8 +46,8 @@ public class VapxUI {
     public JPanel createUI() {
         JPanel panel = new JPanel();
         panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
-        panel.setPreferredSize(new Dimension(ToolUI.WIDTH, ToolUI.HEIGHT / 3));
-        panel.setMinimumSize(new Dimension(ToolUI.WIDTH, ToolUI.HEIGHT / 3));
+        panel.setPreferredSize(new Dimension(ToolUI.WIDTH, 300));
+        panel.setMinimumSize(new Dimension(ToolUI.WIDTH, 300));
         controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.PAGE_AXIS));
         controlPanel.add(getAddLayout());
         JScrollPane areaScrollPane = new JScrollPane(controlPanel);
@@ -50,6 +55,24 @@ public class VapxUI {
         return panel;
     }
 
+    public boolean isVapxEnable() {
+        return !maskUiList.isEmpty();
+    }
+
+    public SrcSet getSrcSet() {
+        if (maskUiList.isEmpty()) return null;
+        SrcSet srcSet = new SrcSet();
+
+        SrcSet.Src src;
+        for (MaskUI maskUI : maskUiList) {
+            src = maskUI.getSrc();
+            if (src == null) return null;
+            srcSet.srcs.add(src);
+        }
+
+        return srcSet;
+    }
+
 
     private JPanel getAddLayout() {
         JPanel panel = new JPanel();
@@ -92,6 +115,10 @@ public class VapxUI {
         private final String[] fitTypeArray = new String[]{SrcSet.Src.FIT_TYPE_FITXY, SrcSet.Src.FIT_TYPE_CF};
         private final JComboBox<String> boxFitType = new JComboBox<>(fitTypeArray);
 
+        private final JPanel txtPanel = new JPanel();
+        private final JTextField textTxtColor = new JTextField();
+        private final JCheckBox checkTxtBold = new JCheckBox("text Bold");
+
         final JLabel labelMaskPathState = new JLabel();
 
         public MaskUI(int index, IMaskUIListener listener) {
@@ -104,12 +131,44 @@ public class VapxUI {
             return panel;
         }
 
+        public SrcSet.Src getSrc() {
+            SrcSet.Src src = new SrcSet.Src();
+            src.srcId = String.valueOf(index);
+            src.srcTag = textSrcTag.getText().trim();
+            src.srcType = (String) boxSrcType.getSelectedItem();
+            src.fitType = (String) boxFitType.getSelectedItem();
+            src.srcPath = maskPath;
+
+            if (SrcSet.Src.SRC_TYPE_TXT.equals(src.srcType)) {
+                src.color = textTxtColor.getText().trim();
+                if (checkTxtBold.isSelected()) {
+                    src.style = SrcSet.Src.TEXT_STYLE_BOLD;
+                }
+            }
+
+            if (src.srcTag == null || "".equals(src.srcTag)) {
+                String msg = "id:" + index + " source tag is empty";
+                TLog.e(TAG, msg);
+                JOptionPane.showMessageDialog(panel, msg, "Error", JOptionPane.ERROR_MESSAGE);
+                return null;
+            }
+
+            if (src.srcPath == null || "".equals(src.srcPath)) {
+                String msg = "id:" + index + " mask path is empty";
+                TLog.e(TAG, msg);
+                JOptionPane.showMessageDialog(panel, msg, "Error", JOptionPane.ERROR_MESSAGE);
+                return null;
+            }
+            return src;
+        }
+
         private void createUI() {
             panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
 
             setMaskPath();
             panel.add(part1Layout());
             panel.add(part2Layout());
+            panel.add(part3Layout());
             panel.add(new JSeparator());
         }
 
@@ -137,7 +196,12 @@ public class VapxUI {
             panel.add(new JLabel(" source type:"));
             boxSrcType.setSelectedIndex(0);
             panel.add(boxSrcType);
-
+            boxSrcType.addItemListener(new ItemListener() {
+                @Override
+                public void itemStateChanged(ItemEvent itemEvent) {
+                    txtPanel.setVisible(SrcSet.Src.SRC_TYPE_TXT.equals(itemEvent.getItem()));
+                }
+            });
             // fitType
             panel.add(new JLabel(" fit type:"));
             boxFitType.setSelectedIndex(0);
@@ -177,17 +241,30 @@ public class VapxUI {
             return panel;
         }
 
+
         private JPanel part2Layout() {
-            JPanel panel = new JPanel();
+            JPanel panel = txtPanel;
             panel.setLayout(new FlowLayout(FlowLayout.LEFT));
 
-            panel.add(labelMaskPathState);
+            panel.add(new JLabel(" text color:"));
+            textTxtColor.setPreferredSize(new Dimension(100, 20));
+            textTxtColor.setText("#000000");
+            panel.add(textTxtColor);
 
+            panel.add(checkTxtBold);
+            panel.setVisible(false);
             return panel;
         }
 
 
+        private JPanel part3Layout() {
+            JPanel panel = new JPanel();
+            panel.setLayout(new FlowLayout(FlowLayout.LEFT));
 
+            panel.add(labelMaskPathState);
+
+            return panel;
+        }
     }
 
     private interface IMaskUIListener {

+ 38 - 3
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/vapx/GetMaskFrame.java

@@ -4,6 +4,8 @@ import com.tencent.qgame.playerproj.animtool.CommonArg;
 import com.tencent.qgame.playerproj.animtool.TLog;
 import com.tencent.qgame.playerproj.animtool.data.PointRect;
 
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
 import java.io.File;
 
@@ -77,14 +79,32 @@ public class GetMaskFrame {
             return null;
         }
 
+        PointRect maskPoint = new PointRect(
+            frame.frame.x,
+            frame.frame.y,
+            frame.frame.w,
+            frame.frame.h
+        );
+
         PointRect mFrame = new PointRect(x, y, frame.frame.w, frame.frame.h);
         // 计算是否能放下遮罩
         if (mFrame.x + mFrame.w > outW) { // 超宽换行
             mFrame.x = startX;
             mFrame.y = lastMaxY;
             if (mFrame.x + mFrame.w > outW) {
-                TLog.e(TAG, "frameIndex=" + frameIndex + ",src=" + src.srcId + ", no more space for(w)" + mFrame);
-                return null;
+
+                // 超长后缩放mask
+                float scale = (outW - mFrame.x) * 1f / mFrame.w;
+
+                mFrame.w = outW - mFrame.x;
+                mFrame.h = (int) (mFrame.h * scale);
+
+                maskPoint.x = (int) (maskPoint.x * scale);
+                maskPoint.y = (int) (maskPoint.y * scale);
+
+                maskArgb = scaleMask(scale, inputBuf);
+
+                TLog.w(TAG, "frameIndex=" + frameIndex + ",src=" + src.srcId + ", no more space for(w)" + mFrame + ",scale=" + scale);
             }
         }
         if (mFrame.y + mFrame.h > outH) { // 高度不够直接错误
@@ -93,7 +113,7 @@ public class GetMaskFrame {
         }
         frame.mFrame = mFrame;
 
-        fillMaskToOutput(outputArgb, outW, maskArgb, maskW, frame.frame, frame.mFrame, SrcSet.Src.SRC_TYPE_TXT.equals(src.srcType));
+        fillMaskToOutput(outputArgb, outW, maskArgb, maskW, maskPoint, frame.mFrame, SrcSet.Src.SRC_TYPE_TXT.equals(src.srcType));
 
         // 设置src的w,h 取所有遮罩里最大值
         synchronized (GetMaskFrame.class) {
@@ -106,6 +126,21 @@ public class GetMaskFrame {
         return frame;
     }
 
+    /**
+     * 缩放遮罩
+     */
+    private int[] scaleMask(float scale, BufferedImage inputBuf) {
+        AffineTransform at = new AffineTransform();
+        at.scale(scale, scale);
+
+        int w = inputBuf.getWidth();
+        int h = inputBuf.getHeight();
+        BufferedImage alphaBuf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+        AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
+        alphaBuf = scaleOp.filter(inputBuf, alphaBuf);
+
+        return alphaBuf.getRGB(0, 0, w, h, null, 0, w);
+    }
 
     /**
      * 获取遮罩位置信息 并转换为黑白