1. front

  1. HTML
    main.ejs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="description" content="How to create an image upload form without page refresh using Bootstrap, jQuery AJAX and PHP.">
        <meta name="author" content="ShinDarth">
     
     
        <link rel="stylesheet" type="text/css" href="/css/style.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
        <style>body { padding-top:50px; }.navbar-inverse .navbar-nav > li > a { color: #DBE4E1; }</style>
     
        <!--[if IE]>
        <script src="https://cdn.jsdelivr.net/html5shiv/3.7.2/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
    </head>
     
    <body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#"></a>
            </div>
     
        </div>
    </nav>
     
    <div class="container">
        <div class="containerStyle">
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h2>Google image analysis</h2>
                </div>
                <div class="panel-body">
                    <p class="lead">Select a PNG or JPEG image, having maximum size <span id="max-size"></span> KB.</p>
     
                    <div id="image-preview-div" style="display: none">
                        <label for="exampleInputFile">Selected image:</label>
                        <br>
                        <img id="preview-img" src="noimage">
                    </div>
                    <div class="form-group">
                        <input type="file" name="file" id="file" required>
                    </div>
     
                    <div class="text-center">
                        <button type="button" class="btn btn-primary" id="upload-image-button" disabled><i class="glyphicon glyphicon-film">Image analyze</i></button>
                        <button type="button" class="btn btn-primary" id="upload-text-button" disabled><i class="glyphicon glyphicon-file">Text analyze</i></button>
                    </div>
     
                    <br>
                    <div class="alert alert-info" id="loading" style="display: none;" role="alert">
                        Uploading image...
                        <div class="progress">
                            <div id="progress-bar" class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
     
     
        </div>
        <br><br>
        <div id="result" class="containerStyle">
     
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h2>Analyzed result</h2>
                </div>
                <div class="panel-body">
                    <h3>Analyzed result for user</h3>
                    <div class="panel panel-default" id="message-for-user"></div>
     
                    <h3>Analyzed result for developer</h3>
                    <button type="button" class="btn btn-info" data-toggle="collapse" data-target="#message-for-developer">show or hide</button>
                    <div id="message-for-developer" class="collapse panel panel-default"></div>
                </div>
            </div>
        </div>
     
     
     
     
     
    </div>
     
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
    <script src="/js/upload-image.js"></script>
    </body>
    </html>
    cs

    googleVisionConn.zip



  2. JAVASCRIPT
    upload-file.js



  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    /*jslint browser: true, white: true, eqeq: true, plusplus: true, sloppy: true, vars: true*/
    /*global $, console, alert, FormData, FileReader*/
     
     
    function noPreview() {
        $('#image-preview-div').css("display""none");
        $('#preview-img').attr('src''noimage');
        $('upload-button').attr('disabled''');
    }
     
    function selectImage(e) {
        $('#file').css("color""green");
        $('#image-preview-div').css("display""block");
        $('#preview-img').attr('src', e.target.result);
        $('#preview-img').css('max-width''550px');
    }
     
    $(document).ready(function (e) {
     
     
        //set up maxsize
        var maxsize = 500 * 1024// 500 KB
        $('#max-size').html((maxsize/1024).toFixed(2));
     
        $('#result').hide();
     
        $('#upload-text-button').click(function(){
     
            var formData = new FormData();
            var files = $('#file')[0].files[0];
            formData.append('file', files);
     
            $('#result').hide();
            $('#message-for-user').empty();
            $('#message-for-developer').empty();
            $('#loading').show();
     
     
            $.ajax({
                url: "/text",
                type: "POST",
                data: formData,
                contentType: false,
                cache: false,
                processData: false,
                success: function(data){
                    $('#loading').hide();
                    $('#message-for-user').append(`Description:${data[0]['description']}`);
                    $('#message-for-developer').append(JSON.stringify(data));
                    $('#result').show();
                }
            });
        });
     
        $('#upload-image-button').click(function(){
     
            var formData = new FormData();
            var files = $('#file')[0].files[0];
            formData.append('file', files);
     
     
            $('#result').hide();
            $('#message-for-user').empty();
            $('#message-for-developer').empty();
            $('#loading').show();
     
     
     
            $.ajax({
                url: "/image",
                type: "POST",
                data: formData,
                contentType: false,
                cache: false,
                processData: false,
                success: function(data){
                    $('#loading').hide();
                    $('#message-for-user').append(`Description:${data[0]['description']}`);
                    $('#message-for-developer').append(JSON.stringify(data));
                    $('#result').show();
                }
            });
        });
     
        //
        $('#file').change(function() {
     
            $('#message').empty();
     
            var file = this.files[0];
            var match = ["image/jpeg""image/png""image/jpg"];
     
            if ( !( (file.type == match[0]) || (file.type == match[1]) || (file.type == match[2]) ) )
            {
                noPreview();
     
                $('#message').html('<div class="alert alert-warning" role="alert">Unvalid image format. Allowed formats: JPG, JPEG, PNG.</div>');
     
                return false;
            }
     
            if ( file.size > maxsize )
            {
                noPreview();
     
                $('#message').html('<div class=\"alert alert-danger\" role=\"alert\">The size of image you are attempting to upload is ' + (file.size/1024).toFixed(2+ ' KB, maximum size allowed is ' + (maxsize/1024).toFixed(2+ ' KB</div>');
     
                return false;
            }
     
            $('#upload-image-button').removeAttr("disabled");
            $('#upload-text-button').removeAttr("disabled");
     
            var reader = new FileReader();
            reader.onload = selectImage;
            reader.readAsDataURL(this.files[0]);
     
        });
     
    });
    cs



    1. var files = $('#file')[0].files[0];하면, HTML 쪽에서  <input type="file" name="file" id="file" required로 업로드했던 파일이 files변수에 담기게 된다.
    2. var formData = new FormData();로 생성한 formData 객체에  formData.append('file', files);로 append하면, formData변수에 파일이 담긴다. 이걸로 서버로 전송할 준비가 완료.
    3. ajax에 담아서 송신


  4. CSS
    1
    2
    3
    4
    5
    6
    7
    8
    .containerStyle{
        max-width: 650px;
        margin: auto;
    }
    #progress-bar{
        width: 100%;
    }
    cs





2. Server


app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
'use strict';
global.__base = __dirname + "/src";
 
//require external modules
const bodyParser = require('body-parser');
const co = require('co');
const VisionExt = require(__base + '/google/vision_ext')
const formidable = require(__base + '/upload-file/formidable-send');
 
 
//Declare express and configurate
const express = require('express');
const app = express();
 
//Configure Directory path
app.use(bodyParser.urlencoded({extended : false}));
app.use(express.static('./public'));
app.set('view engine','ejs');
app.set('views''./views');
 
 
app.post('/image'function (req,res){
    const uploadedDir=__dirname + "/public/image";
    co(function*(){
        const tgFile = yield formidable.uploadFile(req,uploadedDir);
        const result = yield VisionExt.labelDetection(tgFile);
 
        yield res.send(result);
    })
});
 
app.post('/text'function (req,res){
    const uploadedDir=__dirname + "/public/image";
    co(function*(){
        const tgFile = yield formidable.uploadFile(req,uploadedDir);
        const result = yield VisionExt.textDetection(tgFile);
 
        yield res.send(result);
    })
});
 
app.get('/'function(req,res){
    res.render('main2');
});
 
 
app.listen(5100,'127.0.0.1'function() {
    console.log('connection complete. Open page localhost:5100');
});
cs


formidable 모듈로 ajax로 송신된 파일을 담음. 이때, req에는 송신된 file이 보이지 않지만 formidable로는 보이므로 req에서 보이지 않아도 크게 염려하지 말것.



formidable-send.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
'use strict';
 
const formidable = require('formidable');
const fs = require('fs');
 
 
exports.uploadFile=function(req,dir){
    return new Promise(function(resolve){
        const form = new formidable.IncomingForm(),
            files = [],
            fields = [];
 
        form.parse(req);
        form.uploadDir = dir;
 
        let tgFile;
        form
            .on('field'function(field, value) {
                console.log(field, value);
                fields.push([field, value]);
            })
            .on('file'function(field, file) {
                console.log(field, file);
                fs.renameSync(file.path, form.uploadDir + "/" + file.name);
                tgFile = form.uploadDir + "/" + file.name;
                files.push([field, file]);
            })
            .on('end'function() {
                console.log('-> upload done');
                resolve(tgFile);
            });
    });
}
cs




vision-ext.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
'use strict';
 
// Imports the Google Cloud client library
const vision = require('@google-cloud/vision');
 
// Creates a client
const client = new vision.ImageAnnotatorClient({
    keyFilename:__base+'/config/GAC.json'
});
 
exports.labelDetection=function(filePath){
    return new Promise(function(resolve){
        client
            .labelDetection(filePath)
            .then(results => {
                const detections = results[0].labelAnnotations;
                resolve(detections);
            })
            .catch(err => {
                console.error('ERROR:', err);
            });
    });
}
 
 
exports.textDetection=function(filePath){
    return new Promise(function(resolve){
        client
            .textDetection(filePath)
            .then(results => {
                const detections = results[0].textAnnotations;
                resolve(detections);
            })
            .catch(err => {
                console.error('ERROR:', err);
            });
    });
}
 
 
 
cs
















+ Recent posts