Link to home
Start Free TrialLog in
Avatar of Panos
PanosFlag for Germany

asked on

Js-Jquery preview image before upload

Hello experts.
I need help to remake a very useful tutorial from this website: https://gist.github.com/cute/4006330
The problem i have is that i want to use this with multiple input "file" types. I decided to try to handle this by classes and not id's. Because i'm using jquery it seems that it should be easy to specify the elements but unfortunately the result was not as expected. When i select an image in the firast input file all preview classes show this image, and on IE it is not working at all
I'm posting both codes. The tutorial and my remake
Tutorial:
<!DOCTYPE html>
<html>
<head>
<meta chraset="utf-8" />
<style type="text/css">
 #kk{ 
  width:400px; height:400px; overflow: hidden; 
 } 
 #preview_wrapper{
  width:120px; height:90px; background-color:#CCC; overflow: hidden; 
 } 
 #preview_fake{
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
  width:120px; overflow: hidden; 
 } 
 #preview_size_fake{ 
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);
  width:120px; visibility:hidden; overflow: hidden; 
 } 
 #preview{  
  width:120px; height:90px; overflow: hidden; 
 }
</style>
<script type="text/javascript">
 function onUploadImgChange(sender) {
  if (!sender.value.match(/.jpg|.gif|.png|.bmp/i)) {
   alert('no image file');
   return false;
  }
  var objPreview = document.getElementById('preview');
  var objPreviewFake = document.getElementById('preview_fake');
  var objPreviewSizeFake = document.getElementById('preview_size_fake');
  if (sender.files && sender.files[0]) {
   objPreview.style.display = 'block';
   objPreview.style.width = 'auto';
   objPreview.style.height = 'auto';
   try {
    objPreview.src = sender.files[0].getAsDataURL();
   } catch(e) {
    var reader = new FileReader();
    reader.onload = function(e) {
     objPreview.src = e.target.result;
    }
    reader.readAsDataURL(sender.files[0]);
   }
  } else if (objPreviewFake.filters) {
   sender.select();
   sender.blur();
   var imgSrc = document.selection.createRange().text;
   objPreviewFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   objPreviewSizeFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   autoSizePreview(objPreviewFake, objPreviewSizeFake.offsetWidth, objPreviewSizeFake.offsetHeight);
   objPreview.style.display = 'none';
  }
 }

 function onPreviewLoad(sender) {
  autoSizePreview(sender, sender.offsetWidth, sender.offsetHeight);
 }

 function autoSizePreview(objPre, originalWidth, originalHeight) {
  var zoomParam = clacImgZoomParam(120, 90, originalWidth, originalHeight);
  objPre.style.width = zoomParam.width + 'px';
  objPre.style.height = zoomParam.height + 'px';
  objPre.style.marginTop = zoomParam.top + 'px';
  objPre.style.marginLeft = zoomParam.left + 'px';
 }

 function clacImgZoomParam(maxWidth, maxHeight, width, height) {
  var param = {
   width: width,
   height: height,
   top: 0,
   left: 0};
  if (width > maxWidth || height > maxHeight) {
   rateWidth = width / maxWidth;
   rateHeight = height / maxHeight;

   if (rateWidth > rateHeight) {
    param.width = maxWidth;
    param.height = height / rateWidth;
   } else {
    param.width = width / rateHeight;
    param.height = maxHeight;
   }
  }

  param.left = (maxWidth - param.width) / 2;
  param.top = (maxHeight - param.height) / 2;
  return param;
 }
</script>
</head>
<body>
 <p>
  <input name="localfile" type="file" id="localfile" size="28" onchange="onUploadImgChange(this)"
  />
  <div id="kk">
   <div id="preview_wrapper">
    <div id="preview_fake">
     <img id="preview" src="http://placekitten.com/300/300" onload="onPreviewLoad(this)" />
    </div>
   </div>
   <br/>
   <img id="preview_size_fake" />
  </div>
 </p>
</body>
</html>

Open in new window


Remake using classes:
<!DOCTYPE html>
<html>
<head>
<meta chraset="utf-8" />
<style type="text/css">
 .kk{ 
  width:200px; height:150px; overflow: hidden; 
 } 
 .preview_wrapper{
  width:120px; height:90px; background-color:#CCC; overflow: hidden; 
 } 
 .preview_fake{
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
  width:120px; overflow: hidden; 
 } 
 .preview_size_fake{ 
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);
  width:120px; visibility:hidden; overflow: hidden; 
 } 
 .preview{  
  width:120px; height:90px; overflow: hidden; 
 }
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
 function onUploadImgChange(sender) {
  if (!sender.value.match(/.jpg|.gif|.png|.bmp/i)) {
   alert('no image file');
   return false;
  }
  var objinput = $(sender);
  var objmaindiv = objinput.parent().nextAll('.kk');  
  var objPreview = objmaindiv.find('.preview'); 
  var objPreviewFake = objmaindiv.find('div.preview_fake');
  var objPreviewSizeFake = objmaindiv.children('.preview_size_fake');
  if (sender.files && sender.files[0]) {
   objPreview.css("display", "block");
   objPreview.css("width", "auto");
   objPreview.css("height", "auto");
   try {
    objPreview.attr('src',sender.files[0].getAsDataURL());
   } catch(e) {
    var reader = new FileReader();
    reader.onload = function(e) {
     objPreview.attr('src',e.target.result) ;
    }
    reader.readAsDataURL(sender.files[0]);
   }
  } else if (objPreviewFake.filters) {
   sender.select();
   sender.blur();
   var imgSrc = document.selection.createRange().text;
   objPreviewFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   objPreviewSizeFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   autoSizePreview(objPreviewFake, objPreviewSizeFake.offsetWidth, objPreviewSizeFake.offsetHeight);
   objPreview.hide();
  }
 }

 function onPreviewLoad(sender) {
  autoSizePreview(sender, sender.offsetWidth, sender.offsetHeight);
 }

 function autoSizePreview(objPre, originalWidth, originalHeight) {
  var zoomParam = clacImgZoomParam(120, 90, originalWidth, originalHeight);
  objPre.style.width = zoomParam.width + 'px';
  objPre.style.height = zoomParam.height + 'px';
  objPre.style.marginTop = zoomParam.top + 'px';
  objPre.style.marginLeft = zoomParam.left + 'px';
 }

 function clacImgZoomParam(maxWidth, maxHeight, width, height) {
  var param = {
   width: width,
   height: height,
   top: 0,
   left: 0};
  if (width > maxWidth || height > maxHeight) {
   rateWidth = width / maxWidth;
   rateHeight = height / maxHeight;

   if (rateWidth > rateHeight) {
    param.width = maxWidth;
    param.height = height / rateWidth;
   } else {
    param.width = width / rateHeight;
    param.height = maxHeight;
   }
  }

  param.left = (maxWidth - param.width) / 2;
  param.top = (maxHeight - param.height) / 2;
  return param;
 }
</script>
</head>
<body>
 <p>
  <input name="localfile" type="file" id="localfile1" size="28" onchange="onUploadImgChange(this)"/>
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview"  src="" onload="onPreviewLoad(this)" />
    </div>
   </div>
   <br/>
   <img class="preview_size_fake" />
  </div>
 </p>
 <p>
  <input name="localfile" type="file" id="localfile2" size="28" onchange="onUploadImgChange(this)"/>
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview" src="" onload="onPreviewLoad(this)" />
    </div>
   </div>
   <br/>
   <img  class="preview_size_fake" />
  </div>
 </p>
 <p>
  <input name="localfile" type="file" id="localfile3" size="28" onchange="onUploadImgChange(this)"/>
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview" src="" onload="onPreviewLoad(this)" />
    </div>
   </div>
   <br/>
   <img class="preview_size_fake" />
  </div>
 </p>
</body>
</html>

Open in new window


Any help?
Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

just a few errors in the source but it works here
http://q28683425.azurewebsites.net/
Save the code below as "hielo-test.html" and give it a try.  Be sure to read the comments in the code:
<!DOCTYPE html>
<html>
<head>
<meta chraset="utf-8" />
<style type="text/css">
 .kk{ 
  width:200px; height:150px; overflow: hidden; 
 } 
 .preview_wrapper{
  width:120px; height:90px; background-color:#CCC; overflow: hidden; 
 } 
 .preview_fake{
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
  width:120px; overflow: hidden; 
 } 
 .preview_size_fake{ 
  filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image);
  width:120px; visibility:hidden; overflow: hidden; 
 } 
 .preview{  
  width:120px; height:90px; overflow: hidden; 
 }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
 function onUploadImgChange(sender) {
  if (!sender.value.match(/.jpg|.gif|.png|.bmp/i)) {
   alert('no image file');
   return false;
  }
  var objinput = $(sender);

  // #var objmaindiv = objinput.parent().nextAll('.kk');
  // I don't know what was your intention with the statement above, but you
  // should be trying to get only ONE "div.kk" -- the one immediately after the
  // <input type="file"> that was just clicked.
  var objmaindiv = objinput.next('.kk');
  
  //on the original code, the variables below get initialized by getElementById()
  //which returns null OR a reference to the respoctive DOM node!!!
  //By contrast, a jquery selector returns a jquery object, NOT the DOM node.
  //So to make your code compatible, you need to extract the actual DOM node
  //from the returned jquery object wherever necessary.  To do so, just append
  //".get(0)" after a selector expression
  var objPreview = objmaindiv.find('.preview').get(0); 
  var objPreviewFake = objmaindiv.find('div.preview_fake').get(0);
  var objPreviewSizeFake = objmaindiv.children('.preview_size_fake').get(0);
  
  if (sender.files && sender.files[0]) {
   objPreview.css("display", "block");
   objPreview.css("width", "auto");
   objPreview.css("height", "auto");
   try {
    objPreview.attr('src',sender.files[0].getAsDataURL());
   } catch(e) {
    var reader = new FileReader();
    reader.onload = function(e) {
     objPreview.attr('src',e.target.result) ;
    }
    reader.readAsDataURL(sender.files[0]);
   }
  } else if (objPreviewFake.filters) {
   sender.select();
   sender.blur();
   var imgSrc = document.selection.createRange().text;
   objPreviewFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   objPreviewSizeFake.filters.item('DXImageTransform.Microsoft.AlphaImageLoader').src = imgSrc;
   autoSizePreview(objPreviewFake, objPreviewSizeFake.offsetWidth, objPreviewSizeFake.offsetHeight);
   
   //since objPreview is now a DOM node reference (not a jquery object), you need
   //to wrap it around $() in order to invoke the ".hide()" method.
   $(objPreview).hide();
  }
 }

 function onPreviewLoad(sender) {
  autoSizePreview(sender, sender.offsetWidth, sender.offsetHeight);
 }

 function autoSizePreview(objPre, originalWidth, originalHeight) {
  var zoomParam = clacImgZoomParam(120, 90, originalWidth, originalHeight);
  objPre.style.width = zoomParam.width + 'px';
  objPre.style.height = zoomParam.height + 'px';
  objPre.style.marginTop = zoomParam.top + 'px';
  objPre.style.marginLeft = zoomParam.left + 'px';
 }

 function clacImgZoomParam(maxWidth, maxHeight, width, height) {
  var param = {
   width: width,
   height: height,
   top: 0,
   left: 0};
  if (width > maxWidth || height > maxHeight) {
   rateWidth = width / maxWidth;
   rateHeight = height / maxHeight;

   if (rateWidth > rateHeight) {
    param.width = maxWidth;
    param.height = height / rateWidth;
   } else {
    param.width = width / rateHeight;
    param.height = maxHeight;
   }
  }

  param.left = (maxWidth - param.width) / 2;
  param.top = (maxHeight - param.height) / 2;
  return param;
 }


// now, when the document is ready, bind the onchange and onload events
// of the respective elements.  So you don't need to included these attributes
// in your html markup.
$(function(){
	
	$('.row')
		.on('change','input[type="file"]',function(){
				onUploadImgChange(this);
			})
		.on('load','img.preview',function(){
				onPreviewLoad(this);
		});
});
</script>
</head>
<body>
<form>

 <div class="row">
  <input name="localfile" type="file" id="localfile1" size="28" />
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview"  src="" />
    </div>
   </div>
   <br/>
   <img class="preview_size_fake" />
  </div>
 </div>

 <div class="row">
  <input name="localfile" type="file" id="localfile2" size="28"/>
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview" src="" />
    </div>
   </div>
   <br/>
   <img  class="preview_size_fake" />
  </div>
 </div>
 
 <div class="row">
  <input name="localfile" type="file" id="localfile3" size="28"/>
  <div class="kk">
   <div class="preview_wrapper">
    <div class="preview_fake">
     <img  class="preview" src="" />
    </div>
   </div>
   <br/>
   <img class="preview_size_fake" />
  </div>
 </div>
 </form>
</body>
</html>

Open in new window

Avatar of Panos

ASKER

Hi
Thank you for your posts

Hielo the code is not working.
I get error :
TypeError: objPreview.css is not a function
objPreview.css("display", "block");

line:51

David Johnson  i'm sorry but i can't understand your post. The tutorial code is working. Have you made any changes?
Avatar of Panos

ASKER

I got it:
$(objPreview).css("display", "block");
   $(objPreview).css("width", "auto");
   $(objPreview).css("height", "auto");
but the images don't resize in FF
It is working in IE
SOLUTION
Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
you could have gone to the site I submitted and tested it and then grabbed the source.
Avatar of Panos

ASKER

Hi David Johnson.
Thank you again for your post. I did go to your page you posted and i saw your source. There are realy mistakes and i m going to make the changes
I still need a working solution with multiple inputs and classes using jquery.
Experts Hielo code needs a little correcton to make it working perfect (or i m doing something wrong). I m sorry but i will be able to answer to any solution tomorrow because it is too late for me. Thank you so far for your help.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Panos

ASKER

Hi hielo
Thank you for your post.
Your code is working but i have a problem
Testing the original code with the id's and the script part:
.....
if (sender.files && sender.files[0]) {
   objPreview.style.display = 'block';
   objPreview.style.width = 'auto';
   objPreview.style.height = 'auto';
......

I get for the image css following in firebug:
User generated image
Using the jquery work around :
.....
if(sender.files && sender.files[0])
                        {
                              $(objPreview).css("display", "block");
                              $(objPreview).css("width", "auto !important");
                              $(objPreview).css("height", "auto !important");
.....

I get for the image css following in firebug:
User generated image
The image is been stretched to suit 100% in the image tag.

I don't know why it happends. I'm testing and testing but i don't find the solution.
A solution could be to use the same calculator script that is been used for the IE.
Can you you please helpme with this?
>>A solution could be to use the same calculator script that is been used for the IE.
I don't know what you are talking about.  Please clarify.
Avatar of Panos

ASKER

If i'm reading correct the script the following line:
autoSizePreview(objPreviewFake, objPreviewSizeFake.offsetWidth, objPreviewSizeFake.offsetHeight);

is for IE ...if(objPreviewFake.filters)..

This is calculating the preview image size:
function autoSizePreview(objPre, originalWidth, originalHeight)
                  {.......
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Panos

ASKER

Hi
I delete the !important attribute and it is working in FF.
It is not working in IE and i'm searching for a solution
Avatar of Panos

ASKER

Hi.
I think it is working now. I cleared the cached. I will test it tomorrow again. Thank you very much for your help
Avatar of Panos

ASKER

Sorry i did check my comment too
Avatar of Panos

ASKER

Thank you for your help