Skip to content
This repository has been archived by the owner on Nov 20, 2018. It is now read-only.

Commit

Permalink
feat(scaling): Allow an alternate library to be used to generate resi…
Browse files Browse the repository at this point in the history
…zed images

#1525
  • Loading branch information
rnicholus authored Jun 15, 2016
1 parent d40d8f6 commit 07873ef
Show file tree
Hide file tree
Showing 21 changed files with 588 additions and 281 deletions.
12 changes: 1 addition & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
addons:
firefox: "38.0"
firefox: "latest"

sudo: false
language: node_js
Expand All @@ -21,23 +21,13 @@ env:
awR42/q/Akos2eA8NWx5yU+hRC5rr+oQG5Eio0tzi9+y3a6VXDvgS1h2SaQz
TR/MjA/29gFvV7bnp1LSs2TdZx+NGhLd4zHv01XZ+pQk/nQiW9w=
before_install:
- npm install -g grunt-cli
- git submodule update --init --recursive

before_script:
- "sh -e /etc/init.d/xvfb start"

script:
- grunt travis

branches:
only:
- master
- develop
- /^feature.*$/
- /^.*fix.*$/
- /^release.*$/
notifications:
slack:
secure: qb1LdOGlBVKCLxNi86tWrabIKs9TFa3ttpLIwu1vtEeh+R9XDeG32X89sM3a5CHRwLqkHwrs6JNcIC4qhTAKiUOiaPYPbv7PkZXX1GIuOPMBp20ghpnWA7QHv6SpmW4qDCTixZSzf0B0m97muzWm1VnotgRELbfKr9Cf/7h3jS0=
13 changes: 8 additions & 5 deletions client/js/image-support/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ qq.ImageGenerator = function(log) {
maxWidth: maxSize,
maxHeight: maxSize,
orientation: orientation,
mime: mime
mime: mime,
resize: options.customResizeFunction
});
},

Expand All @@ -177,7 +178,8 @@ qq.ImageGenerator = function(log) {
mpImg.render(container, {
maxWidth: maxSize,
maxHeight: maxSize,
mime: mime
mime: mime,
resize: options.customResizeFunction
});
}
);
Expand All @@ -193,7 +195,7 @@ qq.ImageGenerator = function(log) {
return drawPreview;
}

function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize) {
function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) {
var tempImg = new Image(),
tempImgRender = new qq.Promise();

Expand All @@ -213,7 +215,8 @@ qq.ImageGenerator = function(log) {
mpImg.render(canvasOrImg, {
maxWidth: maxSize,
maxHeight: maxSize,
mime: determineMimeOfFileName(url)
mime: determineMimeOfFileName(url),
resize: customResizeFunction
});
},

Expand Down Expand Up @@ -287,7 +290,7 @@ qq.ImageGenerator = function(log) {
*
* @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image
* @param container <img> or <canvas> to contain the preview
* @param options possible properties include `maxSize` (int), `orient` (bool - default true), and `resize` (bool - default true)
* @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`.
* @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed
*/
generate: function(fileBlobOrUrl, container, options) {
Expand Down
88 changes: 78 additions & 10 deletions client/js/image-support/megapix-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,19 @@
/**
* Rendering image element (with resizing) and get its data URL
*/
function renderImageToDataURL(img, options, doSquash) {
function renderImageToDataURL(img, blob, options, doSquash) {
var canvas = document.createElement("canvas"),
mime = options.mime || "image/jpeg";
mime = options.mime || "image/jpeg",
promise = new qq.Promise();

renderImageToCanvas(img, canvas, options, doSquash);
return canvas.toDataURL(mime, options.quality || 0.8);
renderImageToCanvas(img, blob, canvas, options, doSquash)
.then(function() {
promise.success(
canvas.toDataURL(mime, options.quality || 0.8)
);
})

return promise;
}

function maybeCalculateDownsampledDimensions(spec) {
Expand All @@ -98,16 +105,31 @@
/**
* Rendering image element (with resizing) into the canvas element
*/
function renderImageToCanvas(img, canvas, options, doSquash) {
function renderImageToCanvas(img, blob, canvas, options, doSquash) {
var iw = img.naturalWidth,
ih = img.naturalHeight,
width = options.width,
height = options.height,
ctx = canvas.getContext("2d"),
promise = new qq.Promise(),
modifiedDimensions;

ctx.save();

if (options.resize) {
return renderImageToCanvasWithCustomResizer({
blob: blob,
canvas: canvas,
image: img,
imageHeight: ih,
imageWidth: iw,
orientation: options.orientation,
resize: options.resize,
targetHeight: height,
targetWidth: width
})
}

if (!qq.supportedFeatures.unlimitedScaledImageSize) {
modifiedDimensions = maybeCalculateDownsampledDimensions({
origWidth: width,
Expand All @@ -117,7 +139,7 @@
if (modifiedDimensions) {
qq.log(qq.format("Had to reduce dimensions due to device limitations from {}w / {}h to {}w / {}h",
width, height, modifiedDimensions.newWidth, modifiedDimensions.newHeight),
"warn");
"warn");

width = modifiedDimensions.newWidth;
height = modifiedDimensions.newHeight;
Expand Down Expand Up @@ -148,7 +170,7 @@
tmpCtx = tmpCanvas.getContext("2d");

while (sy < ih) {
sx = 0,
sx = 0;
dx = 0;
while (sx < iw) {
tmpCtx.clearRect(0, 0, d, d);
Expand All @@ -169,6 +191,49 @@
}

canvas.qqImageRendered && canvas.qqImageRendered();
promise.success();

return promise;
}

function renderImageToCanvasWithCustomResizer(resizeInfo) {
var blob = resizeInfo.blob,
image = resizeInfo.image,
imageHeight = resizeInfo.imageHeight,
imageWidth = resizeInfo.imageWidth,
orientation = resizeInfo.orientation,
promise = new qq.Promise(),
resize = resizeInfo.resize,
sourceCanvas = document.createElement("canvas"),
sourceCanvasContext = sourceCanvas.getContext("2d"),
targetCanvas = resizeInfo.canvas,
targetHeight = resizeInfo.targetHeight,
targetWidth = resizeInfo.targetWidth;

transformCoordinate(sourceCanvas, imageWidth, imageHeight, orientation);

targetCanvas.height = targetHeight;
targetCanvas.width = targetWidth;

sourceCanvasContext.drawImage(image, 0, 0);

resize({
blob: blob,
height: targetHeight,
image: image,
sourceCanvas: sourceCanvas,
targetCanvas: targetCanvas,
width: targetWidth
})
.then(
function success() {
targetCanvas.qqImageRendered && targetCanvas.qqImageRendered();
promise.success();
},
promise.failure
)

return promise;
}

/**
Expand Down Expand Up @@ -315,11 +380,14 @@
if (tagName === "img") {
(function() {
var oldTargetSrc = target.src;
target.src = renderImageToDataURL(self.srcImage, opt, doSquash);
oldTargetSrc === target.src && target.onload();
renderImageToDataURL(self.srcImage, self.blob, opt, doSquash)
.then(function(dataUri) {
target.src = dataUri;
oldTargetSrc === target.src && target.onload();
});
}())
} else if (tagName === "canvas") {
renderImageToCanvas(this.srcImage, target, opt, doSquash);
renderImageToCanvas(this.srcImage, this.blob, target, opt, doSquash);
}
if (typeof this.onrender === "function") {
this.onrender(target);
Expand Down
6 changes: 5 additions & 1 deletion client/js/image-support/scaler.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ qq.Scaler = function(spec, log) {
"use strict";

var self = this,
customResizeFunction = spec.customResizer,
includeOriginal = spec.sendOriginal,
orient = spec.orient,
defaultType = spec.defaultType,
Expand Down Expand Up @@ -51,6 +52,7 @@ qq.Scaler = function(spec, log) {
}),
blob: new qq.BlobProxy(originalBlob,
qq.bind(self._generateScaledImage, self, {
customResizeFunction: customResizeFunction,
maxSize: sizeRecord.maxSize,
orient: orient,
type: outputType,
Expand Down Expand Up @@ -170,6 +172,7 @@ qq.extend(qq.Scaler.prototype, {
name = uploadData && uploadData.name,
uuid = uploadData && uploadData.uuid,
scalingOptions = {
customResizer: specs.customResizer,
sendOriginal: false,
orient: specs.orient,
defaultType: specs.type || null,
Expand Down Expand Up @@ -290,6 +293,7 @@ qq.extend(qq.Scaler.prototype, {
"use strict";

var self = this,
customResizeFunction = spec.customResizeFunction,
log = spec.log,
maxSize = spec.maxSize,
orient = spec.orient,
Expand All @@ -303,7 +307,7 @@ qq.extend(qq.Scaler.prototype, {

log("Attempting to generate scaled version for " + sourceFile.name);

imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient}).then(function() {
imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() {
var scaledImageDataUri = canvas.toDataURL(type, quality),
signalSuccess = function() {
log("Success generating scaled version for " + sourceFile.name);
Expand Down
18 changes: 10 additions & 8 deletions client/js/templating.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,10 @@ qq.Templating = function(spec) {
relatedThumbnailId = optFileOrBlob && optFileOrBlob.qqThumbnailId,
thumbnail = getThumbnail(id),
spec = {
customResizeFunction: queuedThumbRequest.customResizeFunction,
maxSize: thumbnailMaxSize,
scale: true,
orient: true
orient: true,
scale: true
};

if (qq.supportedFeatures.imagePreviews) {
Expand Down Expand Up @@ -534,8 +535,9 @@ qq.Templating = function(spec) {
showWaitingImg = queuedThumbRequest.showWaitingImg,
thumbnail = getThumbnail(id),
spec = {
maxSize: thumbnailMaxSize,
scale: serverScale
customResizeFunction: queuedThumbRequest.customResizeFunction,
scale: serverScale,
maxSize: thumbnailMaxSize
};

if (thumbnail) {
Expand Down Expand Up @@ -982,16 +984,16 @@ qq.Templating = function(spec) {
show(getSpinner(id));
},

generatePreview: function(id, optFileOrBlob) {
generatePreview: function(id, optFileOrBlob, customResizeFunction) {
if (!this.isHiddenForever(id)) {
thumbGenerationQueue.push({id: id, optFileOrBlob: optFileOrBlob});
thumbGenerationQueue.push({id: id, customResizeFunction: customResizeFunction, optFileOrBlob: optFileOrBlob});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
}
},

updateThumbnail: function(id, thumbnailUrl, showWaitingImg) {
updateThumbnail: function(id, thumbnailUrl, showWaitingImg, customResizeFunction) {
if (!this.isHiddenForever(id)) {
thumbGenerationQueue.push({update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});
thumbGenerationQueue.push({customResizeFunction: customResizeFunction, update: true, id: id, thumbnailUrl: thumbnailUrl, showWaitingImg: showWaitingImg});
!thumbnailQueueMonitorRunning && generateNextQueuedPreview();
}
},
Expand Down
6 changes: 3 additions & 3 deletions client/js/uploader.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,11 +574,11 @@

if (canned) {
this._templating.addFileToCache(id, this._options.formatFileName(name), prependData, dontDisplay);
this._templating.updateThumbnail(id, this._thumbnailUrls[id], true);
this._templating.updateThumbnail(id, this._thumbnailUrls[id], true, this._options.thumbnails.customResizer);
}
else {
this._templating.addFile(id, this._options.formatFileName(name), prependData, dontDisplay);
this._templating.generatePreview(id, this.getFile(id));
this._templating.generatePreview(id, this.getFile(id), this._options.thumbnails.customResizer);
}

this._filesInBatchAddedToUi += 1;
Expand Down Expand Up @@ -696,7 +696,7 @@

// This will replace the "waiting" placeholder with a "preview not available" placeholder
// if called with a null thumbnailUrl.
this._templating.updateThumbnail(fileId, thumbnailUrl);
this._templating.updateThumbnail(fileId, thumbnailUrl, this._options.thumbnails.customResizer);
}
},

Expand Down
7 changes: 4 additions & 3 deletions client/js/uploader.basic.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,16 @@
// returning a promise that is fulfilled when the attempt completes.
// Thumbnail can either be based off of a URL for an image returned
// by the server in the upload response, or the associated `Blob`.
drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer) {
drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) {
var promiseToReturn = new qq.Promise(),
fileOrUrl, options;

if (this._imageGenerator) {
fileOrUrl = this._thumbnailUrls[fileId];
options = {
scale: maxSize > 0,
maxSize: maxSize > 0 ? maxSize : null
customResizeFunction: customResizeFunction,
maxSize: maxSize > 0 ? maxSize : null,
scale: maxSize > 0
};

// If client-side preview generation is possible
Expand Down
2 changes: 2 additions & 0 deletions client/js/uploader.basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@

// scale images client side, upload a new file for each scaled version
scaling: {
customResizer: null,

// send the original file as well
sendOriginal: true,

Expand Down
1 change: 1 addition & 0 deletions client/js/uploader.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ qq.FineUploader = function(o, namespace) {
},

thumbnails: {
customResizer: null,
maxCount: 0,
placeholders: {
waitUntilResponse: false,
Expand Down
2 changes: 1 addition & 1 deletion client/js/version.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/*global qq */
qq.version = "5.10.0";
qq.version = "5.10.0-2";
Loading

0 comments on commit 07873ef

Please sign in to comment.