mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
✨ Added webp image support (#13105)
refs https://github.com/TryGhost/Ghost/issues/9448 refs https://github.com/TryGhost/Ghost/issues/2591 Added API support for webp image files.
This commit is contained in:
parent
86fbb14033
commit
4ac89c0176
5 changed files with 71 additions and 12 deletions
|
@ -27,8 +27,8 @@
|
||||||
"contentTypes": ["text/csv", "application/csv", "application/octet-stream", "application/vnd.ms-excel"]
|
"contentTypes": ["text/csv", "application/csv", "application/octet-stream", "application/vnd.ms-excel"]
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"extensions": [".jpg", ".jpeg", ".gif", ".png", ".svg", ".svgz", ".ico"],
|
"extensions": [".jpg", ".jpeg", ".gif", ".png", ".svg", ".svgz", ".ico", ".webp"],
|
||||||
"contentTypes": ["image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon"]
|
"contentTypes": ["image/jpeg", "image/png", "image/gif", "image/svg+xml", "image/x-icon", "image/vnd.microsoft.icon", "image/webp"]
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"extensions": [".png", ".ico"],
|
"extensions": [".png", ".ico"],
|
||||||
|
|
|
@ -61,6 +61,18 @@ describe('Images API', function () {
|
||||||
images.push(res.body.images[0].url.replace(config.get('url'), ''));
|
images.push(res.body.images[0].url.replace(config.get('url'), ''));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can upload a webp', async function () {
|
||||||
|
const res = await request.post(localUtils.API.getApiQuery('images/upload'))
|
||||||
|
.set('Origin', config.get('url'))
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.attach('file', path.join(__dirname, '/../../utils/fixtures/images/ghosticon.webp'))
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
res.body.images[0].url.should.match(new RegExp(`${config.get('url')}/content/images/\\d+/\\d+/ghosticon.webp`));
|
||||||
|
|
||||||
|
images.push(res.body.images[0].url.replace(config.get('url'), ''));
|
||||||
|
});
|
||||||
|
|
||||||
it('Can upload a square profile image', async function () {
|
it('Can upload a square profile image', async function () {
|
||||||
const res = await request.post(localUtils.API.getApiQuery('images/upload'))
|
const res = await request.post(localUtils.API.getApiQuery('images/upload'))
|
||||||
.set('Origin', config.get('url'))
|
.set('Origin', config.get('url'))
|
||||||
|
|
|
@ -37,20 +37,22 @@ describe('Importer', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets the correct extensions', function () {
|
it('gets the correct extensions', function () {
|
||||||
ImportManager.getExtensions().should.be.instanceof(Array).and.have.lengthOf(11);
|
ImportManager.getExtensions().should.be.instanceof(Array).and.have.lengthOf(12);
|
||||||
ImportManager.getExtensions().should.containEql('.json');
|
ImportManager.getExtensions().should.containEql('.json');
|
||||||
ImportManager.getExtensions().should.containEql('.zip');
|
ImportManager.getExtensions().should.containEql('.zip');
|
||||||
ImportManager.getExtensions().should.containEql('.jpg');
|
ImportManager.getExtensions().should.containEql('.jpg');
|
||||||
ImportManager.getExtensions().should.containEql('.md');
|
ImportManager.getExtensions().should.containEql('.md');
|
||||||
|
ImportManager.getExtensions().should.containEql('.webp');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets the correct types', function () {
|
it('gets the correct types', function () {
|
||||||
ImportManager.getContentTypes().should.be.instanceof(Array).and.have.lengthOf(12);
|
ImportManager.getContentTypes().should.be.instanceof(Array).and.have.lengthOf(13);
|
||||||
ImportManager.getContentTypes().should.containEql('application/octet-stream');
|
ImportManager.getContentTypes().should.containEql('application/octet-stream');
|
||||||
ImportManager.getContentTypes().should.containEql('application/json');
|
ImportManager.getContentTypes().should.containEql('application/json');
|
||||||
ImportManager.getContentTypes().should.containEql('application/zip');
|
ImportManager.getContentTypes().should.containEql('application/zip');
|
||||||
ImportManager.getContentTypes().should.containEql('application/x-zip-compressed');
|
ImportManager.getContentTypes().should.containEql('application/x-zip-compressed');
|
||||||
ImportManager.getContentTypes().should.containEql('text/plain');
|
ImportManager.getContentTypes().should.containEql('text/plain');
|
||||||
|
ImportManager.getContentTypes().should.containEql('image/webp');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets the correct directories', function () {
|
it('gets the correct directories', function () {
|
||||||
|
@ -61,27 +63,27 @@ describe('Importer', function () {
|
||||||
|
|
||||||
it('globs extensions correctly', function () {
|
it('globs extensions correctly', function () {
|
||||||
ImportManager.getGlobPattern(ImportManager.getExtensions())
|
ImportManager.getGlobPattern(ImportManager.getExtensions())
|
||||||
.should.equal('+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.json|.md|.markdown|.zip)');
|
.should.equal('+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp|.json|.md|.markdown|.zip)');
|
||||||
ImportManager.getGlobPattern(ImportManager.getDirectories())
|
ImportManager.getGlobPattern(ImportManager.getDirectories())
|
||||||
.should.equal('+(images|content)');
|
.should.equal('+(images|content)');
|
||||||
ImportManager.getGlobPattern(JSONHandler.extensions)
|
ImportManager.getGlobPattern(JSONHandler.extensions)
|
||||||
.should.equal('+(.json)');
|
.should.equal('+(.json)');
|
||||||
ImportManager.getGlobPattern(ImageHandler.extensions)
|
ImportManager.getGlobPattern(ImageHandler.extensions)
|
||||||
.should.equal('+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico)');
|
.should.equal('+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp)');
|
||||||
ImportManager.getExtensionGlob(ImportManager.getExtensions())
|
ImportManager.getExtensionGlob(ImportManager.getExtensions())
|
||||||
.should.equal('*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.json|.md|.markdown|.zip)');
|
.should.equal('*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp|.json|.md|.markdown|.zip)');
|
||||||
ImportManager.getDirectoryGlob(ImportManager.getDirectories())
|
ImportManager.getDirectoryGlob(ImportManager.getDirectories())
|
||||||
.should.equal('+(images|content)');
|
.should.equal('+(images|content)');
|
||||||
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 0)
|
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 0)
|
||||||
.should.equal('*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.json|.md|.markdown|.zip)');
|
.should.equal('*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp|.json|.md|.markdown|.zip)');
|
||||||
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 0)
|
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 0)
|
||||||
.should.equal('+(images|content)');
|
.should.equal('+(images|content)');
|
||||||
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 1)
|
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 1)
|
||||||
.should.equal('{*/*,*}+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.json|.md|.markdown|.zip)');
|
.should.equal('{*/*,*}+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp|.json|.md|.markdown|.zip)');
|
||||||
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 1)
|
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 1)
|
||||||
.should.equal('{*/,}+(images|content)');
|
.should.equal('{*/,}+(images|content)');
|
||||||
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 2)
|
ImportManager.getExtensionGlob(ImportManager.getExtensions(), 2)
|
||||||
.should.equal('**/*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.json|.md|.markdown|.zip)');
|
.should.equal('**/*+(.jpg|.jpeg|.gif|.png|.svg|.svgz|.ico|.webp|.json|.md|.markdown|.zip)');
|
||||||
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 2)
|
ImportManager.getDirectoryGlob(ImportManager.getDirectories(), 2)
|
||||||
.should.equal('**/+(images|content)');
|
.should.equal('**/+(images|content)');
|
||||||
});
|
});
|
||||||
|
@ -366,7 +368,7 @@ describe('Importer', function () {
|
||||||
|
|
||||||
it('has the correct interface', function () {
|
it('has the correct interface', function () {
|
||||||
ImageHandler.type.should.eql('images');
|
ImageHandler.type.should.eql('images');
|
||||||
ImageHandler.extensions.should.be.instanceof(Array).and.have.lengthOf(7);
|
ImageHandler.extensions.should.be.instanceof(Array).and.have.lengthOf(8);
|
||||||
ImageHandler.extensions.should.containEql('.jpg');
|
ImageHandler.extensions.should.containEql('.jpg');
|
||||||
ImageHandler.extensions.should.containEql('.jpeg');
|
ImageHandler.extensions.should.containEql('.jpeg');
|
||||||
ImageHandler.extensions.should.containEql('.gif');
|
ImageHandler.extensions.should.containEql('.gif');
|
||||||
|
@ -374,13 +376,15 @@ describe('Importer', function () {
|
||||||
ImageHandler.extensions.should.containEql('.svg');
|
ImageHandler.extensions.should.containEql('.svg');
|
||||||
ImageHandler.extensions.should.containEql('.svgz');
|
ImageHandler.extensions.should.containEql('.svgz');
|
||||||
ImageHandler.extensions.should.containEql('.ico');
|
ImageHandler.extensions.should.containEql('.ico');
|
||||||
ImageHandler.contentTypes.should.be.instanceof(Array).and.have.lengthOf(6);
|
ImageHandler.extensions.should.containEql('.webp');
|
||||||
|
ImageHandler.contentTypes.should.be.instanceof(Array).and.have.lengthOf(7);
|
||||||
ImageHandler.contentTypes.should.containEql('image/jpeg');
|
ImageHandler.contentTypes.should.containEql('image/jpeg');
|
||||||
ImageHandler.contentTypes.should.containEql('image/png');
|
ImageHandler.contentTypes.should.containEql('image/png');
|
||||||
ImageHandler.contentTypes.should.containEql('image/gif');
|
ImageHandler.contentTypes.should.containEql('image/gif');
|
||||||
ImageHandler.contentTypes.should.containEql('image/svg+xml');
|
ImageHandler.contentTypes.should.containEql('image/svg+xml');
|
||||||
ImageHandler.contentTypes.should.containEql('image/x-icon');
|
ImageHandler.contentTypes.should.containEql('image/x-icon');
|
||||||
ImageHandler.contentTypes.should.containEql('image/vnd.microsoft.icon');
|
ImageHandler.contentTypes.should.containEql('image/vnd.microsoft.icon');
|
||||||
|
ImageHandler.contentTypes.should.containEql('image/webp');
|
||||||
ImageHandler.loadFile.should.be.instanceof(Function);
|
ImageHandler.loadFile.should.be.instanceof(Function);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,49 @@ describe('lib/image: image size', function () {
|
||||||
}).catch(done);
|
}).catch(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('[success] should return image dimensions for locally stored .webp image', function (done) {
|
||||||
|
const url = 'http://myblog.com/content/images/ghosticon.webp';
|
||||||
|
const expectedImageObject = {
|
||||||
|
height: 249,
|
||||||
|
url: 'http://myblog.com/content/images/ghosticon.webp',
|
||||||
|
width: 249
|
||||||
|
};
|
||||||
|
|
||||||
|
const storagePath = path.join(__dirname, '../../../../test/utils/fixtures/images/');
|
||||||
|
const urlForStub = sinon.stub();
|
||||||
|
urlForStub.withArgs('image').returns('http://myblog.com/content/images/ghosticon.webp');
|
||||||
|
urlForStub.withArgs('home').returns('http://myblog.com/');
|
||||||
|
const urlGetSubdirStub = sinon.stub();
|
||||||
|
urlGetSubdirStub.returns('');
|
||||||
|
|
||||||
|
const imageSize = new ImageSize({config: {
|
||||||
|
get: () => {}
|
||||||
|
}, i18n: {}, storage: {
|
||||||
|
getStorage: () => ({
|
||||||
|
read: obj => fs.promises.readFile(obj.path)
|
||||||
|
})
|
||||||
|
}, storageUtils: {
|
||||||
|
isLocalImage: () => true,
|
||||||
|
getLocalFileStoragePath: imageUrl => path.join(storagePath, imageUrl.replace(/.*\//, ''))
|
||||||
|
}, validator: {}, urlUtils: {
|
||||||
|
urlFor: urlForStub,
|
||||||
|
getSubdir: urlGetSubdirStub
|
||||||
|
}, request: () => {
|
||||||
|
return Promise.reject({});
|
||||||
|
}});
|
||||||
|
|
||||||
|
imageSize.getImageSizeFromStoragePath(url).then(function (res) {
|
||||||
|
should.exist(res);
|
||||||
|
should.exist(res.width);
|
||||||
|
res.width.should.be.equal(expectedImageObject.width);
|
||||||
|
should.exist(res.height);
|
||||||
|
res.height.should.be.equal(expectedImageObject.height);
|
||||||
|
should.exist(res.url);
|
||||||
|
res.url.should.be.equal(expectedImageObject.url);
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
|
|
||||||
it('[failure] returns error if storage adapter errors', function (done) {
|
it('[failure] returns error if storage adapter errors', function (done) {
|
||||||
const url = '/content/images/not-existing-image.png';
|
const url = '/content/images/not-existing-image.png';
|
||||||
|
|
||||||
|
|
BIN
test/utils/fixtures/images/ghosticon.webp
Normal file
BIN
test/utils/fixtures/images/ghosticon.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 386 B |
Loading…
Add table
Reference in a new issue