Skip to content

Commit

Permalink
Merge pull request #15 from kaliber5/multiconfig
Browse files Browse the repository at this point in the history
Multiconfig
  • Loading branch information
Andreas Schacht authored Mar 8, 2017
2 parents 4203a67 + 8226ee1 commit a749f2e
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 143 deletions.
39 changes: 36 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,36 @@ module.exports = function(environment) {
}
```

If you need different configurations, you can make the `responsive-image` config an array:

```js
module.exports = function(environment) {
var ENV = {
'responsive-image': [
{
sourceDir: 'assets/images/generateLarge',
destinationDir: 'assets/images/responsiveLarge',
quality: 80,
supportedWidths: [2048, 1536, 1080],
removeSourceDir: true,
justCopy: false,
extensions: ['jpg', 'jpeg', 'png', 'gif']
},
{
sourceDir: 'assets/images/generateSmall',
destinationDir: 'assets/images/responsiveSmall',
quality: 80,
supportedWidths: [750, 640, 320],
removeSourceDir: true,
justCopy: false,
extensions: ['jpg', 'jpeg', 'png', 'gif']
}
]
}
}
```


### Options

* **sourceDir:** The folder with the origin images.
Expand Down Expand Up @@ -71,13 +101,16 @@ let availableImages = responsiveImageService.getImages("myImage.png");
/**
avaliableImages contains now:
[
{width: 640, image: "/assets/images/responsive/myImage640w.png"},
{width: 750, image: "/assets/images/responsive/myImage750w.png"},
{width: 640, height: 320, image: "/assets/images/responsive/myImage640w.png"},
{width: 750, height: 375, image: "/assets/images/responsive/myImage750w.png"},
...
{width: 2048, image: "/assets/images/responsive/myImage2048w.png"}
{width: 2048, height: 1012, image: "/assets/images/responsive/myImage2048w.png"}
]
*/

let imageData = responsiveImageService.getImageDataBySize("myImage.png", 100); // The size argument is in ´vw´, 100 is the default and can be omitted
// {width: 750, height: 375, image: "/assets/images/responsive/myImage750w.png"}

let fittingImage = responsiveImageService.getImageBySize("myImage.png", 100); // The size argument is in ´vw´, 100 is the default and can be omitted
// "/assets/images/responsive/myImage1080w.png"
```
Expand Down
133 changes: 30 additions & 103 deletions addon/services/responsive-image.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Ember from 'ember';

const { computed, getOwner } = Ember;
const { computed, A, assert } = Ember;

/**
* Service class to provides images generated by the responsive images package
Expand Down Expand Up @@ -30,13 +30,12 @@ export default Ember.Service.extend({
*
* @method getImages
* @param {String} imageName The origin name of the Image
* @returns {Array} An array of objects with the image name and width, e.g. [{ width: 40, image: myImage40w.jpg}, ...]
* @returns {Array} An array of objects with the image name and width, e.g. [{ width: 40, height: 20, image: myImage40w.jpg}, ...]
* @public
*/
getImages(imageName) {
return this.get('supportedWidths').map((item) => {
return {width: item, image: this.getImageByWidth(imageName, item)};
}, this);
assert(`There is no data for image ${imageName}`, this.get('meta').hasOwnProperty(imageName));
return A(this.get('meta')[imageName]);
},

/**
Expand All @@ -49,55 +48,35 @@ export default Ember.Service.extend({
* @public
*/
getImageBySize(imageName, size) {
let width = this.getDestinationImageWidthBySize(size);
return this.getImageByWidth(imageName, width);
return this.getImageDataBySize(imageName, size).image;
},

/**
* returns the image string for the given width
* returns the image data which fits for given size
*
* @method getImageByWidth
* @method getImageBySize
* @param {String} imageName The origin name of the Image
* @param {Number} width The width of the image
* @return string
* @private
*/
getImageByWidth(imageName, width) {
let name = this.getImageNamePart(imageName);
let type = this.getImageType(imageName);
return this.getImageFromMeta(`${name}${width}w.${type}`);
},

/**
* returns the image string from the metadata
*
* @method getImageFromMeta
* @param {String} imageName The sized name of the Image
* @return string
* @private
* @param {Number} size The width of the image in percent of the screenwidth
* @return {Object} The data with image,width and height
* @public
*/
getImageFromMeta(imageName) {
let meta = this.get('meta');
let img = '';
if (meta[imageName] && meta[imageName].filename) {
img = meta[imageName].filename;
} else {
img = `${this.get('destinationPath')}${imageName}`;
}
return img;
getImageDataBySize(imageName, size) {
let width = this.getDestinationImageWidthBySize(imageName, size);
return this.getImages(imageName).findBy('width', width);
},

/**
* returns the closest supported width to the screenwidth and size
*
* @method getDestinationImageWidthBySize
* @param {String} image The name of the image
* @param {Number} size The width of the image in percent of the screenwidth
* @return {Number} the supported width
* @private
*/
getDestinationImageWidthBySize(size) {
getDestinationImageWidthBySize(image, size) {
let destinationWidth = this.getDestinationWidthBySize(size || 100);
return this.get('supportedWidths').reduce((prevValue, item)=> {
return this.getSupportedWidths(image).reduce((prevValue, item)=> {
if (item >= destinationWidth && prevValue >= destinationWidth) {
return (item >= prevValue) ? prevValue : item;
} else {
Expand All @@ -106,6 +85,20 @@ export default Ember.Service.extend({
}, 0);
},

/**
* returns the supported widths of an image
*
* @method getSupportedWidths
* @param {String} image the name of the image
* @return {Number[]} the supported widths
* @private
*/
getSupportedWidths(image) {
return this.getImages(image).map((item) => {
return item.width;
});
},

/**
* @method getDestinationWidthBySize
* @param {Number} size returns the physical width factored by size
Expand All @@ -120,72 +113,6 @@ export default Ember.Service.extend({
return physicalWidth * factor;
},

/**
* @method getImageNamePart
* @param {string} imageName the name of the origin image
* @returns {string} the name part without the file type extension
* @private
*/
getImageNamePart(imageName) {
return imageName.substr(0, imageName.lastIndexOf('.'));
},

/**
* @method getImageType
* @param {string} imageName the name of the origin image
* @returns {string} the file type extension ( e.g. jpg)
* @private
*/
getImageType(imageName) {
return imageName.substr(imageName.lastIndexOf('.') + 1);
},

/**
* the path to the assets, if the baseURL points to something
*
* @property assetsPath
* @readonly
* @type string
* @private
*/
assetsPath: computed(function() {
let config = getOwner(this).resolveRegistration('config:environment'),
baseUrl = Ember.get(config, 'rootURL') || Ember.get(config, 'baseURL') || '';
return baseUrl;
}).readOnly(),

/**
* the supported widths from the configuration
*
* @property supportedWidths
* @readonly
* @type array
* @private
*/
supportedWidths: computed(function() {
let config = getOwner(this).resolveRegistration('config:environment'),
widths = Ember.get(config, 'responsive-image.supportedWidths');
return widths;
}).readOnly(),

/**
* the path where the generated images will be stored
*
* @property destinationPath
* @type string
* @readonly
* @private
*/
destinationPath: computed(function() {
let config = getOwner(this).resolveRegistration('config:environment'),
destinationDir = Ember.get(config, 'responsive-image.destinationDir'),
assetsPath = this.get('assetsPath');

// if assetPath is empty the first file path would lead to an absolute path, that might break things (e.g. cordova),
// so check for empty assetPath!
return Ember.isPresent(assetsPath) ? `${assetsPath}${destinationDir}/` : `${destinationDir}/`;
}).readOnly(),

/**
* the meta values from build time
*
Expand Down
19 changes: 12 additions & 7 deletions broccoli-image-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ ImageResizer.prototype.copyImages = function (file, sourcePath, destinationPath)
Q.ninvoke(gmImage, 'size')
])
.then((infos) => {
this.insertMetadata(generatedFilename, width, infos);
this.insertMetadata(file, generatedFilename, width, infos);
return Q.nfcall(fs.copy, source, destination);
})
});
Expand Down Expand Up @@ -150,7 +150,7 @@ ImageResizer.prototype.generateImage = function (file, sourcePath, destinationPa
gmImage.setFormat('PNG8');
}

this.insertMetadata(generatedFilename, width, infos);
this.insertMetadata(file, generatedFilename, width, infos);
return Q.ninvoke(gmImage, 'write', destination);
});
};
Expand All @@ -159,17 +159,22 @@ ImageResizer.prototype.generateFilename = function (file, width) {
return file.substr(0, file.lastIndexOf('.')) + width + 'w.' + file.substr(file.lastIndexOf('.') + 1);
};

ImageResizer.prototype.insertMetadata = function (file, width, infos) {
ImageResizer.prototype.insertMetadata = function (filename, imagename, width, infos) {
let image = path.join(this.image_options.rootURL, this.image_options.destinationDir, imagename);
let aspectRatio = 1;
let filename = path.join(this.image_options.rootURL, this.image_options.destinationDir, file);
if (infos[2].height > 0) {
aspectRatio = Math.round((infos[2].width / infos[2].height) * 100) / 100;
}
this.metaData[file] = {
let height = Math.round(width / aspectRatio);
let meta = {
image,
width,
aspectRatio,
filename
height
};
if (this.metaData.hasOwnProperty(filename) === false) {
this.metaData[filename] = [];
}
this.metaData[filename].push(meta);
};

module.exports = ImageResizer;
50 changes: 33 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,33 @@ module.exports = {
config(env, baseConfig) {
if (!env)
return;
this.options = extend(defaultConfig(env), baseConfig['responsive-image']);
this.options.rootURL = baseConfig.rootURL || baseConfig.baseURL || '';
let config = baseConfig['responsive-image'];
let url = baseConfig.rootURL || baseConfig.baseURL || '';
this.options = [];

if (Array.isArray(config) === false) {
config = [config];
}
config.forEach((item) => {
let extendedConfig = extend(defaultConfig(env), item);
extendedConfig.rootURL = url;
this.options.push(extendedConfig);
})
},

preconcatTree: function(tree) {
return filterInitializers(tree, this.app.name);
},

resizeImages(tree) {
let options = this.options;
let extensions = this.options.extensions.join('|');
resizeImages(tree, options) {
let extensions = options.extensions.join('|');
let funnel = new Funnel(tree, {
srcDir: options.sourceDir,
include: [`**/*.+(${extensions})`],
allowEmpty: true,
destDir: '/'
});

this.metaData.prepend = '';
if (this.app && this.app.options && this.app.options.fingerprint) {
this.metaData.prepend = this.app.options.fingerprint.prepend;
}
return new Writer([funnel], this.options, this.metaData, this.ui);
return new Writer([funnel], options, this.metaData, this.ui);
},

contentFor(type) {
Expand All @@ -86,7 +90,16 @@ module.exports = {

postprocessTree(type, tree) {
if (type === 'all') {
let imageTree = this.resizeImages(tree);
this.metaData.prepend = '';
if (this.app && this.app.options && this.app.options.fingerprint) {
this.metaData.prepend = this.app.options.fingerprint.prepend;
}
let trees = [];
this.options.forEach((options) => {
let imageTree = this.resizeImages(tree, options)
trees.push(imageTree);
});

let pattern = '\'__ember_responsive_image_meta__\'';
if (process.env.EMBER_CLI_FASTBOOT) {
tree = map(tree, '**/*.js', (content, path) => {
Expand All @@ -99,16 +112,19 @@ module.exports = {
return content.replace(pattern, metaData);
});
}
return mergeTrees([imageTree, tree]);
trees.push(tree);
return mergeTrees(trees);
}

return tree;
},

postBuild(result) {
if (this.options.removeSourceDir) {
// remove folder with source files
rimraf.sync(path.join(result.directory, this.options.sourceDir));
}
this.options.forEach((options) => {
if (options.removeSourceDir) {
// remove folder with source files
rimraf.sync(path.join(result.directory, options.sourceDir));
}
});
}
};
Loading

0 comments on commit a749f2e

Please sign in to comment.