<commit_before>var debug = require('debug')('server:models:image');

var Promise = require('bluebird');

var path = require('path');
var child_process = require('child_process');

var gm = require('gm').subClass({imageMagick: true});
var dataobjectParser = require('dataobject-parser');

var Waterline = require('waterline');

var image = Waterline.Collection.extend({
	identity: 'image',
	tableName: 'images',
	connection: 'default',
	migrate: 'safe',

	attributes: {
		//initial submission
		originalFileName: 'string',
		url: 'string',
		fileName: 'string',
		path: 'string',
		fileSize: 'integer',
		type: 'string',
		md5: 'string',
		size: 'json',
		permalink: 'string',
		uploaderIP: 'string',
		metaComplete: 'boolean',

		//imagemagick
		depth: 'json',
		imageStatistics: 'json',
		channelStatistics: 'json',
		gamma: 'string',
		chromaticity: 'json',

		//exiv2
		exif: 'json',
		iptc: 'json',
		xmp: 'json',

		//phoenix
		hackerfactorQuality: 'float',
		imagemagickQuality: 'float',
		qtables: 'json',

		analyses: {
			collection: 'analysis',
			via: 'image'
		},

		filePath: function () {
			return path.join(this.path, this.fileName);
		},
		getGMInfo: function () {
			debug('image.getGMInfo');

			var filePath = this.filePath();

			return Promise.fromNode(function (callback) {
				gm(filePath).identify(callback);
			});
		},
		getExiv2Info: function () {
			debug('image.getExiv2Info');

			var dotParser = new dataobjectParser();
			var filePath = this.filePath();

			return Promise.fromNode(function (callback) {
				child_process.exec('exiv2 -pa ' + filePath, callback);
			})
			.spread(function (stdout, stderr) {
				//parsing exiv2 output
				var lines = stdout.split(/\r?\n/);
				for( var i = 0; i < lines.length; i++ ) {
					if( ! lines[i] ) {
						continue;
					}

					var line = lines[i].replace(/\s+/g, ' ');
					var parsed = line.split(' ');

					var key = parsed[0];
					var value = parsed.slice(3).join(' ');
					dotParser.set(key, value);
				}

				return dotParser.data();
			})
			.catch(function (err) {
				debug('error calling `exiv2 -pa`', err);

				throw err;
			});
		},
		queueAnalysis: function(options) {
			debug('image.queueAnalysis');

			options = options || {};
			var params = {};

			if( options.ela ) {
				var quality = options.ela.quality || config.defaultAnalysisOpts.ela.quality;
				//clamp it between [0-100]
				params.ela = {
					quality: Math.min(Math.max(quality, 0), 100)
				}
			}

			if( options.avgdist ) {
				params.avgdist = true;
			}

			if( options.lg ) {
				params.lg = true;
			}<commit_msg>handle exiv2 bug<commit_after>var debug = require('debug')('server:models:image');

var Promise = require('bluebird');

var path = require('path');
var child_process = require('child_process');

var gm = require('gm').subClass({imageMagick: true});
var dataobjectParser = require('dataobject-parser');

var Waterline = require('waterline');

var image = Waterline.Collection.extend({
	identity: 'image',
	tableName: 'images',
	connection: 'default',
	migrate: 'safe',

	attributes: {
		//initial submission
		originalFileName: 'string',
		url: 'string',
		fileName: 'string',
		path: 'string',
		fileSize: 'integer',
		type: 'string',
		md5: 'string',
		size: 'json',
		permalink: 'string',
		uploaderIP: 'string',
		metaComplete: 'boolean',

		//imagemagick
		depth: 'json',
		imageStatistics: 'json',
		channelStatistics: 'json',
		gamma: 'string',
		chromaticity: 'json',

		//exiv2
		exif: 'json',
		iptc: 'json',
		xmp: 'json',

		//phoenix
		hackerfactorQuality: 'float',
		imagemagickQuality: 'float',
		qtables: 'json',

		analyses: {
			collection: 'analysis',
			via: 'image'
		},

		filePath: function () {
			return path.join(this.path, this.fileName);
		},
		getGMInfo: function () {
			debug('image.getGMInfo');

			var filePath = this.filePath();

			return Promise.fromNode(function (callback) {
				gm(filePath).identify(callback);
			});
		},
		getExiv2Info: function () {
			debug('image.getExiv2Info');

			var dotParser = new dataobjectParser();
			var filePath = this.filePath();

			// return Promise.fromNode(function (callback) {
			return new Promise(function (resolve, reject) {
				child_process.exec('exiv2 -pa ' + filePath, function (err, stdout, stderr) {
					//handle exiv2 bug where it returns code 253 even when there is data
					if( err && ! (err.code == 253 && stdout) ) {
						return reject(err);
					}

					//parsing exiv2 output
					var lines = stdout.split(/\r?\n/);
					for( var i = 0; i < lines.length; i++ ) {
						if( ! lines[i] ) {
							continue;
						}

						var line = lines[i].replace(/\s+/g, ' ');
						var parsed = line.split(' ');

						var key = parsed[0];
						var value = parsed.slice(3).join(' ');
						dotParser.set(key, value);
					}

					return resolve(dotParser.data());
				});
			});
		},
		queueAnalysis: function(options) {
			debug('image.queueAnalysis');

			options = options || {};
			var params = {};

			if( options.ela ) {
				var quality = options.ela.quality || config.defaultAnalysisOpts.ela.quality;
				//clamp it between [0-100]
				params.ela = {
					quality: Math.min(Math.max(quality, 0), 100)
				}
			}

			if( options.avgdist ) {
				params.avgdist = true;
			}

			if( options.lg ) {
				params.lg = true;
			}
{'fraction_non_alphanumeric': 0.167107250755287, 'fraction_numerical': 0.008119335347432024, 'mean_word_length': 3.2006344171292627, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '733789', 'n_tokens_mistral': 2202, 'n_tokens_neox': 1784, 'n_words': 406}