Prevent progressive jpeg from loading completely - jpeg

So, let's say I have a large version of an image that gets displayed only as a thumbnail. Would it be possible to avoid having a separate file for the thumbnail by using a progressive jpeg, stopping its loading when a certain number of scans have been reached, and continue loading only when the user chooses to open it in full?
If so, how can the loading of the image be controlled?
Thanks in advance.

There are 2 approaches:
1. Client-side heavy
Prerequisite
the image server has to support the range HTTP header
eg. Range: bytes=0-1024 means you are requesting only the first 1024 bytes
you have to know in advance how many bytes you want to request
you can say 1/8th of full size, if you push that value from server side
so the exact byte number should be known in the client side
if the Range is not valid or not supported, then the server will return the whole image, which is a good natural "fallback"
Cross domain requests: if html and images are on different domains
Access-Control-Allow-Headers: "range" has to be set
Apache .htaccess example on image server:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers: "range"
</IfModule>
If the browser fails to make the request due to improper CROS settings, the code falls back to set the data-src attribute to the src attribute
Overview
request image with an AJAX request
set Range header of AJAX request to how many bytes you want to get back
set the mimeType to plaintext (so we can base64 encode it later)
Base64 encode data and set it to image's src attribute (<img src="data:image/jpeg;base64,...">)
beware for larger images this can be quite heavy on the client
If setting the src attribute fails for whatever reason (eg. improper CROS settings), then fall back to set the data-src attribute to the src attribute
The code
This is built on gaetanoM's awesome answer here: Get Image using jQuery.ajax() and decode it to base64
// for each img, which has data-src and data-bytes attributes
$('img[data-src][data-bytes]').each(function(i,e){
$.ajax({
url: $(e).data('src'), // url of image
type: 'GET',
headers: {
'Range':'bytes=0-'+$(e).data('bytes') // Range header, eg. Range: bytes=0-1024
},
mimeType: "text/plain; charset=x-user-defined"
}).done(function( data, textStatus, jqXHR ) {
$(e).attr('src', 'data:image/jpeg;base64,' + base64encode(data)); // on success we set the base64 encoded data to the image's src attribute
}).always(function(){
// if setting the src failed for whatever reason, we fall back to set the data-src attribute to src attribute
if(!$(e).attr('src'))
$(e).attr('src', $(e).data('src'));
});
});
function base64encode(str) {
var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var out = "", i = 0, len = str.length, c1, c2, c3;
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
out += CHARS.charAt(c1 >> 2);
out += CHARS.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
out += CHARS.charAt(c1 >> 2);
out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
out += CHARS.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += CHARS.charAt(c1 >> 2);
out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
out += CHARS.charAt(c3 & 0x3F);
}
return out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- total filesize is 35 933 bytes -->
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="1900">
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="2500">
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="5600">
<!-- if data-bytes are erroneous the server will return the whole image -->
<img data-src="http://shoepimper.com/doklist.com-logo.jpg" data-bytes="error">
<!-- if CROS fails, then it falls back to set the data-src attribute to the src attribute -->
<img data-src="https://i.stack.imgur.com/QOPRf.jpg" data-bytes="error">
2. Server-side heavy
Ellaborating on ProgressiveMonkey's comment, you can easily trim the image data with php, or any other server side programming language.
Overview
server side: trim the image data based on an url parameter
if you want to know exactly where the first scan ends, please read this wonderful answer: How many bytes are needed for a complete thumbnail of a progressive JPEG?
client side: change that url parameter as you wish
Server-side code
<?php
$div = isset($_GET['div']) && intval($_GET['div'])>1 ? intval($_GET['div']) : 1; // what fraction of the image shall we return
$img = 'doklist.com-logo.jpg';
$size = round(filesize($img) / $div); // calculating the size in bytes what we return
// setting the headers
header("Content-Type: image/jpeg");
header("Content-Length: $size");
$fp = fopen($img, 'r');
echo fread($fp, $size); // returning the necessary amount of bytes
fclose($fp);
?>
Examples
Please see here an example of one of our site's logo (Doklist.com)
Please feel free to play along with this url's div parameter (also please note that my test server may not handle the increased traffic well):
http://shoepimper.com/progressive-thumb.php?div=14
Reading just 1/24th of the filesize and returning it as a whole image:
<img src="http://shoepimper.com/progressive-thumb.php?div=24">
Reading 1/14th of the image:
<img src="http://shoepimper.com/progressive-thumb.php?div=14">
Reading 1/6th of the image:
<img src="http://shoepimper.com/progressive-thumb.php?div=6">
Reading the whole image (1/1th)
<img src="http://shoepimper.com/progressive-thumb.php?div=1">
If you need help to determine whether the image is progressively encoded or not, then use this: http://codepen.io/sergejmueller/full/GJKwv
If you don't have direct access to the images, then you should use a proxy, meaning the structure of the code itself doesn't really change, you just "fopening" a remote file.

It would be possible. You would just need to modify a decoder to do it.
You can control the loading as long as you have access to the data stream.

Related

Code not saving when trying to wrap promoted tiles in SharePoint Online

Apologies for another question re this, but I've tried so hard to get this working (I'm fairly new to SharePoint, don't have extensive coding knowledge, but know HTML and generally alright at trouble shooting).
We are using SharePoint online and we have SharePoint Tiles. We have recently added a few more tiles and it's obviously not wrapping these tiles, thus having to scroll right to access some.
I have found the code for wrapping the tiles here and when editing the page source, it appears to be working... until I save it. The code I put in is stripped out when I next go to the content editor.
I've read a few pages on it and have tried things such as the content editor web part, but for the life of me cannot get it to work.
If anyone would know if there's a step to step guide to ensure wrapped tiles are saved, I may be able to get it to work.
Any help is greatly appreciated.
If it changes anything, we use SharePoint online that is part of our Office 365 account.
Add the following code into script editor web part in the page.
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// Update this value to the number of links you want to show per row
var numberOfLinksPerRow = 6;
// local variables
var pre = "<tr><td><div class='ms-promlink-body' id='promlink_row_";
var post = "'></div></td></tr>";
var numberOfLinksInCurrentRow = numberOfLinksPerRow;
var currentRow = 1
// find the number of promoted links we're displaying
var numberOfPromotedLinks = $('.ms-promlink-body > .ms-tileview-tile-root').length;
// if we have more links then we want in a row, let's continue
if (numberOfPromotedLinks > numberOfLinksPerRow) {
// we don't need the header anymore, no cycling through links
$('.ms-promlink-root > .ms-promlink-header').empty();
// let's iterate through all the links after the maximum displayed link
for (i = numberOfLinksPerRow + 1; i <= numberOfPromotedLinks; i++) {
// if we're reached the maximum number of links to show per row, add a new row
// this happens the first time, with the values set initially
if (numberOfLinksInCurrentRow == numberOfLinksPerRow) {
// i just want the 2nd row to
currentRow++;
// create a new row of links
$('.ms-promlink-root > table > tbody:last').append(pre + currentRow + post);
// reset the number of links for the current row
numberOfLinksInCurrentRow = 0;
}
// move the Nth (numberOfLinksPerRow + 1) div to the current table row
$('#promlink_row_' + currentRow).append($('.ms-promlink-body > .ms-tileview-tile-root:eq(' + (numberOfLinksPerRow) + ')'));
// increment the number of links in the current row
numberOfLinksInCurrentRow++;
}
}
});
</script>
We can also use CSS style below in script editor web part in the page to achieve it.
<style>
.ms-promlink-body {
width: 960px;
}
</style>

Using rotate for images leads to blank pdf with pdfkit

I have asked the question on the repository directly, but in my experience SO is more reactive.
Hey there,
I am trying to create a pdf from photos using pdfkit.
Depending on whether an image is in landscape or portait mode, I want to turn the image around.
This basically means the following (in typescript) :
function toPostscriptPoint(mm: number) {
return mm * 2.8346456693;
}
const document = new PDFDocument({
size: [toPostscriptPoint(156), toPostscriptPoint(106)],
});
document.pipe(fs.createWriteStream('output.pdf'));
document.save();
document.rotate(90);
document.image(
'photos/sample.jpeg',
{ width: toPostscriptPoint(150), fit: [toPostscriptPoint(150), toPostscriptPoint(100)] });
document.restore();
document.end();
What happens though is that the pdf renders completely white. I do see however that something is happening, because the pdf has the size of the input image.
Is rotation for images not supported? What would be possible alternatives? I would like to avoid having to rewrite my files before putting them in the pdf.
Thanks
Alright, after investigation, I can answer my own question :).
I could see that the images were in the pdf somehow because of the size of the file so I dived deeper.
What happened was that the image was rendered out of the viewport. This was due to multiple things:
By default, the origin of a page after rotation in pdfkit is the center of the page! ( See the doc for more info)
The origin is rotated together with the transformation.
The x and y in the image method are actually inverted.
So after getting all this right, the following code shows the image as expected :
function toPostscriptPoint(mm: number) {
return mm * 2.8346456693;
}
const document = new PDFDocument({
size: [toPostscriptPoint(156), toPostscriptPoint(106)],
});
document.pipe(fs.createWriteStream('output.pdf'));
document.save();
document.rotate(90, {origin : [0, 0]});
document.image(
'photos/sample.jpeg',
toPostscriptPoint(0),
toPostscriptPoint(-150),
{ width: toPostscriptPoint(150), height: toPostscriptPoint(100) });
document.restore();
document.end();
Note the :
origin argument in the rotation
toPostscriptPoint(-150) actually takes into account the position of the origin, and corresponds to the X axis.
Hope that helps some later on :).
Its because taking picture from camera , if picture ISO is less than 100 it will be automatically rotated , take picture with iso more than or equal to 100 to avoid autorotation.

Imagemagick and web fonts

Does anyone know if ImageMagick can be powered by a web font? (Or perhaps feed in via STD IN?) I tried the line below with no luck:
convert -fill black -font http://fonts.googleapis.com/css?family=Diplomata+SC -pointsize 72 label:'Acme Dynamite Company, LLC' logo.png
My goal would be to let users choose a Google Web Font.
If you wget the GWF API, it returns a TTF url:
$ wget -qO- "http://fonts.googleapis.com/css?family=Diplomata+SC" | urlext2
http://themes.googleusercontent.com/static/fonts/diplomatasc/v1/JdVwAwfE1a_pahXjk5qpNonF5uFdDttMLvmWuJdhhgs.ttf
$
Final update: The user barethon wrote a python woff to ttf converter, which works perfectly. (https://github.com/hanikesn/woff2otf/blob/master/woff2otf.py) I'm now able to rip down the font I want from Google, convert it to ttf and use it with imagemagick. Slightly more complicated than I would have liked, but no big deal.
I know this is pretty old at this point, but in the interest of savings others some times, here is some basic PHP to do what you want. It could be optimized to use curl and such, but this should be enough to get people going. It appears that when accessed from a browser it returns a woff and woff2 url, but when accessed from anything else it returns a tff.
$fontUrl = 'http://fonts.googleapis.com/css?family=Anton';
$fontDescription = file_get_contents($fontUrl);
$startStr = 'url(';
$startStrLen = strlen($startStr);
$start = strpos($fontDescription, $startStr) + $startStrLen;
$end = strpos($fontDescription, ')', $start);
$tffUrl = substr($fontDescription, $start, $end - $start);
$tffFile = '/tmp/anton.ttf';
file_put_contents($tffFile, file_get_contents($tffUrl));
$im = new Imagick();
$im->setFont($tffFile);
$im->newPseudoImage(100, 100, "caption:Hello");
$im->setImageFormat('png');
$im->setImageBackgroundColor(new ImagickPixel('transparent'));
header('Content-Type: image/png');
echo $im->__toString();
Thank you to Floss for your approach to this problem. I solved it in a similar way.
The reason I used a random number rather than a static filename like font.ttf is in case other users were calling the function at the same time, it could create an issue.
Query the Google Fonts list
$url = 'https://www.googleapis.com/webfonts/v1/webfonts?key=YOUR KEY HERE';
$responseString = file_get_contents($url);
$fontJSON = json_decode($responseString);
Access the url of the fonts like so:
<select name="font">
<?php foreach ($fontJSON->items as $font): ?>
<option value="<?= $font->files->regular ?>"><?= $font->family ?></option>
<?php endforeach; ?>
</select>
Note that you'd have to do some other trickery to select the variants (like bold or italic) but that's beyond this post.
After passing the form data to the server, use it in the following way.
//create a random number for a unique filename
$random_number = intval( "0" . rand(1,9) . rand(0,9) . rand(0,9) . rand(0,9) . rand(0,9) );
//download the TTF from Google's server
$font_contents = file_get_contents($font);
//Make a local file of a unique name
$font_file = fopen("/tmp/$random_number.ttf", "w");
//Write data from the Google Font file into your local file
fwrite($font_file, $font_contents);
//Close the file
fclose($font_file);
//Set iMagick to use this temporary file
$draw->setFont("/tmp/$random_number.ttf");
//DO YOUR iMagick STUFF HERE
Delete the temporary font file
unlink("tmp/$random_number.ttf"); //remove tmp font

trying to extract formatted images from indesign into a separate folder

I'm looking for a way to extract images from an ID file in a 'formatted' / cropped form.
i.e: a. I have placed numerous, hi-res (tiff, psd) images into an InDesign CS5 file
b. The image boxes that they have been placed into, are smaller than the actual image (pretty intense cropping occurred) c. I am trying to collect these images in their new stage (cropped to the image box) and export them as jpg at 72dpi.
Are there any plug-ins out there that would automatically collect "formatted" images from ID for me? Or is there some other way?
If you're familiar with Indesign Scripting, this can very easily be done via a script. I use Javascript but this can be done with VBSript or AppleScript as well. Here is a basic example of a script that will open a document, and export a rectangle (your image box) as a JPG. Basically, you can just loop through the pictures in your document and export each one to a location/filename you choose (see the myFile variable below). There are several "jpegExportPreferences" you can pick from to determine how your output JPG will be (i.e. DPI).
test();
function test(){
var myDoc = app.open('c:/user/desktop/testDocument.indd');
var myGroups = myDoc.groups;
//for each group...
for (var i = 0;i < myGroups.length; i++){
// for each rectangle in the group...
for(var r = 0; r< myGroups[i].rectangles.length; r++){
var myRect = myGroups[i].rectangles[r];
app.jpegExportPreferences.exportResolution = 300;
app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MAXIMUM;
//give it a unique name
var myFile = new File('c:/users/desktop/newJPG' + myRect.id + '.jpg');
myRect.exportFile(ExportFormat.JPG, myFile);
}
}
}
For a list of the other optional JPG Export preferences, see this link:
http://indesignscriptingreference.com/cs2/javascript-cs2/jpegexportpreference.htm
Hope this helps!

How to display vertical text (90 degree rotated) in all browsers?

How can I display vertical text (90 degree rotated) in all browsers?
(source: sun.com)
The problem is independent from the server side language. If it's not a problem when the vertically rendered text isn't text anymore but an image, choose the solution provided by tharkun. Otherwise, there are ways to do it in the presentation layer.
First, there's (at the moment) an IE-only solution, which is part of the CSS3 standard. You can check it live.
p {
writing-mode: tb-rl;
}
The CSS3 text module also specify some properties for text orientation.
Other guys do it with SVG.
I don't think you can rotate text with PHP/HTML/CSS. But you can create an image with GD containing vertical text.
Example:
header ("Content-type: image/png");
// imagecreate (x width, y width)
$img_handle = #imagecreatetruecolor (15, 220) or die ("Cannot Create image");
// ImageColorAllocate (image, red, green, blue)
$back_color = ImageColorAllocate ($img_handle, 0, 0, 0);
$txt_color = ImageColorAllocate ($img_handle, 255, 255, 255);
ImageStringUp ($img_handle, 2, 1, 215, $_GET['text'], $txt_color);
ImagePng ($img_handle);
ImageDestroy($img_handle);
function verticletext($string)
{
$tlen = strlen($string);
for($i=0;$i<$tlen;$i++)
{
$vtext .= substr($string,$i,1)."<br />";
}
return $vtext;
}
there you go no echo
Text rotation is also possible with other browsers.
CSS:
/*Safari*/
-webkit-transform: rotate(-90deg);
/*Firefox*/
-moz-transform: rotate(-90deg);
/*Opera*/
-o-transform: rotate(-90deg);
/*IE*/
writing-mode: tb-rl;
filter: flipV flipH;
I use the function below if table header rows are too long. It's quite useful because it's easy to use, fast and you don't have to calculate text height & width. Those css-gimmicks just don't work.
#######################################################
# convert text to image and embed it to html
# uses /tmp as a cache to make it faster
# usage: print imagetext("Hello my friend");
# Created by Ville Jungman, GPL-licenced, donated by www.varuste.net
function imagetext($text,$size = 10,$color = array(253,128,46)){
$dir = "/tmp/tekstit";
$filename = "$dir/" . base64_encode($text);
if(!file_exists($filename)){
$font = "/usr/share/fonts/truetype/freefont/FreeSans.ttf";
$box = imagettfbbox($size,90,$font,$text);
$w = -$box[4] - 1;
$h = -$box[3];
$im = imagecreatetruecolor($w,$h);
$white = imagecolorallocate($im,$color[1],$color[2],$color[3]);
$black = imagecolorallocate($im, 0x00, 0x00, 0x00);
imagecolortransparent($im,$white);
imagefilledrectangle($im, 0, 0, $size, 99, $white);
imagettftext($im,$size,90,$size,$h,$black,$font,$text);
#mkdir($dir);
imagepng($im,$filename);
imagedestroy($im);
}
$data = base64_encode(file_get_contents($filename));
return "<img src='data:image/png;base64,$data'>";
}
This thread suggests that you can write text to an image and then rotate the image.
It appears to be possible with IE but not with other browsers so it might be one of those little win for IE6 =)
imagettftext oughta do the trick.
As far as I know it's not possible to get vertical text with CSS, so that means that the rotated text has to be in an image. It's very straightforward to generate with PHP's' libgd interface to output an image file.
Note however that this means using one script to produce the image, and another to produce the surrounding web page. You can't generally (inline data: URI's notwithstanding) have one script produce more than one page component.
Use raphaeljs
It works on IE 6 also
http://raphaeljs.com/text-rotation.html
function verticletext($string)
{
$tlen = strlen($string);
for($i=0;$i<$tlen;$i++)
{
echo substr($string,$i,1)."<br />";
}
}

Resources