1. 程式人生 > >響應微博小祕書倡議 連夜加急擼出頭像變灰小工具之開發歷程

響應微博小祕書倡議 連夜加急擼出頭像變灰小工具之開發歷程

昨天看到了微博小祕書關於全國性悼念活動倡議,我非常支援這個倡議。 因為修改灰色頭像會有一定技術門檻,於是思考能否開發一個小工具方便大家使用。 考慮到第二天就是哀悼日,準備夜間快速開發上線。

 

0X00 廢話少說先上東西

有興趣的老哥可以訪問:http://smartding.top:81/ 或者 http://smartding.top:8080/

因為暫時無法備案,所以只能採用帶埠或者純 IP 的方式訪問,有點鬱悶。

小工具裡面記錄了專案歷程,有興趣可以閱讀,

 

0X01 選型

因為時間相當有限,技術選型必須選擇較為成熟的腳手架型框架。

基於這樣的原則出發,前端框選用 Element.io,Element.io 優勢是支援 CDN 引用,你甚至不需要建立一個 Webpack 專案,提供的元件既有顏值也非常穩定可靠,文件也十分齊全。後端框架則採用 Springboot,通過簡單引入 Springboot 依賴就可以輕鬆建立一個 Java web 專案。

 

0X02 核心演算法

技術選型完成之後,開始考慮核心演算法也就是如何把彩色圖片轉為灰度圖片。我沒有圖片處理經驗,但經過摸索大致瞭解了轉換方法。轉換演算法其實就是下面的數學公式:

 

gray(red, green, blue)  = (red + green + blue)/3

 

主要思路是把求得每個畫素的RGB 三色平均值,如此把三維的顏色空間對映到一維的灰度空間。通過逐一轉換圖片的每一個畫素,最終我們得到一副只包含灰度的圖片。

 

具體實現如下:

        int width = img.getWidth();
        int height = img.getHeight();

        for (int i = 0; i < height; i++) {

            for (int j = 0; j < width; j++) {

                int p = img.getRGB(j, i);

                int a = (p >> 24) & 0xff;
                int r = (p >> 16) & 0xff;
                int g = (p >> 8) & 0xff;
                int b = p & 0xff;

                int avg = (r + g + b)/3;

                //replace RGB value with avg
                p = (a << 24) | (avg << 16) | (avg << 8) | avg;

                img.setRGB(j, i, p);
            }
        }

 

 

0X03 對抗惡意刷流

第二個難點是如何既保證使用體驗又避免惡意刷流量,考慮到應用的生命週期極短,我採用的方法是頻寬採用按流量計費,應用中增加單 IP 下載次數限制, Guava 的 Cache 類很好的滿足了我需求。

 

具體實現如下:

         // Cache 定義,注意到 expireAfterWrite 非常關鍵,它用來控制限流週期。
         private final LoadingCache<String, AtomicInteger> cache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.DAYS).build(new CacheLoader<String, AtomicInteger>() {
            @Override
            public AtomicInteger load(final String s) throws Exception {
                return new AtomicInteger(0);
            }
        });


        // 超限檢查
        String ip = request.getRemoteAddr();
        AtomicInteger counter = cache.get(ip);

        if (counter.getAndIncrement() > 50) {
            log.error("ip {} try too many time, rejected!", ip);
            throw new RuntimeException("try too many!");
        }

 

0X04 總結

這是我的一個人作品,甚至我還獲得的人生的第一粒金(有慷慨老哥支援了 0.1 元),這個專案技術難度不高,最難的部分其實是推廣,即如何讓更多的人瞭解到你的作品,這個是我的短板。不管怎麼說,我離正式創業專案也邁進了一步,儘管沒有什麼收入能做出一個有價值的小工具我也非常高興。

 

覺得好有可以分享給朋友,感謝啦。

&n