2016年9月28日 星期三

ByteArrayOutputStream - Java - close 後可取出資料的OutputStream

ByteArrayOutputStream繼承OutputStream,但跟平常看到的例如FileOutputStream、ServletOutputStream等不同,它是可以在資料輸出至OutputStream後、甚至在被close()後,還可以將資料取回的一種OutputStream,例如可用其擁有的方法,toByteArray(),來取得byte[]型別的資料。

例如以之前的文章為例,使用Java製作GIF動畫 - AnimatedGifEncoder,其中
OutputStream o = response.getOutputStream();
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.start(o);
o.flush();
o.close();

也可寫成:

ByteArrayOutputStream oo = new ByteArrayOutputStream();
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
encoder.start(oo);  //
/* some code */
oo.flush();
oo.close();

byte[] gif_btyeArray = oo.toByteArray();
/* you can do something with gif_byteAray */
OutputStream o = response.getOutputStream();
o.write(gif_btyeArray );
o.flush();
o.close();

可以看到我們先把輸出的資料先送到ByteArrayOutputStream裡,在其close()後,還可以利用ByteArrayOutputStream的toByteArray()取回資料,對資料做想要的處理之後,再送給ServeltOutputSteam

參考資料:
  1. java.ByteArrayInputStream与ByteArrayOutputStream再次理解http://blog.csdn.net/rcoder/article/details/6118313
  2. How can we read or use the contents of outputstream [closed]

2016年9月27日 星期二

使用Java製作GIF動畫 - AnimatedGifEncoder

今天要來介紹一個對於用Java生成動態GIF特別好用的類別, AnimatedGifEncoder,
由Kevin Weiner所撰寫,

下面以一個簡單的例子來演示如何使用。

需求如下:

  1. 寫一個servlet,其接到request後可輸出一個GIF動畫。
  2. 在一個htm內用<img>的src接接看測試

實作的檔案結構如下:

各檔內容如下(AnimatedGifEncoder.java就不介紹了):

  1. index.html
    <!DOCTYPE html>
    <html>
        <head>
            <title>Animated Gif Test</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <style>
                /* 為img加上背景色,測試透明GIF動畫 */
                img {
                    background-color: black;
                }
            </style>
        </head>
        <body>
            <div>Animated Gif Test</div>
            <!-- 測試GIF動畫 -->
            <img src="AnimatedGif.do" />
        </body>
    </html>
  2. AnimatedGif.java
    /*
     * To change this license header, choose License Headers in Project Properties.
     * To change this template file, choose Tools | Templates
     * and open the template in the editor.
     */
    package servlet;
    
    import java.awt.Color;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.io.OutputStream;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import tools.AnimatedGifEncoder;
    
    @WebServlet(name = "AnimatedGif", urlPatterns = {"/AnimatedGif.do"})
    public class AnimatedGif extends HttpServlet {
    
        /**
         * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
         * methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            OutputStream o = response.getOutputStream();
            response.setContentType("image/gif"); //設定-- header -- ContentType
            
            Color transparentColor = Color.WHITE;
            
            AnimatedGifEncoder encoder = new AnimatedGifEncoder();
            encoder.setTransparent(transparentColor); //設定透明色
            encoder.setDelay(100);  //設定frame之間的間隔 (毫秒)
            encoder.setRepeat(0);  //設定重覆迴圈次數(不設就是不重覆), 0:無限, 1:重覆一次...
            encoder.start(o);      //綁定OutputStream  
            
            //產生畫布
            BufferedImage generatedImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
            //產生繪圖工具
            Graphics2D graphics2D = generatedImage.createGraphics();
            for (int i = 0; i < 10 ; i++){
                //畫底色
                graphics2D.setColor(transparentColor);
                graphics2D.fillRect(0, 0, generatedImage.getWidth(), generatedImage.getHeight());
                //畫圓圈
                graphics2D.setColor(Color.RED);
                graphics2D.drawOval(i*3, 25, 50, 50);
                //加到GIF動畫frame中
                encoder.addFrame(generatedImage);
            }
            graphics2D.dispose(); //釋放資源
     encoder.finish();  //GIF動畫結束
            //串流輸出
            o.flush();
            o.close();
        }
    
        // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
        /**
         * Handles the HTTP <code>GET</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
    
        /**
         * Handles the HTTP <code>POST</code> method.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
    
        /**
         * Returns a short description of the servlet.
         *
         * @return a String containing servlet description
         */
        @Override
        public String getServletInfo() {
            return "Short description";
        }// </editor-fold>
    
    }
    
    
    
成果展示:
video

原始碼下載:
AnimatedGifEncoderTest.7z

參考資料:

  1. Java – How To Overlay One Image Over Another Using Graphics2D [Tutorial]
  2. 在Java應用程序中創建圖像的方法和技巧
  3. Is there a way to create one Gif image from multiple images in Java? [closed]
  4. 在Java中使用AnimatedGifEncoder生成GIF動畫
  5. [Android] AnimatedGifEncoder
  6. java将gif动态图片分开展示源代码简单示例

2016年9月17日 星期六

typescript + SystemJS + npm + jQuery (Netbeans, Eclipse)

這篇主要紀錄在Netbeans和Eclipse中使用Typescript,並配合SystemJS的範例,再來我們要利用npm來安裝JQuery並用SystemJS引入JQuery模組,學習建立自己的javascript module。

這篇要實現的需求如下:
  1. 在Netbeans和Eclipse中使用typescript外掛編譯我們的ts檔成js檔。
  2. 使用npm安裝JQuery。
  3. 使用SystemJS引入JQuery模組並使用。
  4. 建立一個自製的JS module, Greeter,配製好相應的package.json和export設定,放到node_modules中。
  5. import自制的Greeter,並建立一個myGreeter去entend(繼承)Greeter擴充功能。
以下是我們完成的目錄結構,需注意到的是,藍色框線標示的js及map檔是ts檔被typescript編譯出來的檔案:



接下來講解步驟:

2016年9月10日 星期六

使用raycaster實現Object的選取 - three.js

three.js可以在Scene放置許多的Object3D,但如果我們想要讓User跟那些Obejct做互動,那要如何做呢,例如User在Camera的畫面中看到許多的物件,想用滑鼠去點擊那些物件去做互動。

在three.js中,有一個Raycaster類可以做到上述需求,它的原裡是,想像有一條光束(ray)從Camera畫面中滑鼠指的位置,以垂直於Camera的X-Y平面的方式向Camera的負Z方向射出,並且計算在Scene的children中有哪些物件被這條線射中(ray可以穿過所有Object3D)。 

在這裡,我要來示範一個使用three.js的Raycaster的範例,需求是這樣的:

需求:
  1. 畫面上有許多的Object3D物件,有各自的顏色。
  2. 當滑鼠指到(hover)某一個Object時,將指到的第一個Object變成紅色(即它後面的Object不會變色)。
  3. 滑鼠移開後,剛剛指到但現在沒指的Object變回原來的顏色。
接下來一步步的講解每一個步驟: