Information graphical visualization for web-page: Is there any better way instead of small PNG files? - html

Let's describe the task first:
I'd like to create a web-page with several rows of a text and a small (let's say 100 by 20 pixels) graphic for each one. Each graphic generated dynamically (so it will be a new one each time the page is loaded).
The only way I can imagine to my self is to create on server a new PNG file each time the row is indicated and include the link to this newly created file to HTML: <img src='row1graph.png'>.
If the page would be the single image - I could output it directly to the browser, but this is not my case.
So the question is: is there any better way to handle such images and skip unnecessary disk access operations?

You can serve an image from PHP rather than from a file - I mean you can have PHP dynamically create an image and serve it rather than having to have a file in your webserver's filesystem and having to refer to it by name in the src field of an tag in your HTML.
So, instead of
<image src="xyz.png" alt="..." size="...">
you can use
<img src="/php/thumb.php?param1=128&param2=45"/>
which causes the PHP script at /php/thumb.php to be called when the page is rendered. In that script, you can dynamically create the image (using extra parameters if you wish) like this:
<?php
header("Content-type: image/png");
$p1 = $_GET['param1'];
$p2 = $_GET['param2'];
// Create a 200x200 image
$im = imagecreatetruecolor(200,200);
$white = imagecolorallocate($im, 255, 255, 255);
$red = imagecolorallocate($im, 255, 0, 0);
// Here you can draw in the image, write on it, set any pixels, calculate any colours you wish
// Draw a white rectangle, then a red one
imagefilledrectangle($im, 50, 50, 100, 100, $white);
imagefilledrectangle($im, 75, 75, 150, 150, $red);
imagepng($im);
imagedestroy($im);
?>
I have omitted some code after the first 3 lines so you just see the technique rather than all the gory details of my code. The actual lines you are interested in are:
header(...image/png);
which tells the browser what type of stuff is coming - i.e. an image, and
imagepng();
which actually sends the stream of PNG data to the browser.
The code above produces this in the browser:

There's two ways to optimize small graphics in a web page. You can use the tile-set concept (all the graphics in a single image, with offsets based on e.g. background-position), or you can embed the PNG directly into the page as base-64:
<img alt="Embedded Image" src="data:image/png;base64,yourbase64image" />
The options have different merits based on file size and browser support. And of course, both can be combined - you can have an embedded tile-set.

Well if you want to avoid "unnecessary disk access" and since the image size is small you can use Base64 encoding. You can store the encoded strings in the database as well.
This way <img src='row1graph.png'> becomes...
<img src="data:image/jpg;base64,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"/>

Related

WTL CCommandBarCtrl imagelist (default and hot/disabled) ignored when set

I am trying to modify the images in a ribbon's Quick-Access-Toolbar but all my attempts seem to be in vain. I had the WTL-wizard create a simple ribbon-based application to start with. The wizard creates a CMainFrame with the a member var called 'm_CmdBar' of type 'CCommandBarCtrl'.
In 'CMainFrame::OnCreate()' the m_CmdBar is created with 'Create( m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE )' and the images are loaded with 'LoadImages(IDR_MAINFRAME)'. The images come from the default visual-studio provided 4-bit Bitmap toolbar-resource. If I leave 'LoadImages(IDR_MAINFRAME)' untouched, then the crappy 4bit icons are visible in the QAT.
Now, reading through the very sparsely only available WTL documentation (and Win32 API docu about about image lists) some people suggest to change the image list. I tried the following approaches (after commenting out 'LoadImages(IDR_MAINFRAME)' in order to start with a blank slate.).
1st attempt (load a 32Bit bitmap-strip with 5 16x15px consecutive icons):
CBitmap bmp;
bmp.LoadBitmap( IDB_TEST32BPP );
WTL::CImageList imgList = m_CmdBar.GetImageList();
imgList.Create( 16, 15, ILC_COLOR32, 8, 1 );
imgList.Add( bmp.m_hBitmap, RGB( 255, 255, 255 ) ); // also tried different masks
m_CmdBar.SetImageList( imgList );
imgList.Detach(); // also tried once without detaching
But to no avail. I tried to force the imagelist with:
m_CmdBar.SendMessage( TB_SETIMAGELIST, 0, (LPARAM)imgList.m_hImageList );
but it this did not work either.
2nd attempt is very much like the first, except that this time I changed the create call to:
imgList.Create( 16, 15, ILC_COLOR24 | ILC_MASK, 8, 1 );
in hope that maybe the loading code does not like 32bpp images... but again, no cigar (LoadBitmap was adjusted to load a 24bpp version of course). 3rd attempt was to simply reload the default images (4bit) so again I changed the create call to:
imgList.Create( 16, 15, ILC_COLOR4 | ILC_MASK, 8, 1 );
but you have guessed it... noting. And with nothing I actually mean, that the QuackAccess-Toolbar does reserve the space for the 5 buttons (as per the XAML ribbon config) but icons/images do not appear. The QAT-buttons are white but react to interaction. Trying to load the hot and disabled lists using the provided WTL-API also does nothing at all.
The only approach that worked somehow was to manually load every bitmap directly and linking it to its command with:
CBitmap bmp;
bmp.LoadBitmap( IDB_ICON1_32BPP );
m_CmdBar.AddBitmap( bmp.m_hBitmap, ID_TEST_BTN );
works as long as the XAML config correctly provides an entry in the QAT section for ID_TEST_BTN. AddIcon also works but introduces an artifact (a black vertical
1px-bar, as if a right-frame was drawn for every icon. I guess it's the 16x16 versus 16x15 pixel problem).
I might be inclined to give up and go with the AddBitmap-workaround, but I'd like the disabled and hot-version to work too, and there is no AddBitmap for that as it looks. Also, I guess there is no way to force an image to any of the QAT buttons via the XAML file???

SVG Stack not working in Chrome (webkit)

I have been exploring using SVG's for the latest website I've been building - bit behind the times so trying to catch up. I initially setup my file similar to the way I would do a normal sprite. Although this worked, it does seem a little clumsy when you want to take advantage of resizing the vector and then trying to find the new background position in the document!
After doing some research I came across the idea of stacking it via layers - which makes a heap of sense. After getting all excited and successfully doing this I then came across a few posts saying this isn't support in all browsers - typical.
https://code.google.com/p/chromium/issues/detail?id=128055#c6
Here is a great tutorial for stacking SVG images in a single file as well as some work arounds for browsers that don't support it: http://hofmannsven.com/2013/laboratory/svg-stacking/
Although this works fine, is there an alternative to save writing all this extra code and fallbacks?
After thinking about this a little I decided I could take advantage of the Apache server and see if I could simply inject what I needed into the document. The end result? Works perfect in all browsers :)
To start with I added some code in my .htaccess file to capture all .svg requests
RewriteRule ^(.*)\.svg$ /{path-to-file}/svg.php [L]
Then I wrote a few lines to deal with the target layer and inject that into the file
(UPDATE) Added new variable called target-fill to allow for dynamically changing the fill colour of a shape if required
<?php
// Set the SVG header
header('Content-Type: image/svg+xml');
$queryString = Array();
if(isset($_SERVER['QUERY_STRING'])) $queryString = explode('&', $_SERVER['QUERY_STRING']);
// Get target from the query string
$target = $queryString[0];
// Get a fill alternative if available and valid
if(isset($queryString[1]) && hexdec($queryString[1]) !== false) {
$targetFill = '#' . $queryString[1];
} else {
$targetFill = '';
}
// Validate the target - this is your ID in the SVG file
$validTargets = Array('Camera', 'Layer_1');
if(!in_array($target, $validTargets)) $target = false;
// Get contents of the file - tweak this depending on where you have saved this file to relative to the root of your website
$filename = '../..' . $_SERVER['REDIRECT_URL'];
// Get the contents of the file
$contents = file_get_contents($filename);
// Replace the target with the valid target above
// - doing it this way rather than echoing the target in the SVG file as it seemed like a security risk
if($target) $contents = str_replace('g:target', 'g#' . $target, $contents);
// Replace the fill colour if available
$contents = str_replace('target-fill', $targetFill, $contents);
// Output the amended SVG file
echo $contents;
Included near the top of the SVG is the stacking code to hide we don't want displayed and to turn on what we do
<defs>
<style>
svg g { display: none }
svg g:target, svg g:target g { display: inline }
svg g:target * { fill: target-fill; }
</style>
</defs>
And that is it. So now instead of calling your SVG file like (also works as a background image):
<img src="images/svg-file.svg#Camera">
You would do it like this
<img src="images/svg-file.svg?Camera">
The advantage of doing it this way is you can now also do some further checks based on the user agent to return an alternative file altogether if SVG isn't supported.
(UPDATE) You can now also express a second parameter to change the fill colour if required. Use it like this:
<img src="images/svg-file.svg?Camera&cc0000">
Hope this helps someone else out there.

Loading CSS background images before normal images?

I have a ruby on rails web app, and in some views i have many heavy images( <img> ) to render .The <img> are generated in a Helper.
The problem is that the css is loaded first, then the js, then the heavy images , and then finally the css refereneced background images.
It takes quite a while for all of the heavy images to load, which therefore holds the whole site up.
I want to load first the css background images then load the other images, as they obviously hold visual structure of the page.
rails version: 2.3.8
EDIT:
Thank you guys, I apologize for not having shared the code earlier.
I have two models : Categories and Images, each Category has many images.
In the view i have a list of categories, which is generated by a helper :
categories.each do |cat|
html << "<a href='##{cat.id}' class='mapcat' >#{cat.libelle}</a>"
end
and when I click on the category the images are displayed
categories_images.each do |i|
html << "<div id='#{i.id}' class='#{css}'><img src='/images_moi/categories/#{cat.libelle}/#{i.path_file_name}' />"
end
I have css background image associated to the list of category
The problem is that the images (<img>) is displayed before the css background images of the list of categories.
We need to assume things because you haven't shared your code.
Coming to your query, for now you can preload images using jQuery:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}
// Usage:
preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);
This saves the loading time of loading images.
Use a base64 string.
Example:
background-image: url(data:image/png;base64,*CONVERTED IMAGE DATA HERE*);
without: **
online converter: http://webcodertools.com/imagetobase64converter
note: I only would suggest this if the image size is not too heavy.
Solution: Do not use the img tag.
Create a sprite containing all your images. Load the sprite in your application.html layout once.
Use data uris to transmit the data directly in the html. See http://css-tricks.com/data-uris/
My approach is to lazy load the images using jquery and data- tags. This approach also allows me to choose different images based on device width and spare tablet/mobile users.
<img src="" data-src="/img/graphic-desktop.jpg" data-smallsrc="/img/graphic-smaller.jpg" alt="Graphics" class="lazy" />
<!-- the following would be in your js file -->
$lazy = $('img.lazy');
$(window).load(function(){
// window load will wait for all page elements to load, including css backgrounds
$lazy.each(function(){
// run thru each img.lazy on the page. spare the jquery calls by making $this a variable
$this = $(this);
// if the window is greater then 800px wide, use data-src, otherwise, use the smaller graphic
($(window).width() >= 800) ? $this.attr('src', $this.attr('data-src')) : $this.attr('src', $this.attr('data-smallsrc'));
});
});

Controlling image load order in HTML

Is there a way to control the load order of images on a web page? I was thinking of trying to simulate a preloader by first loading a light-weight 'LOADING' graphic. Any ideas?
Thanks
Use Javascript, and populate the image src properties later. The # tells the browser to link to a URL on the page, so no request will be sent to the server. (If the src property was empty, a request is still made to the server - not great.)
Assemble an array of image addresses, and recurse through it, loading your images and calling a recursive function when the onload or onerror method for each image returns a value.
HTML:
<img src='#' id='img0' alt='[]' />
<img src='#' id='img1' alt='[]' />
<img src='#' id='img2' alt='[]' />
JS:
var imgAddresses = ['img1.png','img2.jpg','img3.gif'];
function loadImage(counter) {
// Break out if no more images
if (counter==imgAddresses.length) { return; }
// Grab an image obj
var I = document.getElementById("img"+counter);
// Monitor load or error events, moving on to next image in either case
I.onload = I.onerror = function() { loadImage(counter+1); }
//Change source (then wait for event)
I.src = imgAddresses[counter];
}
loadImage(0);
You could even play around with a document.getElementsByTagName("IMG").
By the way, if you need a loading image, this is a good place to start.
EDIT
To avoid multiple requests to the server, you could use almost the same method, only don't insert image elements until you're ready to load them. Have a <span> container waiting for each image. Then, loop through, get the span object, and dynamically insert the image tag:
var img = document.createElement("IMG");
document.getElementById('mySpan').appendChild(img);
img.src = ...
Then the image request is made only once, when the element is created.
I think this article https://varvy.com/pagespeed/defer-images.html gives a very good and simple solution. Notice the part which explains how to create "empty" <img> tags with:
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">
to avoid <img src="">
To display a loading image, just put it in the HTML and change it later at the appropriate moment/event.
Just include the 'loading' image before any other images. usually they are included at the very top of the page and then when the page loading completes, they are hidden by a JS.
Here's a small jQuery plugin that does this for you: https://github.com/AlexandreKilian/imageorder

Is it possible to load an entire web page before rendering it?

I've got a web page that automatically reloads every few seconds and displays a different random image. When it reloads, however, there is a blank page for a second, then the image slowly loads. I'd like to continue to show the original page until the next page is loaded into the browser's memory and then display it all at once so that it looks like a seamless slideshow. Is there a way to do this?
is the only thing changing the image? if so it might be more efficient to use something like the cycle plugin for jQuery instead of reloading your whole page.
http://malsup.com/jquery/cycle/
Here is the JS needed if you used jQuery -
Say this was your HTML:
<div class="pics">
<img src="images/beach1.jpg" width="200" height="200" />
<img src="images/beach2.jpg" width="200" height="200" />
<img src="images/beach3.jpg" width="200" height="200" />
</div>
Here would be the needed jQuery:
$(function(){
$('div.pics').cycle();
});
no need to worry about different browsers- complete cross browser compatibility.
If you're just changing the image, then I'd suggest not reloading the page at all, and using some javascript to just change the image. This may be what the jquery cycle plugin does for you.
At any rate, here's a simple example
<img id="myImage" src="http://someserver/1.jpg" />
<script language="javascript">
var imageList = ["2.jpg", "3.jpg", "4.jpg"];
var listIndex = 0;
function changeImage(){
document.getElementById('myImage').src = imageList[listIndex++];
if(listIndex > imageList.length)
listIndex = 0; // cycle around again.
setTimeout(changeImage, 5000);
};
setTimeout(changeImage, 5000);
</script>
This changes the image source every 5 seconds. Unfortunately, the browser will download the image progressively, so you'll get a "flicker" (or maybe a white space) for a few seconds while the new image downloads.
To get around this, you can "preload" the image. This is done by creating a new temporary image which isn't displayed on the screen. Once that image loads, you set the real image to the same source as the "preload", so the browser will pull the image out of it's cache, and it will appear instantly. You'd do it like this:
<img id="myImage" src="http://someserver/1.jpg" />
<script language="javascript">
var imageList = ["2.jpg", "3.jpg", "4.jpg"];
var listIndex = 0;
var preloadImage = new Image();
// when the fake image finishes loading, change the real image
function changeImage(){
document.getElementById('myImage').src = preloadImage.src;
setTimeout(preChangeImage, 5000);
};
preloadImage.onload = changeImage;
function preChangeImage(){
// tell our fake image to change it's source
preloadImage.src = imageList[listIndex++];
if(listIndex > imageList.length)
listIndex = 0; // cycle around again.
};
setTimeout(preChangeImage, 5000);
</script>
That's quite complicated, but I'll leave it as an exercise to the reader to put all the pieces together (and hopefully say "AHA!") :-)
If you create two divs that overlap in the image area, you can load one with a new image via AJAX, hide the current div and display the one with the new image and you won't have a web page refresh to cause a the "bad transition". Then repeat the process.
If there's only a small number of images and they're always displayed in the same order, you can simply create an animated GIF.
Back in the dark old days (2002) I handled this kind of situation by having an invisible iframe. I'd load content into it and in the body.onload() method I would then put the content where it needed to go.
Pre-AJAX that was a pretty good solution.
I'm just mentioning this for completeness. I'm not recommending it but it's worth noting that Ajax is not a prerequisite.
That being said, in your case where you're simply cycling an image, use Ajax or something like the jQuery cycle plug-in to cycle through images dynamically without reloading the entire page.