I want to be able to set a minimum width and height for images uploaded via the FilePicker Upload dialog box (Minimum size: 1200 x 960 pixels).
Ideally there would be an option for this but I cannot seem to find it.
While we don't have a method to limit uploads based on image dimensions, we did add the ability to resize images upon upload in May of 2015.
The follow parameters govern this behavior:
These functions work for local files picked from your computer and images captured using the webcam service.
Image dimensions
{imageDim: [width, height]}
Specify image dimenions. e.g. : {imageDim: [800, 600]}. Local images will be resized (upscaled or downscaled) to the specified dimensions before uploading. The original height to width ratio is maintained. To resize all images based on the width, set [width, null], eg. [800, null]. For the height set [null, height], eg [null, 600].
Max image dimensions
{imageMax: [width, height]}
Specify maximum image dimenions. e.g. : {imageMax: [800, 600]}. Images bigger than the specified dimensions will be resized to the max size.
Min image dimensions
{imageMin: [width, height]}
Specify minimum image dimenions. e.g. : {imageMin: [800, 600]}. Images smaller than the specified dimensions will be upscaled to the minimum size.
Note: client side resizing relies on the dialog being opened to work. If a user utilizes the drop-pane functionality (meaning no modal dialog window opens) to upload their images, their images will not be modified.
Filestack does provide a picker option to set a callback onFileSelected. This is an example from a tutorial on their web site:
function checkImgSize (file) {
return new Promise(function (resolve, reject) {
const maxWidth = 1300;
const maxHeight = 1300;
const blob = file.originalFile;
// Get an object URL for the local file
const url = URL.createObjectURL(blob);
// Create an image and load the object URL
const img = new Image();
img.src = url;
img.onload = function () {
URL.revokeObjectURL(url);
if (this.naturalWidth > maxWidth) {
reject('File is too wide');
}
if (this.naturalHeight > maxHeight) {
reject('File is too tall');
}
// If we made it here then the file was approved
resolve();
}
});
}
const picker = client.picker({
exposeOriginalFile: true,
onFileSelected: checkImgSize,
});
Related
I'm setting up an app that allows the user to upload an image and make minor modifications (zoom, brightness, rotate, etc). I'm running into an issue with the brightness adjustment where Fabric.js just redraws a 2,048 x 2,048 segment of the image, rather than the entire thing. This is despite the max texture size being 16,384.
The image I'm uploading is large (5,400 x 3,600), but that's on purpose. These days even cell phones have high resolution cameras, so I need to be prepared for users to upload large images.
I found that if I randomly resize the image down by .5 as soon as it's loaded, then the brightness adjustment works just fine. That's not the end of the world - but I need to know how far to resize any image upon receipt. So is there a way to calculate the current texture size and then resize it down to something I can be sure Fabric.js will handle? I thought the current texture size could be the larger of either the pixel width or height of the image, but something must be wrong there, because my current image would be 5,400 which is well below the max of 16,384 (and resizing it by half would bring it down to 2,700, which is still above 2,048, but this actually works).
Any ideas on how to either:
determine how far to resize the image so Fabric.js can handle it
or, get Fabric.js to use the max texture size (since it seems to be ignoring it)
Here are some code snippets..
var FabricCanvas = new fabric.Canvas('FabricCanvas');
// image file upload handler
jQuery(".FabricPhotoUpload").on("change", function( event_change ) {
var reader = new FileReader();
reader.onload = function ( event_onload ) {
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function () {
var FabricImage = new fabric.Image(imgObj);
FabricImage.set({ angle: 0, top: 0, left: 0 });
fabric.filterBackend = fabric.initFilterBackend();
if ( fabric.isWebglSupported() ) {
fabric.textureSize = fabric.maxTextureSize;
}
FabricCanvas.add(FabricImage);
FabricCanvas.renderAll();
}
}
reader.readAsDataURL( event_change.target.files[0] );
event_change.target.value = "";
});
// using jQueryUI for the brightness slider
window.FabricSliderMax_Bright = 50;
jQuery( ".FabricBrightness" ).slider({
slide: function( event, ui ) {
var NewBrightness = ui.value / window.FabricSliderMax_Bright;
// for now I'm assuming FabricImage.filters[0] is the brightness filter
if ( typeof( FabricImage.filters[0] ) == "undefined" ) {
FabricImage.filters[0] = new fabric.Image.filters.Brightness({ brightness: NewBrightness });
} else {
FabricImage.filters[0].brightness = NewBrightness;
}
FabricImage.applyFilters();
FabricCanvas.renderAll();
},
max: window.FabricSliderMax_Bright,
min: -50,
value: 1
});
I too am playing with maxTextureSize.
I have not yet determined if there is a valid method to [pre]determine the hardware's limit for all platforms, but you can set it directly;
if (fabric.isWebglSupported()) fabric.textureSize = 65536;
I suspect it definitely needs to be at the least mod4 (4 bytes per pixel) ... but whether the increments can be less than 1k, I have yet to determine.
I've found that I need to first init the filter backend, then set the max texture size, then re-init the filter backend again. I'm not sure if this will work for everyone or not, but it fixed the issue for me:
// #ts-ignore
fabric.filterBackend = fabric.initFilterBackend(); //this will init WebGL
// #ts-ignore
fabric.textureSize = fabric.maxTextureSize; //allows for larger images
//This will re-init WebGL with the larger image textureSize.
// For some reason we need this extra re-init.
// Otherwise we get an error about 'RangeError out-of-bounds Uint8Array on ArrayBuffer'
// #ts-ignore
fabric.filterBackend = fabric.initFilterBackend();
I'm using Cropper https://github.com/fengyuanchen/cropper in a content management system but I'm struggling to get it to fix the size of a cropped image.
What I want to do is ensure whatever size of crop box is drawn on the canvas also results in a cropped image size of exactly 560px X 420px being passed through to the webserver.
The iQuery code I have at the moment is:-
$("#accept_crop").click(function() {
var $image = $("#image");
var cropper = $image.cropper();
var baseURL = window.location.protocol+'//'+window.location.host;
var pho_id = $("input[name=pho_id]").val();
var mem_id = $("input[name=mem_id]").val();
var photopath = $("input[name=photopath]").val();
$image.cropper('getCroppedCanvas').toBlob(function (blob) {
var formData = new FormData();
formData.append('croppedImage', blob);
formData.append('pho_id', pho_id);
formData.append('mem_id', mem_id);
formData.append('photopath', photopath);
$.ajax(baseURL+'/path', {
method: "POST",
data: formData,
processData: false,
contentType: false,
success: function () {
console.log('Upload success');
},
error: function () {
console.log('Upload error');
}
});
}, 'image/jpeg', 0.8);
});
The cropped image is passing over fine but always results in a variable size depending on the size of the crop box that's drawn. Is there any way of fixing the size on the client site regardless of the crop box so that the image is scaled up or down, without using PHP to re-scale it?
This always seems to happen... As soon as I've posted a question, I usually answer it myself shortly afterwards even though I've already spent ages trying to figure it out.
By adding adding the width and height options, this seems to work:-
$image.cropper('getCroppedCanvas', {'width': 560, 'height': 420}).toBlob(function (blob) {
It can be done, check its documentation:
https://github.com/fengyuanchen/cropper#getcroppedcanvasoptions
You can set destination width and height of the output canvas.
Other thing is you need to set the proportion ration as per your required width and height. 560/420 is proportional to 4/3. Set aspectRatio: 4/3. Which will resize the image to your desired size without compromising anything.
I'm working on a Chrome Extension in which I resize images (actually resize; not changing the browser display) that users right click on. When they right click on the image, I get access to the image's 'src'.
I can resize the images that aren't gifs fine; I'm using canvases to do this. You can see me do this here https://jsfiddle.net/cyqvacc6/6/.
img_url = 'https://i.imgur.com/SHo6Fub.jpg';
function get_image(image_url, emoji_name) {
var img_el = document.createElement('img');
img_el.onload = function () {
canvas = img_to_canvas(img_el);
emoji_sized_canvas = emoji_sized(canvas);
document.body.appendChild(emoji_sized_canvas);
};
img_el.src = image_url;
}
function img_to_canvas(img) {
canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas_ctx = canvas.getContext('2d');
canvas_ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
return canvas;
}
function emoji_sized(canvas) {
var target_dim = emoji_dimensions(canvas.width, canvas.height);
var factor = 2;
var canvas_long_side = Math.max(canvas.width, canvas.height);
var target_long_side = Math.max(target_dim.width, target_dim.height);
new_canvas = document.createElement('canvas');
new_canvas_ctx = new_canvas.getContext('2d');
if ((target_long_side === canvas_long_side)) {
// Return the image.
return canvas;
} else if (target_long_side > canvas_long_side * factor) {
// Increase the size of the image and then resize the result.
new_canvas.width = canvas.width * factor;
new_canvas.height = canvas.height * factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else if (canvas_long_side > target_long_side * factor) {
// Half the size of the image and then resize the result.
var width = new_canvas.width = canvas.width / factor;
var height = new_canvas.height = canvas.height / factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else {
// Resize the image in one shot
new_canvas.width = target_dim.width;
new_canvas.height = target_dim.height;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return new_canvas;
}
}
function emoji_dimensions(width, height) {
const MAX_SIDE_LENGTH = 128;
// Get the larger side
long_side = Math.max(height, width);
// Determine the scale ratio
// If the image is between 95% to 100% of the target
// emoji size, don't adjust it's size.
var scale;
if ((long_side >= 0.95 * MAX_SIDE_LENGTH) && (long_side <= MAX_SIDE_LENGTH))
{
scale = 1;
} else {
scale = MAX_SIDE_LENGTH / long_side;
}
return {
'height': height * scale,
'width': width * scale
};
}
Unfortunately, I'm not seeing an easy way to resize gifs using canvases. When I try the same approach on gifs, the 'resized' image is no longer a gif; it's just the first frame of the gif resized.
I think I'm going to end up sending gifs to a server to resize them, but still, in order to do this, I need to know whether the image I'm working on is animated or not, which I don't know how to do.
So, how do I determine if an image is a gif? Also, is it possible to resize these gifs from the client, i.e. javascript?
For reference, I need to reduce the gifs in terms of byte size and pixel, i.e. the gif needs to be both below 128px in both height and width and less than 64k in total byte size.
Since your question actually contains multiple questions, it's quite hard to answer it, so I'll currently don't include code in here.
First, Canvas API can only draw the first frame of any animated image passed through an <img> element. According to specs.
Specifically, when a CanvasImageSource object represents an animated image in an HTMLOrSVGImageElement, the user agent must use the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation, when rendering the image for CanvasRenderingContext2D APIs.
So you won't natively be able to render all your gif's frames on the canvas.
For this, you'll have to parse the file and extract every frames of your file.
Here are is an untested library that do propose this functionality :
libgif-js.
If you don't like libraries, you could also write a script yourself.
edit: I tried this lib and it's awfull... don't use it, maybe you could fork it, but it's really not meant to do image processing
Once you've got the frames, you can resize these with canvas, and then reencode them all in a final gif file. Untested either gif.js seems to be able to do that.
Tested too, little bit less awfull but it doesn't like transparency and it needs to have the js files hosted, so no online demo... Would also probably need a fork...
And finally, to answer the title question, "How to check the MIME type of a file", check this Q/A.
Basically, the steps are to extract the 4 first bits of your file and checking it against magic-numbers. 'image/gif' magic-numbers are 47 49 46 38.
I'm working on a toy project in Javascript. The goal is to have two different canvas elements with different sizes. I want to show a smaller image in the browser, on which the user can apply effects to, and when the time comes to save, the changes will be applied to the larger image.
Basically, my workflow is
User drags and drops an image into the drop zone
ImageWrapper object is created within the FileReader.onload callback
Two canvas elements are created: originalCanvas and previewCanvas
previewCanvas is resized with aspect ratio to fit the preview container
My issue is that the downscale operation results in a crop, rather than a resize.
My code is
//executes on the drop event
var reader = new FileReader();
reader.onload = function(e){
canvasImage = new ImageWrapper();
canvasImage.init(e.target.result, "preview", "center_align");
canvasImage.scaleAspect("image_preview");
document.getElementById("drop_image_container")
.appendChild(canvasImage.previewCanvas.canvas);
I created an ImageWrapper object to contain several fields:
var ImageWrapper = function(){
//set up the original and preview canvases
var originalCanvas = new CanvasImage(),
previewCanvas = new CanvasImage();
//inner object to allow for original and preview canvas objects.
function CanvasImage(){
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
image = new Image();
return {
canvas : canvas,
context : context,
image : image
};
}
function init(src, id, classes){
previewCanvas.canvas.id = id;
previewCanvas.canvas.className = classes;
originalCanvas.image.src = src;
previewCanvas.image.src = src;
originalCanvas.canvas.height = originalCanvas.image.naturalHeight;
originalCanvas.canvas.width = originalCanvas.image.naturalWidth;
previewCanvas.canvas.height = previewCanvas.image.naturalHeight;
previewCanvas.canvas.width = previewCanvas.image.naturalWidth;
previewCanvas.image.onload = function(){
previewCanvas.context.drawImage(previewCanvas.image, 0, 0);
originalCanvas.context.drawImage(originalCanvas.image, 0, 0);
}
}
The init() function is intended to create the two canvas elements with the default image size. Then scaleAspect() is called with the id of the preview container, which allows me to calculate the new dimensions of the canvas while maintaining the aspect ratio.
/* Scales the canvas element while maintaining aspect ratio of the original
*/
function scaleAspect(previewContainer){
var container = processParam(previewContainer),
width = previewCanvas.canvas.width,
height = previewCanvas.canvas.height;
var ratio = [container.width()/width, container.height()/height];
ratio = Math.min(ratio[0], ratio[1]);
previewCanvas.canvas.width = width * ratio;
previewCanvas.canvas.height = height * ratio;
previewCanvas.context.drawImage(previewCanvas.image, 0, 0,
previewCanvas.canvas.width, previewCanvas.canvas.height);
}
Once this function is complete, the previewCanvas.canvas element is added as a child of the drop container.
This drawImage is executing, but the results are not what I expected. The preview container is 500x500 pixels, which makes the new image to be 375x500 pixels in size. This drawImage is executing a crop operation, although there is a flicker on the execution. I can briefly see the resized image before the crop sets in.
Is it possible that the originalCanvas element is being drawn even though it is not bound to the element?
The drawImage(image, x, y) version you are using will draw the image at its native pixel size on the canvas. Instead, you should use the drawImage(image, x, y, width, height) version which lets you specify the destinations size when drawing the image into the canvas.
I am currently trying to get RGB data for a texture image, while displaying a preview of the texture to the user.
The user drops an image file into the form, and it should show the preview of the image, while drawing the image to an canvas to get the RGB values for each pixel:
handleTextureImageDrop = (e) ->
e.stopPropagation()
e.preventDefault()
if e.dataTransfer.files.length >= 1
file = e.dataTransfer.files[0]
if file
reader = new FileReader()
reader.onload = (loadEvent) ->
img = $ '<img/>'
img.attr
src: loadEvent.target.result
$(e.target).html img
reader.onloadend = (loadendEvent) ->
img = $(e.target).children 'img'
width = img.width()
height = img.height()
canvas = $ '<canvas/>',
width: width
height: height
$('#wrapper').append canvas
context = $('canvas').get(0).getContext '2d'
context.drawImage img.get(0), 0, 0
rgb = (for x in [0...width]
for y in [0...height]
context.getImageData(x, y, 1, 1).data)
canvas.remove()
TEXTURE_FILES.push
image: file.name
rgb: rgb
reader.readAsDataURL file
As it stands it works about 50% of the time, but the rest of the time width and height are set to 0, so the iteration across the pixel data never happens.
This would suggest to me that there is some sort of race condition happening where the image hasn't loaded into the <img/> tag yet.
Is that what is happening? Or am I missing something silly and obvious?
Any help would be much appreciated.
You will get correct width and height only after the image has been loaded. Usually $(img).load is used for this.
$(img).load(function(e){
var w = $(img).width();
var h = $(img).height();
});
$(img).attr("src", "http://....");
I am not familiar with coffeescript, so I am not able to understand whether you are doing this in your current code. If not please try it.