2

I want to load two separate images in my script. I've accomplished it using:

<img src="iphone4.png" id="img1">
<img src="screenshot.png" id="img2">

<script>
        window.onload = function () {
            var img1 = document.getElementById('img1');
            var img2 = document.getElementById('img2');
</script>

Problem here though is that the images should not be visible on the page but are when loaded using markup. I simply want to load them through the script without first having to add them in the markup. I realize this is an extremely trivial problem, but searching for a solution has given me nothing.

I tried this approach:

        window.onload = function () {
            var img1 = "iphone4.png";
            var img2 = "screenshot.png";

But this did not work. Can someone with some common JS sense please give me some input on this issue.

EDIT : So this is how the markup/JS looks now, the images are still displayed and the final merge of the images won't show. The error I get is:

IndexSizeError: Index or size is negative or greater than the allowed amount
[Stanna vid fel]    

var image1 = context.getImageData(0, 0, width, height);

And this is the syntax:

<body>
    <img src="" id="img1">
    <img src="" id="img2">
    <p>Blended image<br><canvas id="canvas"></canvas></p>
    <script>
        window.onload = function () {
            var img1 = document.getElementById('img1');
            var img2 = document.getElementById('img2');

            img1.src = "iphone4.png";
            img2.src = "screenshot.png";

            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");
            var width = img1.width;
            var height = img1.height;
            canvas.width = width;
            canvas.height = height;

            var pixels = 4 * width * height;
            context.drawImage(img1, 0, 0);
            var image1 = context.getImageData(0, 0, width, height);
            var imageData1 = image1.data;
            context.drawImage(img2, 73, 265);
            var image2 = context.getImageData(0, 0, width, height);
            var imageData2 = image2.data;
            while (pixels--) {
                imageData1[pixels] = imageData1[pixels] * 0 + imageData2[pixels] * 1;
            }
            image1.data = imageData1;
            context.putImageData(image1, 0, 0);
        };
    </script>
Derek Henderson
  • 9,388
  • 4
  • 42
  • 71
AndroidHustle
  • 1,794
  • 5
  • 24
  • 47
  • "Problem here though is that the images also have to be visible on the page", I am not sure what you are trying to achieve, because with the HTML you posted, the images will be visible on the page AND will be loaded as well by the browser. What are you trying to achieve? – plalx Apr 22 '13 at 12:51
  • Thanks for the input plalx. What I'm doing is merging two images using JS. I have it running now, the two images are merged into one which currently is displayed beneath the two initial images. Problem is though that I would like to only have the new combined image showing, and not the two initial images. However, I have not found a way of making it work without loading the the images in the markup and from there take it in to the JS. I would like to be able to load the two initial images directly into JS without having to first add them as visible tags in the markup. I hope this clears it up. – AndroidHustle Apr 22 '13 at 12:57
  • What merging technique are you using? – plalx Apr 22 '13 at 13:02
  • @plalx This one here: http://stackoverflow.com/questions/3648312/blend-two-images-on-a-javascript-canvas – AndroidHustle Apr 22 '13 at 13:03
  • Check my solution, it should be what you need ;) – plalx Apr 22 '13 at 13:25

6 Answers6

3
window.onload = function () {
        var img1 = new Image();
        var img2 = new Image();

        //EDIT2 you can hide img, or simply not add them to the DOM...
        img1.style.display = "none";
        img2.style.display = "none";

        img1.src = "iphone4.png";
        img2.src = "screenshot.png";

EDIT: DO NOT DO THAT and your images won't be displayed

        document.body.append(img1);

OR

        document.getElementById("myID").append(img2);
Pouki
  • 1,654
  • 12
  • 18
  • but this seems to still display the images in the [img1] and [img2] tags though? – AndroidHustle Apr 22 '13 at 12:45
  • Correct me if I'm wrong, but this looks like it will also add the tags under body (or a new div) in the markup and have them visible? I need the images loaded into my JS without first having them displayed. – AndroidHustle Apr 22 '13 at 13:03
  • I hate people asking that so am sorry about that... But what's your aim ? – Pouki Apr 22 '13 at 13:17
  • You can see my edit and the comments to the question. Basically I want to merge two images into one. I have got it to work, but only if I first add the images I want to use as visible img tags in the markup and load the images into my JS from there. What I want to do is simply to load the images directly into the JS, from the folder, merge them and display the result. – AndroidHustle Apr 22 '13 at 13:23
  • ok, so if your code works with img tags... You can also hide images using CSS like my new edit ! – Pouki Apr 22 '13 at 13:26
  • I actually tried adding *display : none;* before posting this question, but then the script couldn't load the image data. At least when I tried it. But in either case, that does feel like somewhat like a "dirty solution", and I would like to find a solution that solves it only using JS. – AndroidHustle Apr 22 '13 at 13:49
  • ok, you can use an Image without adding it to the DOM instead ;) and works with. No ? – Pouki Apr 22 '13 at 13:52
3

You can create an Image without having the actual tag in the markup:

var img = new Image();
img.src = 'iphone4.png';
//use img however you want

Hope this helps.

Chad
  • 19,219
  • 4
  • 50
  • 73
  • 1
    Why was this answer downvoted? This is one of the few answers so far that answers the question that was asked, how to load an image into a script without loading it into the DOM. – Derek Henderson Apr 22 '13 at 13:26
  • Thanks! This did kind of work, problem is though that it only works when I'm debugging and stepping each operation. If I run it I get an error saying: **IndexSizeError: Index or size is negative or greater than the allowed amount var image1 = context.getImageData(0, 0, width, height);**. Do you know if I can add a separate thread, or some other solution to make sure the assets are loaded before continuing the method? – AndroidHustle Apr 22 '13 at 13:32
  • @DerekHenderson This answer doesn't solve the problem in any ways and was posted before carefully understanding the problem. That's why it has been downvoted. When in doubt, ask questions, but dont blindly guess answers. – plalx Apr 22 '13 at 13:41
  • I haven't blindly done anything! I haven't volunteered an answer. However, this question was posted by Chad before AndroidHustle completely re-edited the question to be something else. The initial question was about how to load an image without it appearing in the markup, and Chad's answer is the correct answer. Only later does AndroidHustle ask a separate question about merging images. Really, it's the question that should be downvoted for not being clear, not Chad's answer! – Derek Henderson Apr 22 '13 at 13:53
  • @DerekHenderson, it was obvious that the question wasnt clear and that's why I did asked some precisions instead of trying to answer it. There is no good answer to a bad question. People always try to answer as fast as possible to get reputation and they should get punished for that =P – plalx Apr 22 '13 at 14:01
  • I agree. But to downvote an answer which correctly answered the original question before all the edits is not right. The question's title and the content before "Edit" all suggest that AndroidHustle wants to know how to load an image in JS without it being in the DOM, and that's what Chad answered. What AndroidHustle was trying to achieve (which you asked him in a comment) was really irrelevant to the question being asked and has in fact turned this into a very different question than initially posed. Chad should not be penalized for this. – Derek Henderson Apr 22 '13 at 14:07
  • @DerekHenderson, How could it correctly answer the original question if the original question wasn't clear at all. A question is not simply based on the question's title... there was far more information in the initial post than "How do I load a local image using JS?". – plalx Apr 22 '13 at 14:17
  • The original question, before you posted your first comment, was clear enough. There have been numerous edits since. – Derek Henderson Apr 22 '13 at 14:36
  • @DerekHenderson, If that's the case I did not noticed, but now it's too late for me to remove my downvote, unless the answer gets edited, but I believe answers that doesn't deal with the updated question should just get deleted, or updated. – plalx Apr 22 '13 at 15:02
  • @plalx The original question was "How can I load an image without having it in the DOM", this is the correct answer to that question. I only just now came back to find he edited it to be a completely new question. Down voting a question because it wasn't updated as fast as you would like is not a down vote reason outlined in the FAQs, you are being a little ridiculous. I think my reputation on this site shows that I don't just "post an answer as quick as possible to gain points". – Chad Apr 22 '13 at 15:41
  • @Chad, Well like I just said, update your answer and I will remove my downvote. – plalx Apr 22 '13 at 18:05
  • @plalx Using that logic, you will need to down vote every answer in this question, and most on StackOverflow. I am leaving my answer since it was (and still is) correct, for those who come by later. – Chad Apr 22 '13 at 19:23
  • @Chad, I meant that my vote is locked and I cannot remove it unless you modifiy or update your answer. You made your point and I understand that I should probably not have downvoted, but now you have to edit your answer to unlock my vote. Thanks! – plalx Apr 22 '13 at 19:33
2

"What I'm doing is merging two images using JS"

Your problem is probably due to the fact that you are trying to draw images that have not been loaded yet. To circumvent this issue, you could create the images dynamically and set their src attribute to start loading the image and listen to the image's load event to know when they are fully loaded so that you can perform the merge safely.

I have not tested the code, but it should give you the idea.

var images = [
        'iphone4.png',
        'screenshot.png'
    ],
    len = images.length,
    i = 0,
    loadedCount = 0,
    img;

for (; i < len; i++) {
    img = document.createElement('img');

    //listener has to be added before setting the src attribute in case the image is cached
    img.addEventListener('load', imgLoadHandler);

    img.src = images[i];
    images[i] = img;
}

function mergeImages() {
    var img1 = images[0], 
        img2 = images[1];
    //do the merging stuff
}

function imgLoadHandler() {
    if (++loadedCount === len) {
        mergeImages();
    }
}
plalx
  • 42,889
  • 6
  • 74
  • 90
  • Thanks for the input! I have, somewhat, gotten it to work with Chad's answer. Only problem is though that it only works if I'm in debug mode, stepping through the method. If I run it as it is it seems that the assets don't have enough time to be loaded and I get an error: **IndexSizeError: Index or size is negative or greater than the allowed amount [Stanna vid fel] var image1 = context.getImageData(0, 0, width, height);**. Do you know if I can add some multi threading, or a wait function in the main thread, to make sure all assets are loaded before the method continues? – AndroidHustle Apr 22 '13 at 13:36
  • @AndroidHustle, The other answers will not work because it doesnt wait until the images are loaded. You have to use my solution or something similar. The only reason it works in debugger is that by going step by step through the code, it gives enough time to the image to get loaded asynchronously. – plalx Apr 22 '13 at 13:39
  • exactly.. Ok, so is that what your imgLoadHandler method does? Waits until the images are loaded for the merge I mean? – AndroidHustle Apr 22 '13 at 13:44
  • @AndroidHustle the `imgLoadHandler` increment the `loadedCount` and when it reaches the number of images, it means they are all loaded, so then it calls the `mergeImages` function where you can do the merging stuff because all images will have been loaded at that point. You can put this code inside `window.onload` and put your merging code inside the `mergeImages` function. – plalx Apr 22 '13 at 13:47
  • Cool! then I will try to apply this solution! – AndroidHustle Apr 22 '13 at 13:51
  • btw, is the === in the statement a typo, or is the triple equals char an established statement check? just curious, I don't know too much about JS syntax. – AndroidHustle Apr 22 '13 at 13:53
  • You should always use `===` instead of `==` in JS because you don't want to coerce type. – Derek Henderson Apr 22 '13 at 13:58
  • @plalx After a little tampering this worked like a charm! Thanks a lot for providing a great solution! – AndroidHustle Apr 22 '13 at 14:03
1

There is a way with HTML5, but it would still require the user to have dropped the file into a drop target or use a box.

Using the File API you can read files, and potentially decode them.

Actually reading the file blob and displaying it locally may be tricky though. You may be able to use the FileReader.readAsDataURL method to set the content as a data: URL for the image tag.

example:

$('#f').on('change', function(ev) {
    var f = ev.target.files[0];
    var fr = new FileReader();

fr.onload = function(ev2) {
    console.dir(ev2);
    $('#i').attr('src', ev2.target.result);
};

fr.readAsDataURL(f);
});​

see the working fiddle here : http://jsfiddle.net/alnitak/Qszjg/

Anil
  • 1,028
  • 9
  • 20
  • thanks, but I need the images (at least one of them) to be loaded automatically. In this solution it looks like you have to manually select the images in the explorer, which could work in another scenario, but not in mine I'm afraid. – AndroidHustle Apr 22 '13 at 13:01
0

using jquery:

$('#my_image').attr('src','image.jpg');

using javasript:

document.getElementById("my_image").src="image.jpg";

just check path to your image

Davor Mlinaric
  • 1,989
  • 1
  • 19
  • 26
0

Write the below code in head block

<script>
window.onload = function () {
           document.getElementById("img1").src="iphone4.png";
           document.getElementById("img2").src="screenshot.png";
}
</script>

This will work

Thanks

Claudio
  • 5,078
  • 1
  • 22
  • 33
Hariharan
  • 3,191
  • 4
  • 19
  • 31