-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider option to remove blank space around signature #49
Comments
Thanks! While it might be useful to be able to trim it on the client side (to display it later to the user, or to upload less data), if it's not actually needed there, it's simpler to trim it on the server side using e.g. ImageMagick - As it's not specific to the library, but rather a generic image processing operation, I'd like to avoid merging it. However, I'll leave it opened for now, so that it's easier to find for others. |
I agree that if the server-side is accessible, that is a better place to put trimming. However, I am working with a server that does not (and will not) have ImageMagick installed. Still, even in this situation, the trimming could be placed in javascript outside the library, so you are probably right to keep it out of the library itself. (Apologies, flailing a bit with git comments!) |
@efc super useful, thanks! I like the idea of doing it client side and saving the server from having to process this. |
Not only is it useful, but it's needed. I'm working with Salesforce (cloud based) and have no access to perform image trimming on the server. |
I agree, this should be merged into the project. THANK YOU MUCH EFC! |
I don't think I'll ever merge it into this library. Like I mentioned before, removing white space around an image can be moved into a separate library, because it's not specific to signature pad library and doesn't use any part of it. Feel free to create a small library with the code posted by @efc and I'll add info about it to readme file. The code would probably still need to be modified to support e.g. non-transparent background colors. |
This can also be done easily in PHP using the Intervention library... http://image.intervention.io/api/trim UPDATE - While this works, I found it to be VERY processor intensive, especially when submitting a large signature pad image (I was using GD library). I am now trimming in the browser, which seems "instant", and doesn't use up server resources. |
Could this be merged in? It's not a bad idea to have an additional utility function. If someone needs client side trimming (as I do), they can use this method. Currently I rely on a fork, but having it in the main repository makes upgrading straightforward. |
@BasitAli It won't be merged. You don't have to rely on a fork - you can simply use the function provided by @efc. It doesn't access any data from the library - only the canvas, so it doesn't even have to be on SignaturePad class. You can simply add it as e.g. |
Ah, yes, ofcourse. Thanks :). |
I've just added info about trimming images to readme file and linked to the code provided by @efc (thanks!), so I'm finally closing this issue. |
I disagree that this funcionality should be handled by a separate code/library/component. Don't get me wrong, please. But the signature pad exists to capture a users' signature, and the blank space around it is not part of the signature. Also, in many development teams this is a job for a frontend developer, and most times a frontend developer doesn't have access to backend funcionality to trim the imagem server-side. Signature-pad should handle it, in my opinion. As I said, please don't get me wrong! |
I was able to implement this in my project, it crops the image as it should and sends the cropped image to the server. The problem is that my canvas content gets distorted on screen. I only want to send the cropped image to my server; the changes cannot be made on screen. I'm trying to create a temporary canvas and crop this instead, but I'm having a hard time. Can someone help me? Maybe @efc ? |
The In this implementation, a button triggers the Hope this helps... Javascript (Angular Directive)angular
.module('app')
.directive('psSignature', psSignature);
function psSignature($window, $timeout) {
return {
restrict: 'E',
scope: {
onCancel: '&',
onSubmit: '&',
submitting: '='
},
templateUrl: 'signature.html',
link: function (scope, element, attrs) {
var canvas = element.find('canvas')[0];
var canvasWrapper = element.find('.signature__body')[0];
var signaturePad = new SignaturePad(canvas, {onEnd: makeDirty});
var dirty = false;
scope.cancel = scope.onCancel;
scope.clear = clear;
scope.submit = submit;
scope.isDirty = isDirty;
scope.showCancel = showCancel;
activate();
////////////
function activate() {
addListeners();
$timeout(resizeCanvas, 500);
}
function addListeners() {
// Add
angular.element($window).on('resize', resizeCanvas);
// Clean up
scope.$on('$destroy', function () {
angular.element($window).off('resize', resizeCanvas);
});
}
function makeDirty() {
scope.$apply(function () {
dirty = true;
});
}
function clear() {
signaturePad.clear();
dirty = false;
}
function submit() {
signaturePad.removeBlanks();
scope.onSubmit({contents: signaturePad.toDataURL()});
clear();
resizeCanvas();
}
function isDirty() {
return dirty;
}
function showCancel() {
return !!(attrs.onCancel);
}
function resizeCanvas() {
canvas.width = canvasWrapper.offsetWidth;
canvas.height = canvasWrapper.offsetHeight;
}
}
};
}
|
Looks like @mikemclin provided a great answer, @rodrigovallades. I don't have to bother resizing the canvas in my app since it loads a whole new HTML page with a fresh canvas, so I'm afraid I can't really improve on Mike's suggestion. |
Actually I'm using angular in my project, indeed. I managed to accomplish what I wanted by duplicating the canvas and trimming the new one, so the canvas showing in my page stays untouched. But I'll try your suggestion later @mikemclin , thank you! |
Can you give a few more instructions on setting this up? I presume
That's what I've done so far- and but it does not work.
Not sure if it is related- I have gotten the error "Cannot read property 'addEventListener' of null" when troubleshooting/ I made a plunker- https://plnkr.co/edit/NOZG5Y4dgrpCZKU5Xkja?p=preview Is there an update/fix? Thanks |
Just adjusted the canvas size and signature pad size in the CSS. Worked for me. :) |
@yarnball I modified my answer slightly to better describe what the code snippets are for. The JavaScript is my Angular directive. The HTML provided was the HTML template for the directive. Now I would use that directive in my code; something like this... <ps-signature on-submit="vm.submit(contents)" submitting="vm.submitting">Please sign here...</ps-signature> You're going to need to have a good understanding of Angular directives to actually use my code in your app. And realistically, it was built for my app's purposes and might not be very flexible for reusability. |
For anyone who's looking for a tiny library that does this, I've created one here: https://github.com/agilgur5/trim-canvas based off @efc's code Side note: |
Thanks, @agilgur5. That's great! |
+1 @agilgur5 |
I agree. Since this is for a signature in some respects it makes sense that the white space should be trimmed, or added as a flag: trimWhiteSpace: true. |
Here's what we ended up using. The big difference and thing to note is that running this does NOT modify the primary canvas. It duplicates it, then trims the signature on the duplicate, and returns the data url. This is because I didn't want to modify the canvas the user sees. Our use case is we have the signature field and a hidden field, which is for the data URL. Every time Works very well. Hopefully it helps someone, took a bit of fiddling to get worked out :)
|
this save my life thank you @efc signaturePad.removeBlanks(); |
#49 (comment) This is exactly what I'm looking for. Thanks for sharing! |
Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0. |
@hariomdebut that error is a bit cryptic, but it means the canvas has 0 width. That probably means your original canvas (that is cloned) is incorrectly sized |
@agilgur5 I tried many solutions for this but none worked. I don't know how it works for some people. Still the best solution which works for me : |
@hariomdebut it work perfectly, in my code I replaced: |
Please consider merging this in since the whitespace is not part of a signature. Trying to use this within React client-side pdf generation. Third-party packages like trim-canvas are outdated and fail to load @babel/core correctly. |
@ustincameron hi, dude who made
Just because a package (like
Well If you've got a problem with |
Sorry for this late reply, but is there an option to use this for SVG?
Really searching for a way to trim a Canvas and export it as SVG and not as any bitmap |
@Martinh0 that's not really possible as no browser natively supports Canvas to SVG. Can see agilgur5/react-signature-canvas#49 (comment) for more details |
@agilgur5 hm ok, thank you. Maybe a bit offtopic, but do you know how to (in JavaScript, or PHP) trim normal SVGs? This then also could (should) be implemented in |
@Martinh0 I found a good few results in a quick search, basically all pertaining to changing the SVG's
The above code is only a few lines of user-land code. Theoretically I could make |
I'm using that in angular component https://github.com/ghwrivas/ngx-signature-pad/blob/master/projects/ngx-signature-pad/src/lib/ngx-signature-pad.component.ts |
When using Signature pad in a form, what is the best way to return the completed signature base64 data to an input? |
In case someone wants to have this with white background, just add this little change inside for loop. Final Code
|
jaredatch's code with small modifications becomes 3-4x faster
|
Thanks. Replace the code:
with:
|
Fantastic @Riba-Kit : many thanks! One question, should the line:
...include the zero also? I modified it to:
...because I found documentation which says that |
@larrymcp Thanks! You found a bug in my production) |
This returns it as .png :( |
If you need a jpeg image, you must change : to : |
If exporting SVG are required, @efc 's signaturePad based solution is still the only one works without other dependencies. For signature_pad.umd.min.js v 4.0.7, it needs to modified two lines, from this._canvas.width = cropRight-cropLeft;
this._canvas.height = cropBottom-cropTop; to this._ctx.canvas.width = cropRight-cropLeft;
this._ctx.canvas.height = cropBottom-cropTop; If other file formats are allowed, one can check first which MIME types are working in browsers before using canvas based solutions such as @Riba-Kit 's. However when exporting in jpg (either |
Hi Jared @jaredatch, Regards, |
It would be really helpful for the signature object to also return the bounding rectangle of the signature (no need to actually crop the image). Then we could do the processing ourselves. Something like signature.bounds() which returns { left, top, width, height } of the actual signature image. This could be calculated while the user is drawing the sig, thus eliminating the need to scan the entire image afterward. |
@efc Thanks for your modification, this modification works perfectly if the background is transparent, but if we change the background color of the canvas, it doesn't work. Can you please help me? |
@merbin2012, yes, this requires a transparent background. But instead of coloring the background of this element, why not try wrapping it in another div to which you apply your background color? |
@efc Thanks for your suggestion, I will try and let you know. |
As others have mentioned, the solutions earlier in this thread produce bitmap images. For those looking to obtain a cropped SVG, here's the function I use. First call It manipulates the svg's function cropSVG(svgText: string): string {
// First convert the svg string into an html element so we can
// call getBBox() on it.
const tempElement = document.createElement('div');
tempElement.setAttribute('style', 'visibility: hidden');
// getBBox() only works if the element is rendered into the page.
document.body.appendChild(tempElement);
tempElement.innerHTML = svgText;
const svgElement = tempElement.getElementsByTagName('svg')[0]
// This gets the bounding box around the signature.
const bbox = svgElement.getBBox();
// Use the bounding box's coordinates as the svg's viewBox.
// This eliminates the whitespace by "zooming in" on the
// bounding box. Include 5px extra, as the signature's
// edges get slightly clipped otherwise.
const viewBox = [bbox.x - 5, bbox.y - 5, bbox.width + 10, bbox.height + 10].join(" ");
svgElement.setAttribute("viewBox", viewBox);
// Let the svg have the size and aspect ratio of the
// cropped result, not the original canvas.
svgElement.removeAttribute("width");
svgElement.removeAttribute("height");
const croppedSVG = svgElement.outerHTML;
document.body.removeChild(tempElement);
return croppedSVG;
} Use as follows: const croppedSVGString = cropSVG(signaturePad.toSVG()); |
Hi, from : The only thing i can find if that : either pix.x[0], pix.y[0], w or h is undefined or NaN.. thanks |
I need to use the sig image later in my app and the blank space around the sig can be a bit of a pain. I added an option to remove this blank space so that the image returned when I get the data is the cropped signature. I'm not sure if this would be useful to others, and I am not able to git at the moment, so I'll just offer it here in case it proves helpful.
FYI, credit for most of this code goes to http://stackoverflow.com/questions/12175991/crop-image-white-space-automatically-using-jquery
I imagine my need for this feature also grows from my using signature_pad on a larger tablet instead of a phone-size device.
The text was updated successfully, but these errors were encountered: