I want to create a video that has transparency, but I can't have it be a Quicktime movie since it is being deployed on the web. I need something that is cross-browser compatible also.
I tried to create a video with a black background and use a blend mode in CSS to knock out the background, creating the illusion of transparency. That worked, but it also affected the art in the video that lay on top of the black background. I need a solution that will work to create transparency (alpha) on the background but not affect the rest of the content, such as seen with a QuickTime video with alpha channel.
you can use html5 transparent video, mp4 as example, double the height, with a canvas and alpha channel.
take a look at this code:
(function () {
var outputCanvas = document.getElementById('output'),
output = outputCanvas.getContext('2d'),
bufferCanvas = document.getElementById('buffer'),
buffer = bufferCanvas.getContext('2d'),
video = document.getElementById('video'),
width = outputCanvas.width,
height = outputCanvas.height,
interval;
function processFrame() {
buffer.drawImage(video, 0, 0);
// this can be done without alphaData, except in Firefox which doesn't like it when image is bigger than the canvas
var image = buffer.getImageData(0, 0, width, height),
imageData = image.data,
alphaData = buffer.getImageData(0, height, width, height).data;
for (var i = 3, len = imageData.length; i < len; i = i + 4) {
imageData[i] = alphaData[i - 1];
}
output.putImageData(image, 0, 0, 0, 0, width, height);
}
video.addEventListener('play', function () {
clearInterval(interval);
interval = setInterval(processFrame, 40)
}, false);
// Firefox doesn't support looping video, so we emulate it this way
video.addEventListener('ended', function () {
video.play();
}, false);
})();
and i used this on a webpage once:
<div class="IntroVideo" id="canvas_output">
<video id="video" style="display:none;" autoplay crossorigin="anonymous">
<source src="https://jakearchibald.com/scratch/alphavid/compressed.mp4" type='video/mp4' />
</video>
<canvas width="920" height="1300" id="buffer" style="display: none;"></canvas>
<canvas width="920" height="650" id="output" style="display: inline-block;"></canvas>
</div>
i found a transparent video example for you to try,
there is some instruction somewhere but i can't seem to find them anymore,
it's on jakearchibald.com perhaps the instruction is there too.
I'm afraid it is not possible. I'm also searching, searching and searching.. But looking at your image: can't you create a CSS animation instead of video?
Related
I have a video tag in my Ionic app, video element is added after click on a button.
function addVideo(videoId){
var path = $scope.getVideo(videoId).newVideoLocation.nativeURL;
path = $sce.trustAsResourceUrl(path);
var container = document.getElementById('videoContainer' + videoId);
var video = document.createElement('video');
video.src = path;
video.setAttribute('id', 'video' + videoId);
video.setAttribute('poster', $scope.getVideo(videoId).thumbnailPath);
video.setAttribute('width', '100%');
container.appendChild(video);
};
Video is added successfully but there are bottom and top white spaces / bars:
After click play button spaces are no longer there:
I set border to all elements to know what is happening. Blue border is video tag:
It could be margin o padding however I set them to 0:
* {
border: 1px solid red !important;
}
video {
border: 2px solid blue !important;
margin: 0;
padding: 0;
}
Any idea what is the problem?
After a lot of research I found a solution.
I start understanding what happened after read HTML 5 Video stretch post:
Video content should be rendered inside the element's playback area
such that the video content is shown centered in the playback area at
the largest possible size that fits completely within it, with the
video content's aspect ratio being preserved. Thus, if the aspect
ratio of the playback area does not match the aspect ratio of the
video, the video will be shown letterboxed or pillarboxed. Areas of
the element's playback area that do not contain the video represent
nothing.
Then in google books I found and explanation how works video width, the book is call The Definitive Guide to HTML5 Video
If width and height are not same aspect ratio as original video it doesn't work. Set a 100% to width doesn't mean you want video to fit the container. So I decided to calculate width and height of the container and set to video element:
function addVideo(videoId){
var path = getTrustUrl($scope.getVideo(videoId).newVideoLocation.nativeURL);
// Create container element and get padding
var container = document.getElementById('videoContainer' + videoId);
var paddingLeft = window.getComputedStyle(container, null).getPropertyValue('padding-left');
var paddingRight = window.getComputedStyle(container, null).getPropertyValue('padding-right');
// Get only numeric part and parse to integer
paddingLeft = parseInt(paddingLeft.slice(0,-2));
paddingRight = parseInt(paddingRight.slice(0,-2));
//Get internal width of container and calculate height
var width = container.offsetWidth - paddingLeft - paddingRight;
var height = (width * 9 ) / 16; // TODO, if not 16:9 error
// Create video element and set attributes
var video = document.createElement('video');
video.src = path;
video.setAttribute('id', 'video' + videoId);
video.setAttribute('poster', $scope.getVideo(videoId).thumbnailPath);
video.setAttribute('width', width);
video.setAttribute('height', height);
// Append video to container
container.appendChild(video);
};
I don't see it straightforward... if someone know another solution let me know!
I'm trying to draw an image on a canvas, then use css to fit the canvas within a certain size. It turns out that many browsers don't scale the canvas down very nicely. Firefox on OS X seems to be one of the worst, but I haven't tested very many. Here is a minimal example of the problem:
HTML
<img>
<canvas></canvas>
CSS
img, canvas {
width: 125px;
}
JS
var image = document.getElementsByTagName('img')[0],
canvas = document.getElementsByTagName('canvas')[0];
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
Running in a codepen: http://codepen.io/ford/pen/GgMzJd
Here's the result in Firefox (screenshot from a retina display):
What's happening is that both the <img> and <canvas> start at the same size and are scaled down by the browser with css (the image width is 783px). Apparently, the browser does some nice smoothing/interpolation on the <img>, but not on the <canvas>.
I've tried:
image-rendering, but the defaults seem to already be what I want.
Hacky solutions like scaling the image down in steps, but this didn't help: http://codepen.io/ford/pen/emGxrd.
Context2D.imageSmoothingEnabled, but once again, the defaults describe what I want.
How can I make the image on the right look like the image on the left? Preferably in as little code as possible (I'd rather not implement bicubic interpolation myself, for example).
You can fix the pixelation issue by scaling the canvas's backing store by the window.devicePixelRatio value. Unfortunately, the shoddy image filtering seems to be a browser limitation at this time, and the only reliable fix is to roll your own.
Replace your current onload with:
image.onload = function() {
var dpr = window.devicePixelRatio;
canvas.width = image.width * dpr;
canvas.height = image.height * dpr;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
Results:
Tested on Firefox 35.0.1 on Windows 8.1. Note that your current code doesn't handle browser zoom events, which could reintroduce pixelation. You can fix this by handling the resize event.
Canvas is not quite meant to be css zoomed : Try over-sampling : use twice the required canvas size, and css scaling will do a fine job in down-scaling the canvas.
On hi-dpi devices you should double yet another time the resolution to reach the
same quality.
(even on a standard display, X4 shines a bit more).
(Image, canvas 1X, 2X and 4X)
var $ = document.getElementById.bind(document);
var image = $('fntimg');
image.onload = function() {
drawAllImages();
}
image.src = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Helvetica_Neue_typeface_weights.svg/783px-Helvetica_Neue_typeface_weights.svg.png"
function drawAllImages() {
drawImage(1);
drawImage(2);
drawImage(4);
}
function drawImage(x) {
console.log('cv' + x + 'X');
var canvas = $('cv' + x + 'X');
canvas.width = x * image.width;
canvas.height = x * image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, canvas.width, canvas.height);
}
img,
canvas {
width: 125px;
}
<br>
<img id='fntimg'>
<canvas id='cv1X'></canvas>
<canvas id='cv2X'></canvas>
<canvas id='cv4X'></canvas>
<br>
It's not good idea to scale canvas and think that you solved the image scale problem.you can pass your dynamic value to canvas,and then draw with that size whatever you want.
here is link of canvas doc: http://www.w3docs.com/learn-javascript/canvas.html
Simple answer, you can't do it. The canvas is just like a bitmap, nothing more.
My idea:
You should redraw the whole surface on zooming, and make sure you scale the image you're drawing to the canvas. As it is a vector graphic, this should work. But you're going to have to redraw the canvas for sure.
I have a question, wich one have the best performance in webBrowsers?
drawing a canvas with the given url image "context.drawImage(...)" or just using css with "background:url('...')".
(both images filling the entire webPage as a wallpaper)
For big images (wallpapers) who fill the entire page i think it is heavier to load the image with css.
At least for firefox(20+), if you change tabs or minimize the window and go back again to your page (with the background), i can see that the image takes to show again after a half second.
So, i'm asking bc i found a lot of people telling that basic DOM is better.
Code for css:
--html: <body></body>
$('body').css('background',
"url('http://www.iwallscreen.com/stock/city-lights-hd-wallpaper.jpg') repeat fixed 0 0 #000000");
$('body').css('background-size', "100% auto");
Code for canvas:
--html: <canvas id="canvasWall" style="position:fixed;left:0;z-index:-1;"></canvas>
var context = $('#canvasWall')[0].getContext("2d");
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight;
var img = new Image();
img.src = 'http://www.iwallscreen.com/stock/city-lights-hd-wallpaper.jpg';
img.onload = function() {
context.drawImage(img, 0, 0, window.innerWidth, window.innerHeight);
};
if you look at this fiddle( http://jsfiddle.net/5ajYD/ ) with an android browser you see that the PNG that makes up the flowers has a white background.
On all other browsers it shows perfectly normal, except the android browser.
I've googled on this problem but the only thing I can find is a problem with png banding and related to android app programming.
This reminds me of the issues MSIE 6 has with transparant images, and I find it very strange that this happens.
Does anyone know a fix for this issue on android browsers?
I can't use non transparant background because of the gradient differences in different browsers.
What I have tried so far:
I have already tried using "multiple" backgrounds both posistioned at
location 0px 0px, but that doens't work
I've tried adding a gradient to to the div with the flowers, but that
failed too and broke in other browsers.
I find it very mystifying that this kind of issue shows up on a modern browser... even a nokia n95 gets it right....
The android version I’m testing against/found this with is android 2.3.4(Sony Ericsson Xperia Arc S LT18i)
This is what I see with the fiddle in the android browser on the phone
http://t.co/mofPkqjf
I had a big facepalm moment.
I've been battling with this for two months now and I simply couldn't figure out the logic. The problem was in the econtainer element that it had a parameter: width:100%.
What happens is that it only renders the width up to the actual page width of the viewport.
So if you have a browser screen on mobile that's 480px wide, it'll set width to 480px, render a gradient of 480px, and not rerender when you scroll sideways.
The problem was solved by adding a min-width:1200px; and now it renders properly!
Thank you all for looking into this...
Use HTML5 Canvas to create an alphaJPEG, a JPEG layered under an equivalent PNG with an alpha channel.
<head>
<style>img[data-alpha-src]{visibility: hidden;}</style>
</head>
<body>
<img src="image.jpg" data-alpha-src="alpha.png" />
<!--...-->
<script src="ajpeg.js"></script>
</body>
ajpeg.js
(function() {
var create_alpha_jpeg = function(img) {
var alpha_path = img.getAttribute('data-alpha-src')
if(!alpha_path) return
// Hide the original un-alpha'd
img.style.visiblity = 'hidden'
// Preload the un-alpha'd image
var image = document.createElement('img')
image.src = img.src
image.onload = function () {
// Then preload alpha mask
var alpha = document.createElement('img')
alpha.src = alpha_path
alpha.onload = function () {
var canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
img.parentNode.replaceChild(canvas, img)
// For IE7/8
if(typeof FlashCanvas != 'undefined') FlashCanvas.initElement(canvas)
// Canvas compositing code
var context = canvas.getContext('2d')
context.clearRect(0, 0, image.width, image.height)
context.drawImage(image, 0, 0, image.width, image.height)
context.globalCompositeOperation = 'xor'
context.drawImage(alpha, 0, 0, image.width, image.height)
}
}
}
// Apply this technique to every image on the page once DOM is ready
// (I just placed it at the bottom of the page for brevity)
var imgs = document.getElementsByTagName('img')
for(var i = 0; i < imgs.length; i++)
create_alpha_jpeg(imgs[i])
})();
In the head element I linked to FlashCanvas:
<!--[if lte IE 8]><script src="flashcanvas.js"></script><![endif]-->
... and I threw in this to avoid a flicker of the un-alpha’d JPEG:
I'm trying to display an iframe in my mobile web application, but I'm having trouble restricting the size of the iframe to the dimensions of the iPhone screen. The height and width attributes on the iframe element seem to have no effect, strangely. Surrounding it with a div manages to constrain it, but then I'm unable to scroll within the iframe.
Has anyone tackled iframes in mobile safari before? Any ideas where to start?
Yeah, you can't constrain the iframe itself with height and width. You should put a div around it. If you control the content in the iframe, you can put some JS within the iframe content that will tell the parent to scroll the div when the touch event is received.
like this:
The JS:
setTimeout(function () {
var startY = 0;
var startX = 0;
var b = document.body;
b.addEventListener('touchstart', function (event) {
parent.window.scrollTo(0, 1);
startY = event.targetTouches[0].pageY;
startX = event.targetTouches[0].pageX;
});
b.addEventListener('touchmove', function (event) {
event.preventDefault();
var posy = event.targetTouches[0].pageY;
var h = parent.document.getElementById("scroller");
var sty = h.scrollTop;
var posx = event.targetTouches[0].pageX;
var stx = h.scrollLeft;
h.scrollTop = sty - (posy - startY);
h.scrollLeft = stx - (posx - startX);
startY = posy;
startX = posx;
});
}, 1000);
The HTML:
<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" id="iframe" src="url" />
</div>
If you don't control the iframe content, you can use an overlay over the iframe in a similar manner, but then you can't interact with the iframe contents other than to scroll it - so you can't, for example, click links in the iframe.
It used to be that you could use two fingers to scroll within an iframe, but that doesn't work anymore.
Update: iOS 6 broke this solution for us. I've been attempting to get a new fix for it, but nothing has worked yet. In addition, it is no longer possible to debug javascript on the device since they introduced Remote Web Inspector, which requires a Mac to use.
If the iFrame content is not yours then the solution below will not work.
With Android all you need to do is to surround the iframe with a DIV and set the height on the div to document.documentElement.clientHeight. IOS, however, is a different animal. Although I have not yet tried Sharon's solution it does seem like a good solution. I did find a simpler solution but it only works with IOS 5.+.
Surround your iframe element with a DIV (lets call it scroller), set the height of the DIV and make sure that the new DIV has the following styling:
$('#scroller').css({'overflow' : 'auto', '-webkit-overflow-scrolling' : 'touch'});
This alone will work but you will notice that in most implementations the content in the iframe goes blank when scrolling and is basically rendered useless. My understanding is that this behavior has been reported as a bug to Apple as early as iOS 5.0. To get around that problem, find the body element in the iframe and add -webkit-transform', 'translate3d(0, 0, 0) like so:
$('#contentIframe').contents().find('body').css('-webkit-transform', 'translate3d(0, 0, 0)');
If your app or iframe is heavy on memory usage you might get a hitchy scroll for which you might need to use Sharon's solution.
This only works if you control both the outside page and the iframe page.
On the outside page, make the iframe unscrollable.
<iframe src="" height=200 scrolling=no></iframe>
On the iframe page, add this.
<!doctype html>
...
<style>
html, body {height:100%; overflow:hidden}
body {overflow:auto; -webkit-overflow-scrolling:touch}
</style>
This works because modern browsers uses html to determine the height, so we just give that a fixed height and turn the body into a scrollable node.
I have put #Sharon's code together into the following, which works for me on the iPad with two-finger scrolling. The only thing you should have to change to get it working is the src attribute on the iframe (I used a PDF document).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Pdf Scrolling in mobile Safari</title>
</head>
<body>
<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" id="iframe" src="data/testdocument.pdf" />
</div>
<script type="text/javascript">
setTimeout(function () {
var startY = 0;
var startX = 0;
var b = document.body;
b.addEventListener('touchstart', function (event) {
parent.window.scrollTo(0, 1);
startY = event.targetTouches[0].pageY;
startX = event.targetTouches[0].pageX;
});
b.addEventListener('touchmove', function (event) {
event.preventDefault();
var posy = event.targetTouches[0].pageY;
var h = parent.document.getElementById("scroller");
var sty = h.scrollTop;
var posx = event.targetTouches[0].pageX;
var stx = h.scrollLeft;
h.scrollTop = sty - (posy - startY);
h.scrollLeft = stx - (posx - startX);
startY = posy;
startX = posx;
});
}, 1000);
</script>
</body>
</html>
<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" src="url" />
</div>
I'm building my first site and this helped me get this working for all sites that I use iframe embededding for.
Thanks!
Sharon's method worked for me, however when a link in the iframe is followed and then the browser back button is pressed, the cached version of the page is loaded and the iframe is no longer scrollable. To overcome this I used some code to refresh the page as follows:
if ('ontouchstart' in document.documentElement)
{
document.getElementById('Scrolling').src = document.getElementById('SCrolling').src;
}
I implemented the following and it works well. Basically, I set the body dimensions according to the size of the iFrame content. It does mean that our non-iFrame menu can be scrolled off the screen, but otherwise, this makes our sites functional with iPad and iPhone. "workbox" is the ID of our iFrame.
// Configure for scrolling peculiarities of iPad and iPhone
if (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPad') != -1)
{
document.body.style.width = "100%";
document.body.style.height = "100%";
$("#workbox").load(function (){ // Wait until iFrame content is loaded before checking dimensions of the content
iframeWidth = $("#workbox").contents().width();
if (iframeWidth > 400)
document.body.style.width = (iframeWidth + 182) + 'px';
iframeHeight = $("#workbox").contents().height();
if (iframeHeight>200)
document.body.style.height = iframeHeight + 'px';
});
}
Purely using MSchimpf and Ahmad's code, I made adjustments so I could have the iframe within a div, therefore keeping a header and footer for back button and branding on my page. Updated code:
<script type="text/javascript">
$("#webview").bind('pagebeforeshow', function(event){
$("#iframe").attr('src',cwebview);
});
if (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPad') != -1)
{
$("#webview-content").css("width","100%");
$("#webview-content").css("height","100%");
$("#iframe").load(function (){ // Wait until iFrame content is loaded before checking dimensions of the content
iframeWidth = $("#iframe").contents().width();
if (iframeWidth > 400)
$("#webview-content").css("width",(iframeWidth + 182) + 'px');
iframeHeight = $("#iframe").contents().height();
if (iframeHeight>200)
$("#webview-content").css("height",iframeHeight + 'px');
});
}
</script>
and the html
<div class="header" data-role="header" data-position="fixed">
</div>
<div id="webview-content" data-role="content" style="height:380px;">
<iframe id="iframe"></iframe>
</div><!-- /content -->
<div class="footer" data-role="footer" data-position="fixed">
</div><!-- /footer -->
Don't scroll the IFrame page or its content, scroll the parent page. If you control the IFrame content, you can use the iframe-resizer library to turn the iframe element itself into a proper block level element, with a natural/correct/native height. Also, don't attempt to position (fixed, absolute) your iframe in the parent page, or present an iframe in a modal window, especially if it has form elements.
I also suspect that iOS Safari has a non-standards behavior that expands your iframe's height to its natural height, much like the iframe-resizer library will do for desktop browsers, which seem to render responsive iframe content at height 0px or 150px or some other not useful default. If you need to contrain width, try a max-width style inside the iframe.
The solution is to use Scrolling="no" on the iframe.
That's it.