How to make transparent color white instead of black in html2canvas? - html2canvas

I'm trying to take a screenshot using html2canvas:
var body = document.getElementById("body")
$(body).html2canvas({onrendered: function( canvas ) {
var urlData = canvas.toDataURL("image/jpeg");
}});
My body's background is transparent, and therefore urlData because of jpeg has black background (not white like in browser).
How can I fix this behavior and make background color white in this case?

I modified temporary: _html2canvas.Util.isTransparent from
_html2canvas.Util.isTransparent = function(backgroundColor) {
return (backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)");
};
to
_html2canvas.Util.isTransparent = function(backgroundColor) {
return (backgroundColor === "transparent" ||
backgroundColor === "rgba(0, 0, 0, 0)" ||
backgroundColor === undefined);
};
and after that it was enough to call html2canvas with background parameter set:
html2canvas(screenshotElement, {
background: '#FFFFFF',
onrendered: function (canvas) {
// ...
}
});
For me... it makes sense to consider transparent a background that is undefined.

Try this
var body = document.getElementById("body")
$(body).html2canvas({background:'#fff', onrendered: function( canvas ) {
var urlData = canvas.toDataURL("image/jpeg");
}});

I'd say, it's even simplier now(30/05/18) - just pass backgroundColor: null in html2canvas options:
html2canvas(
document.querySelector("#some-id-to-export"),
{backgroundColor: null}
).then(canvas => {$("#id-to-render-transparent-bg-img").html(canvas);});

https://stackoverflow.com/a/23928038/1815624
simply add css background-color:#ffffff to your table :)
hope this helps
I wrapped the content into a div for each desired page and gave class="pdfpage" then set the css as pdfpage{background:#FFFFFF;}
As I had commented it was not first thoughts that I needed to set the background of the rendered element as white since it was white already...But in truth it was colorless...

var body = document.getElementById("body")
$(body).html2canvas({onrendered: function( canvas ) {
var urlData = canvas.toDataURL("image/jpeg");
},
background: '#fff'});
Two years later but updated version should accept a parameter like this . . .

No worries, Now just add background: '#FFFFFF' , its working fine
html2canvas(element, {
background: '#FFFFFF',
onrendered: function (canvas) {
$("#previewImage").append(canvas);
getCanvas = canvas;
}
});

If you need the actual image data to be non-transparent, use fillRect(0, 0, width, height) with fillStyle 'white'.
Another way to do it but it's quite slow (few milliseconds maybe), is to use getImageData and putImageData and iterate threw each pixel to check rgba values and change them

html2Canvas and ngxcharts teams seem to have closed the bugs on this issue without providing any solution.
Setting up fill property for rect via css classes didn't work.
This is how I ended up solving it, surprisingly it works:
let rectElements = Array.from(document.getElementsByTagName('rect'));
if (rectElements.length > 0) {
rectElements.forEach(rect => {
rect.setAttribute('fill', '#ffffff');
});
}

Related

Position the dialog at the center of the screen in Fiori

I have a SAPUI5 Fiori application.
I use theme sap_fiori_3 as the base theme.
I customized this theme and only attached a background image to the theme.
The interesting part is when I activate this customized theme (that only has an extra background image in comparison to original sap_fiori_3 theme), the dialog are not centered in my app anymore.
The dialog are made with sap.m.dialog class.
I wrote a small snippet of code to center the dialog like following:
onAfterDialogOpen: function(oEvent){
var oDialog = oEvent.getSource(),
$Dialog = oDialog.$(),
oPosition = $Dialog.position(),
iTop = oPosition.top,
iLeft = oPosition.left,
iDialogWidth = $Dialog.width(),
iDialogHeight = $Dialog.height(),
iScreenWidth = sap.ui.Device.resize.width,
iScreenHight = sap.ui.Device.resize.height,
iNewTop = Math.floor((iScreenHight-iDialogHeight)/2),
iNewLeft = Math.floor((iScreenWidth-iDialogWidth)/2);
if(Math.abs(iNewLeft-iLeft) > 10 & Math.abs(iNewTop-iTop) > 10){
$Dialog.offset({top: iNewTop, left: iNewLeft});
}
},
But it is not a good solution. Why? Because it makes a motion on my screen like following:
Now the question is, how can I center the dialog without Java Script and by settings or some other tricks that when the dialog is opened, it be already centered.
Please note that using onBeforeOpen event is not possible as I need the size and position of the dialog!
I finally found out what is the source of the problem. It seems the Theme Designer of SAP is buggy and some part of the theme code does not transfer to the exported file.
When I use the theme designer to customize the theme it not only made the mentioned error, but also some other strange behavior appear in the deployed applications in the fiori launchpad which use the customized theme. However, we don't have those errors in the development time in the WEB IDE.
Therefore as I only needed to customize the following items:
background image
logo
favicon
I tried to use the standard theme like sap_fiori_3 and work around for setting these properties.
So for the first 2 issues I used the CSS hack:
div.sapUShellFullHeight {
background-image: url(../images/myBackgroundImage.svg);
background-repeat: no-repeat;
background-size: contain;
background-position: right;
}
a#shell-header-logo > img#shell-header-icon {
content:url(../images/logo.svg);
}
And for the favicon I used the promise solution. Please notice in the fiori launchpad each time that you switch between the applications fiori will reset the favicon, so I used the JavaScript promise to set it.
// Set the favicon dynamically to get read of blinking
function waitForElementAppear(selector) {
return new Promise(function(resolve, reject) {
var element = document.querySelector(selector);
if(element) {
resolve(element);
return;
}
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var nodes = Array.from(mutation.addedNodes);
for(var node of nodes) {
if(node.matches && node.matches(selector)) {
observer.disconnect();
resolve(node);
return;
}
};
});
});
observer.observe(document.documentElement, { childList: true, subtree: true });
});
}
//
function waitForElementRemoved(selector) {
return new Promise((resolve) => {
var element = document.querySelector(selector);
if(!element) {
resolve();
return;
}
var observer = new MutationObserver((mutations, observer) => {
for (const mutation of mutations) {
for (const removedNode of mutation.removedNodes) {
if (removedNode === element) {
observer.disconnect();
resolve();
}
}
}
});
observer.observe(element.parentElement, { childList: true });
});
}
//
function changeFavIcon(selector) {
waitForElementAppear(selector).then(function(element) {
element.setAttribute("href", "icon/favicon.ico");
waitForElementRemoved(selector).then(function() {
changeFavIcon(selector);
});
});
};
changeFavIcon("link[rel='shortcut icon']");
It recursively checks when the favicon is injected then it will set its href and as soon as it is removed, this function will observe the next injection!
As I know somebody may says why not used sapui5 its original solution for setting the favicon, like this:
jQuery.sap.setIcons({
'phone': '/images/cimt-logo.png',
'phone#2': '/images/cimt-logo.png',
'tablet': '/images/cimt-logo.png',
'tablet#2': '/images/cimt-logo.png',
'favicon': '/icon/favicon.ico',
'precomposed': true
});
I must say it was not working in my case!

html2canvas toDataURL(image/png") return poor image quality

I tried to use html2canvas to get image screenshot byte from website. However, the screenshot result ended with poor resolution. Looking for advice to improve screenshot quality. Thanks.
How about something like this:
var $wrapper = $("#yourDiv");
setSize($wrapper, "2000px", "20pt");
html2canvas($wrapper, {
onrendered: function (canvas) {
var a = document.createElement('a');
a.href = canvas.toDataURL("image/jpg");
a.download = 'filename.jpg';
a.click();
setSize($wrapper, "1000px", "10pt");
}
});
function setSize(dv, width, fontsize) {
dv[0].style.width = width;
dv[0].style.fontSize = fontsize;
}
This resizes the div and font to bigger size and then shrinks back afterwards.

How to disable animation in sap.m.ProgressIndicator on "percentValue" change?

As the title says, how to make the sap.m.ProgressIndicator not animated when changing the percent value of it?
I cannot find a method for it, and extending would probably be the way to go, but maybe somebody has already figured it out and done it?
My Google search was not successful though.
interesting question, below is the sap.m.ProgressIndication.prototype.setPercentValue function, you can see when the percent value changes the bars values is changed via an linear animation
My suggestion, the easiest way to change this behavior is to extend the control to your own control and to redefine the setPercentValue, either remove the animate function on the bar or set time to null so there is no animation
sap.m.ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
var that = this;
...
if (that.getPercentValue() != fPercentValue) {
// animation without rerendering
this.$().addClass("sapMPIAnimate");
var time = Math.abs(that.getPercentValue() - fPercentValue) * 20;
this.setProperty("percentValue", fPercentValue, true);
var $Bar = this.$("bar");
$Bar.animate({
width : fPercentValue + "%"
}, time, "linear", function() {
that._setText.apply(that);
that.$().removeClass("sapMPIAnimate");
});
}
something like
jQuery.sap.declare("my.ProgressIndicator");
jQuery.sap.require("sap.m.ProgressIndicator");
sap.m.ProgressIndicator.extend("my.ProgressIndicator", {
renderer: {}
});
my.ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
var that = this;
// validation of fPercentValue
if (typeof (fPercentValue) == "number") {
if (that.getPercentValue() != fPercentValue) {
// animation without rerendering
this.$().addClass("sapMPIAnimate");
//var time = Math.abs(that.getPercentValue() - fPercentValue) * 20;
var time = 0;
this.setProperty("percentValue", fPercentValue, true);
var $Bar = this.$("bar");
$Bar.animate({
width : fPercentValue + "%"
}, time, "linear", function() {
that._setText.apply(that);
that.$().removeClass("sapMPIAnimate");
});
}
return this;
};
There is no convenient method to suppress this behavior.
You can only extend the control and overwrite the method setPercentValue to you desired behavior.
As of UI5 1.73, the animation on percantageValue-change can be turned off by setting the property displayAnimation to false.
Determines whether a percentage change is displayed with animation.
Since: 1.73.
<ProgressIndicator displayAnimation="false" />

Trying to make use of Jcrop and serverside image resizing with scala Scrimage lib

I'm trying to combine jcrop and scrimage but I'm having trouble in understanding
the documentation of scrimage.
The user uploads an image. When the upload is done the user is able choose a fixed
area to crop with Jcrop:
upload.js
$(function () {
$('#fileupload').fileupload({
dataType: 'json',
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$("#progress").find(".progress-bar").css(
"width",
progress + "%"
);
},
done: function (e, data) {
$("#cropArea").empty();
var cropWidth = 210;
var cropHeight = 144;
if(data.result.status == 200) {
var myImage = $("<img></img>", {
src: data.result.link
}).appendTo('#cropArea');
var c = myImage.Jcrop({
allowResize: false,
allowSelect: false,
setSelect:[0,0,cropWidth,cropHeight],
onSelect: showCoords
});
}
}
});
});
Example:
When the user is satisfied the coordinates will be posted to the server and there is where the magic should happen.
Controller:
def uploadFile = Action(multipartFormDataAsBytes) { request =>
val result = request.body.files.map {
case FilePart(key, filename, contentType, bytes) => {
val coords = request.body.dataParts.get("coords")
val bais = new ByteArrayInputStream(bytes)
Image(bais).resize(magic stuff with coords)
Ok("works")
}
}
result(0)
}
If i read the docs for scrimage and resize:
Resizes the canvas to the given dimensions. This does not scale the
image but simply changes the dimensions of the canvas on which the
image is sitting. Specifying a larger size will pad the image with a
background color and specifying a smaller size will crop the image.
This is the operation most people want when they think of crop.
But when trying to implement resize with an inputstream Image(is).resize() I'm not sure I how should do this. Resize takes a scaleFactor, position and color... I guess I should
populate the position with the coords I get from jcrop??, and what do I do with the scaleFactor? Anybody got a good example of how to do this this?
Thank you for two great libs!
Subimage is what you want. That lets you specify coordinates rather than offsets.
So simply,
val image = // original
val resized = image.subimage(x,y,w,h) // you'll get these from jcrop somehow

Postprossing error - copyTexImage2D: framebuffer is incompatible format

Postprossing error - copyTexImage2D: framebuffer is incompatible format
I'm trying to use the post effects as presented in the samples, but I keep getting the following error in my console and nothing is rendering. Any ideas on what might be causing this? I don't think anything that matters is different than in the postprocessing example.
WebGL: INVALID_OPERATION: copyTexImage2D: framebuffer is incompatible format
renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setClearColorHex(0x000000, 1)
renderer.sortObjects = false;
...
composer = new THREE.EffectComposer( renderer )
composer.addPass( new THREE.RenderPass( scene, camera ) )
effect = new THREE.ShaderPass( THREE.DotScreenShader )
effect.uniforms[ 'scale' ].value = 4
composer.addPass( effect )
effect = new THREE.ShaderPass( THREE.FXAAShader )
composer.addPass( effect )
render = ->
requestAnimationFrame(render)
composer.render()
render()
You could try to add alpha to the WebGLRenderer default framebuffer using:
renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
I found out the error, there's a bug where EffectComposer is incompatable with LensFlare, submitting a change.
Basing on #Axiverse suggest, if your problem come with usage of lens flare (or maybe anything else...), simply add your own render target.
//...
var pixelRatio = renderer.getPixelRatio();
var width = Math.floor( renderer.context.canvas.width / pixelRatio ) || 1;
var height = Math.floor( renderer.context.canvas.height / pixelRatio ) || 1;
var renderTarget = new THREE.WebGLRenderTarget(width, height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat, // <-- The line that fix all for me
stencilBuffer: false
});
var effectComposer = new THREE.EffectComposer(webGLRenderer, renderTarget);