ImageMagick圖片服務器

1.前置準備工具以下:node

  1. nodejs
  2. express(nodejs mvc框架)
  3. body-parser(express middleware)
  4. gm(nodejs中用來處理圖片的)
  5. uuid(nodejs中用於生成uuid)
  6. underscore(nodejs數據處理庫)
  7. ImageMagick(gm會調用該程序處理圖片)

 2.搭建項目
  使用express來快速搭建項目,圖片服務器的功能相對簡單,步驟:一、獲取圖片資源 二、上傳圖片,所以對應express只須要使用到bodyParser這樣的基本組件,代碼大體以下:git

//app.js
var app = require('express')();
process.app = app;//方便在其餘地方使用app獲取配置

require('./config')(__dirname, app);//全部配置
var mode = app.get('mode');
require('./controller/' + mode + 'Controller.js');

var config = app.get(mode);
require('http').createServer(app).listen(config.port, function () {
    console.log('%s已經啓動,正監聽:%s', config.name, config.port);
});

//config.js
var path = require('path');

var OPTIONS = {
        targetDir: function (app) {
                return path.join(app.get('rootDir'), 'img');
        },
        read: {
                name: '<<圖片服務器(讀取)>>',
                port: 80,
                'default': 'default.jpg',
                sizeReg: /(\w+)-(\d+)-(\d+)\.(\w+)$/
        },
        save: {
                name: '<<圖片服務器(保存)>>',
                port: 9990
        },
        mode: 'read',
        contentType: {
                'jpg': 'image/jpeg',
                'jpeg': 'image/jpeg',
                'gif': 'image/gif',
                'png': 'image/png'
        }
};

module.exports = function (rootDir, app) {
    app.set('rootDir', rootDir);

    var $ = require('underscore');
    $.each(OPTIONS, function (v, k) {
        app.set(k, typeof v === 'function' ? v(app) : v);
    });

    app.use(require('body-parser')())
};

3.獲取圖片github

用戶根據url獲取圖片服務器內存儲的圖片,當後臺接收這個請求後,首先判斷圖片上會否存在,若是存在則返回對應的圖片不然返回默認的圖片,大體代碼以下:web

var path = require('path');
var fs = require('fs');
var gm = require('gm').subClass({ imageMagick: true });//默認的狀況下 gm使用的是另一個圖片處理程序

var app = process.app;
var config = app.get('read');
var targetDir = app.get('targetDir');

app.get('/:filename', function (req, res) {
        var filePath = path.join(targetDir, req.params.filename);
        fs.exists(filePath, function (exists) {
                res.sendfile(exists ? filePath : path.join(targetDir, config.default));
        });
});

使用以上的代碼即可以對圖片進行讀取了,可是隻能對targetDir目錄下的文件進行讀取且沒有對文件類型進行判斷,對文件類型的判斷比較簡單隻要在方法執行以前對文件擴展名進行判斷便可,至於增長了文件夾結構的話,跟直接從targetDir目錄下讀取是差很少的流程,稍微調整一下代碼:express

var contentTypes = app.get('contentType');

app.get('/:filename', function (req, res) {
        sendFile([], req.params.filename, res);
});

app.get('/:folder/:filename', function (req, res) {
        sendFile([req.params.folder], req.params.filename, res);
});

app.get('/:folder1/:folder2/:name', function (req, res) {
        sendFile([req.params.folder1, req.params.folder2], req.params.filename, res);
});

function sendFile(folders, filename, res) {
        var ext = path.extname(filename).substr(1);
        if (!contentTypes[ext])
                return res.sendfile(getFilePath());

        folders.push(filename);
        var filePath = getFilePath(path.join.apply(path, folders));
        fs.exists(filePath, function (exists) {
                res.sendfile(exists ? filePath : getFilePath());
        });
}

function getFilePath(filename) {
        return path.join(app.get('targetDir'), filename || config.default);
}

接下來假設一個場景,若是上傳了一張800*600的圖片,可是在頁面上顯示的時候,也許我只想顯示一張200*150的縮略圖,這時候gm就該登場了,咱們可使用gm來爲800*600的圖片臨時生成一張200*150的圖片,並以buffer的形式回傳給客戶端,大體代碼以下:json

//判斷請求圖片是否存在
if (exists)                                                     
        return res.sendfile(filePath);     
                         
var groups = filename.match(config.sizeReg);                    
if (!groups)                                                    
        return res.sendfile(getFilePath());                         
                                                                
folders[len] = groups[1] + "." + groups[4];              
filePath = getFilePath(path.join.apply(path, folders));         
var width = parseInt(groups[2]);                                
var height = parseInt(groups[3]);   
//判斷原始圖是否存在                            
fs.exists(filePath, function (exists) {                         
        if (!exists)                                                
                filePath = getFilePath();                               
                                                                
        var gm = gm(filePath);                                      
        if (width > 0 && height > 0)                                
                gm.resize(width, height);                               
        gm.toBuffer(function (err, buffer) {                        
                if (err)                                                
                        return res.sendfile(getFilePath());                 
                                                                
                res.set('Content-Type', contentTypes[ext]);             
                res.send(buffer);                                       
        });                                                         
});                                

4.上傳圖片服務器

因爲圖片服務器只提供最簡單的功能,支持文件上傳(製做水印以及其餘的處理在下一篇中講述),也不會將此功能開放到外網,所以圖片上傳服務器是在內網的,只能從web服務器那邊處理圖片之後上傳到圖片服務器,圖片服務器對其進行存儲並返回存儲後的圖片路徑,大體代碼以下:mvc

var buf = require('buffer');
var fs = require('fs');
var path = require('path');
var util = require('util');
var gm = require('gm').subClass({ imageMagick: true });
var uuid = require('uuid');

var app = process.app;
var contentTypes = app.get('contentType');

/*
        請求包含以下參數:
        @ext    圖片擴展名
        @buffer 圖片buffer數據
        @folder 文件夾,格式:/aa/bb
*/
app.post('/', function (req, res) {
        var ext = req.body.ext;
        var buffer = req.body.buffer;
        if (!(ext && buffer && contentTypes[ext]))
                return res.json({ success: false });

        var pathArgs = req.body.folder.replace(/\n/g, '');
        if (pathArgs)
                pathArgs = pathArgs.substr(1).split('/');
        else
                pathArgs = [''];

        createDir(pathArgs);

        pathArgs.push('');
        var filePath = createPath(pathArgs, ext);
        gm(new buf.Buffer(JSON.parse(buffer))).write(filePath, function (err) {
                if (err)
                        return res.json({ success: false });

                res.json({ success: true, data: util.format('\\%s.%s', pathArgs.join('\\'), ext) });
        });
});

function createDir(pathArgs) {
        if (pathArgs[0]) {
                var dir = path.join(app.get('targetDir'), path.join.apply(path, pathArgs));
                var exists = fs.existsSync(dir);
                if (!exists)
                        fs.mkdirSync(dir);
        }
}

function createPath(pathArgs, ext) {
        var args = [app.get('targetDir')];
        pathArgs[pathArgs.length - 1] = uuid.v1().replace(/-/g, '');
        args.push.apply(args, pathArgs);
        var filePath = path.join.apply(path, args) + '.' + ext;
        return fs.existsSync(filePath) ? createPath(pathArgs, ext) : filePath;
}
相關文章
相關標籤/搜索