Commit 0dbaa75c authored by Jarrod's avatar Jarrod 💬

Initial commit

parents
Pipeline #114 failed with stages
in 19 seconds
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
############################
# npm
############################
node_modules
npm-debug.log
# Build tools
.nyc_output
coverage
docs
############################
# tmp, editor & OS files
############################
.tmp
*.swo
*.swp
*.swn
*.swm
.DS_STORE
*#
*~
.idea
nbproject
.DS_Store
############################
# Tests
############################
coverage
############################
# Other
############################
.node_history
# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
paths:
- node_modules/
test:
stage: test
script:
- npm install
- npm test
- npm run mpdoc
# Extract coverage %age from Istanbull
coverage: '/All\s+files\s+[|]\s+([\d.]+)/'
artifacts:
paths:
- coverage/
- docs/
# Following along at https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/
# Remove .hidden_ to enable this..
pages:
stage: deploy
script:
- mv docs/ public/
- mv coverage/ public/coverage
artifacts:
paths:
- public
expire_in: 30 days
only:
- master
{
"esversion": 6,
// To fix column positions for JSHint errors you may want to add `"indent": 1` to your
// **User** "jshint_options". This issue affects users with tabs for indentation.
// This fix was reverted due to a conflict with using the `"white": true` option.
// "indent": 1,
"evil": true,
"regexdash": true,
"browser": true,
"wsh": true,
"sub": true,
// Suppress warnings about mixed tabs and spaces
"smarttabs": true,
// Suppress warnings about trailing whitespace
"trailing": false,
// Suppress warnings about the use of expressions where fn calls or assignments are expected
"expr": true,
// Suppress warnings about using functions inside loops (useful for inifinityCounters)
"loopfunc": true,
// Suppress warnings about using assignments where conditionals are expected
"boss": true,
// Suppress warnings about "weird constructions"
// i.e. allow code like:
// (new (function OneTimeUsePrototype () { } ))
"supernew": true,
// Allow backwards, node-dependency-style commas
"laxcomma": true
// "bitwise": true,
// "camelcase": true,
// "node": true,
// "undef": true,
// "unused": true,
// "curly": true,
// "immed": true,
// "latedef": true,
// "noarg": true,
// "noempty": true,
// "plusplus": true,
// "quotmark": "single",
// "trailing": true,
// "asi": false,
// "eqnull": true,
// "eval": true,
// "sub": true,
// "supernew": true,
// "eqeqeq": true,
// "eqnull": true
}
*#
node_modules
ssl
.DS_STORE
*.swo
*.swp
*.swn
*.swm
*~
.idea
nbproject
.git
.gitignore
.tmp
.jshintrc
.editorconfig
CONTRIBUTING.md
*.md
**/*.md
test
language: node_js
node_js:
- "10"
- "8"
- "6"
- "0.10"
- "0.12"
# whitelisted branches
branches:
only:
- master
# machinepack-images
[![pipeline status](https://git.carrotlabs.net/jarrod/machinepack-images/badges/master/pipeline.svg)](https://git.carrotlabs.net/jarrod/machinepack-images/pipelines)
[![coverage report](https://git.carrotlabs.net/jarrod/machinepack-images/badges/master/coverage.svg)](http://jarrod.pages.carrotlabs.net/machinepack-images/coverage)
---
Work with Images
[See here](http://jarrod.pages.carrotlabs.net/machinepack-images/)
## License
MIT © 2018 contributors
// This is a boilerplate file which should not need to be changed.
module.exports = require('machine').pack({
pkg: require('./package.json'),
dir: __dirname,
customize: {
arginStyle: 'serial',
execStyle: 'natural'
}
});
module.exports = {
friendlyName: 'Hash a file',
description: 'Get the hash representation of any file on disk',
sync: false,
inputs: {
file: {
description: 'Full path to the file',
type: 'string',
required: true,
example: '/home/bob/turkey.png',
},
algorithm: {
description: 'Generate hash digests using the given algorithm.',
extendedDescription: `The algorithm is dependent on the available algorithms
supported by the version of OpenSSL on the platform.
Examples are 'sha256', 'sha512', etc.
On recent releases of OpenSSL,
\`~$ openssl list -digest-algorithms\`
(\`openssl list-message-digest-algorithms\` for older versions of OpenSSL)
will display the available digest algorithms.`,
type: 'string',
defaultsTo: 'sha1',
moreInfoUrl: 'https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options'
},
},
exits: {
success: {
description: 'Done.',
outputExample: '40334c01de59ed96bab8e7772936bcc1352736a4',
},
},
fn: function(inputs, exits) {
var fs = require('fs');
var crypto = require('crypto');
// the file you want to get the hash
var fd = fs.createReadStream(inputs.file);
var hash = crypto.createHash(inputs.algorithm);
hash.setEncoding('hex');
fd.on('end', function() {
hash.end();
return exits.success( hash.read() );
});
// read all file and pipe it (write it) to the hash object
fd.pipe(hash);
},
};
module.exports = {
/*
// Note to a future me
// In our PHP version we do this a little better-ly
// ie, we keep the 'image profile' data and then put it back into the output-ed image
$i = new Imagick($input);
$profiles = $i->getImageProfiles("icc", true);
$i->stripImage();
if(!empty($profiles)) {
$i->profileImage("icc", $profiles['icc']);
}
$i->writeImage($output);
*/
friendlyName: 'Strip EXIF data',
description: 'Remove the emdedded exif metadata from a given image',
extendedDescription: "I\'m not entirely sure that this is doing the best it can for the job.\n\n" +
"It basically just makes a copy of the image without preserving metadata, but " +
"in the process my test files have shrunk _dramatically_ in size.\nBaked-in " +
"image colour profiles are lost in the conversion as well and there is a " +
"_barely_ noticable degredation in quality. As far as other ready-to-go options " +
"with Node JS are concerned I think this is unfortunately the best that's available " +
"for now without tearing apart (purportedly non-existant) EXIF standards documentation " +
"and building something that keeps the original image intact minus the EXIF 'stuff'.\n\n" +
\\\\_(ツ)_/¯",
sync: false,
inputs: {
source: {
description: 'Full path to the source image',
type: 'string',
required: true,
example: '/home/bob/turkey.jpg',
},
dest: {
description: 'Full path to the output image',
type: 'string',
required: true,
example: '/home/bob/turkey-noexif.jpg',
},
},
exits: {
success: {
description: 'Done.',
outputExample: {},
moreInfoUrl: 'http://sharp.pixelplumbing.com/en/stable/api-output/#tofile',
},
unreadable: {
description: 'The source file does not exist or you do not have permission to read it'
},
error: {
description: 'Unable to process or save the final image'
}
},
fn: function(inputs, exits) {
// var im = require('imagickal');
const sharp = require('sharp');
if (inputs.source === inputs.dest) {
throw { 'failed': 'Source and destination files cannot be the same!' };
}
// if (!inputs.dest) {
// inputs.dest = inputs.source;
// }
// Check if the source file is readable.
fs.access(inputs.source, fs.constants.R_OK, (err) => {
if (err) { throw 'unreadable'; }
// Basically just make a clone of the source in the destination minus metadata
sharp(inputs.source)
.toFile(inputs.dest)
.then((info) => {
return exits.success(info);
})
.catch((err) => {
return exits.error(err);
});
});
},
};
This diff is collapsed.
{
"name": "machinepack-images",
"version": "0.0.1",
"description": "Work with images n stuff",
"main": "index.js",
"scripts": {
"test": "npm run lint && npm run test-mocha",
"lint": "jshint ./lib",
"test-mocha": "nyc -r html -r text mocha ./test/*.js",
"mpdoc": "mpdoc"
},
"keywords": [
"images",
"exif",
"resize",
"crop",
"machines",
"machinepack"
],
"author": "Jarrod Linahan",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.11",
"machine": "^15.2.2",
"sharp": "^0.21.0"
},
"devDependencies": {
"chai": "^4.2.0",
"jshint": "^2.9.6",
"mocha": "^5.2.0",
"mpdoc": "git+ssh://git@git.carrotlabs.net:jarrod/mpdoc.git",
"nyc": "^13.1.0"
},
"machinepack": {
"friendlyName": "Image Helpers",
"machineDir": "lib/machines/",
"machines": [
"hash",
"strip-exif"
]
},
"repository": {
"type": "git",
"url": "ssh://git@git.linahan.id.au/jarrod/machinepack-images.git"
}
}
var should = require('chai').should(),
assert = require('chai').assert,
mp = require('../index'),
_ = require('lodash'),
fs = require('fs')
path = require('path');
let specDir = path.join(__dirname, 'mp-spec');
let spec = {};
fs.readdirSync(specDir).map((file) => {
let matches = file.match(/[.]js$/);
if (!matches) { return; }
let contents = require(path.join(specDir, file));
if (!contents.machine || !contents.expectations) {
throw new Error(`File ${file} doesn't appear to be a valid machine test spec.`);
}
// un-kebab-ify the machine name
let method = contents.machine.replace(/-(.)/g, (found) => {
return found.substr(1).toUpperCase();
});
spec[method] = contents.expectations;
});
_.each(spec, function(tests, method) {
describe(`#${method}`, function() {
it('Method should exist', function() {
mp[method].should.not.be.undefined;
});
it('Method should look like a machine (have a .getDef() method)', function() {
(typeof mp[method].getDef).should.equal('function');
});
let def = mp[method].getDef();
describe(def.friendlyName || def.description || '', function() {
tests.forEach(function(t) {
runTests(mp[method], t);
})
});
});
});
function runTests(machine, test) {
if (test.output) {
testOutcomes(machine, test);
}
// Support old-style strcmp
if (!test.expect && test.output) { test.expect = test.output }
if (test.expect) {
testExpectations(machine, test);
}
}
function testOutcomes(machine, test) {
// TODO: How can we check this short of mocking it's guts up?
// it(`Should exit with ${test.outcome} when given `+JSON.stringify(test.using), function(done) {
// machine(...Object.values(test.using)).exec(function(err, res) {
// console.log("Args:", arguments)
// console.log("This", this)
// console.log(err, res);
// done();
// });
// })
}
function testExpectations(machine, test) {
let type = getExpectationType(test);
let should = test.describe || `should ` + (type === 're' ? 'match ' + test.expect : type === 'cmp' ? 'equal ' + test.expect : ' pass custom method') + ` when given input ` + JSON.stringify(test.using);
it(should, function(done) {
machine(...Object.values(test.using)).exec((err, res) => {
switch(type) {
case 'cmp':
res.should.equal(test.expect)
break;
case 'match':
assert.match(res, test.expect)
break;
case 'fn':
test.expect(res).should.be.true
break;
}
done();
});
});
}
function getExpectationType(test) {
let type;
if (_.isString(test.expect) || _.isNumber(test.expect)) {
type = 'cmp';
} else if (_.isRegExp(test.expect)) {
type = 'match';
} else if (_.isFunction(test.expect)) {
type = 'fn';
}
if (!type) {
throw new Error('Not sure how to handle expectation for test: ' + JSON.stringify(test))
}
return type;
}
let path = require('path');
module.exports = {
machine: 'hash',
expectations: [
{
using: {
filename: path.join(__dirname, '../files/test.png'),
},
outcome: 'success',
expect: '40334c01de59ed96bab8e7772936bcc1352736a4'
},
{
describe: 'It should match some regex',
using: {
filename: path.join(__dirname, '../files/test.png'),
algorithm: 'md5'
},
outcome: 'success',
expect: /^d62beb9493121f01d22e2da8c03b21cf$/
},
{
describe: 'It pass some custom function',
using: {
filename: path.join(__dirname, '../files/test.png')
},
outcome: 'success',
expect: (out) => out === '40334c01de59ed96bab8e7772936bcc1352736a4'
},
{
describe: 'It pass some custom function',
using: {
filename: path.join(__dirname, '../files/test.png')
},
outcome: 'success',
expect: (out) => out === '40334c01de59ed96bab8e7772936bcc1352736a4'
},
/* {
using: { payload: null },
outcome: error
},
{
using: { payload: },
outcome: error
},
{
using: { payload: [] },
outcome: error
},
{
using: { payload: {} },
outcome: success
} */
]
};
// let path = require('path');
module.exports = {
machine: 'strip-exif',
expectations: [
//
]
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment