I'm writing a WinForms application. I created a Google Doc template file that contains placeholders like {{name}} for various text elements. I can successfully make a copy of this document and use the BatchUpdateDocumentRequest to modify them just fine.
However, I also have an embedded image in the document. I can obtain the objectId for this image just fine. I either want to replace this image with another or remove it from my template and then append my new image to the end of the document. In both cases, the InsertInlineImage or ReplaceImage classes require a URI of the image to insert or replace with. This is where I have an issue.
The image itself has been captured from a control on the WinForms. Its actually a chart. I've saved the image in PNG format since I know that is one of the formats supported by Google drive/docs. I figured in order to use it in the batch update, I would need to upload it first, so I did and got its file id and webcontentlink back in the response.
I'm not locked into any particular way of doing this. I originally tried creating an HTML file, uploading but then it would strip the image from it, so became useless, so I switched gears to using a Google Doc as my template and just try to replace elements in it instead. This went well until I got to the image.
Essentially no matter what I try to specify as the URI, it says the file in not in a supported format.
As far as I can tell, Google expects the URI to actually end in .png or be a real link versus a download URL you'd get from Google Drive.
Here is an example of the code I'm using to attempt to replace the image. The strImageObjectId is the objectId of the Embedded Object image in the template document copy that I want to replace. The Uri is what Google needs to pull the new image from. I'm happy to pull it from my local computer or Google Drive if only I could get it to accept it somehow.
BatchUpdateDocumentRequest batchUpdateRequest = new BatchUpdateDocumentRequest {
Requests = new List<Google.Apis.Docs.v1.Data.Request>()
};
request = new Google.Apis.Docs.v1.Data.Request {
ReplaceImage = new ReplaceImageRequest() {
ImageObjectId = strImageObjectId,
Uri = strChartWebContentLink
}
};
batchUpdateRequest.Requests.Add(request);
DocumentsResource.BatchUpdateRequest updateRequest =
sDocsService.Documents.BatchUpdate(batchUpdateRequest, strCopyFileId);
BatchUpdateDocumentResponse updateResponse = updateRequest.Execute();
I'm happy to use whatever method will get me to a point where I an end up with a Google Doc on Google Drive that was based on a template in which I can replace various text elements, but most importantly add/replace an image.
Thanks so much for the advice.
I got to the point were I believe I was specifying the URI correctly, but then I started getting an access forbidden error instead.
I didn't have time to hunt this one down, so I went back to creating an HTML template with my image, uploading as a Google Doc, exporting to PDF, and then uploading as a PDF. This ended up working because originally I was using a BMP as the file format and that is not supported by Google Docs, so I changed to a PNG instead and it worked just fine.
I think Google Docs needs to add the ability to add an image using a MemoryStream or some other programmatic base64 resource instead of purely being based on URIs and running into temporary upload or permission issues.
Hey I'm doing the same thing with you,
and I got this, by modify the download link format.
from this:
https://docs.google.com/uc?export=download&id={{YOUR GDRIVE IMAGE
ID}
to this
https://docs.google.com/uc?export=view&id={{YOUR GDRIVE IMAGE ID}
e.g :
uri: "https://docs.google.com/uc?export=view&id=1cjgyHqtYSgS0CBT4x-9eQIHRzOIfGgv-"
but the image should be set for public privilege
Background
I am writing and using a very simple CGI-based (Perl) content management tool for two pro-bono websites. It provides the website administrator with HTML forms for events where they fill the fields (date, place, title, description, links, etc.) and save it. On that form I allow the administrator to upload an image related to the event. On the HTML page displaying the form, I am also showing a preview of the picture uploaded (HTML img tag).
The Problem
The problem happens when the administrator wants to change the picture. He would just have to hit the "browse" button, pick a new picture and press ok. And this works fine.
Once the image is uploaded, my back-end CGI handles the upload and reloads the form properly.
The problem is that the image shown does not get refreshed. The old image is still shown, even though the database holds the right image. I have narrowed it down to the fact that the IMAGE IS CACHED in the web browser. If the administrator hits the RELOAD button in Firefox/Explorer/Safari, everything gets refreshed fine and the new image just appears.
My Solution - Not Working
I am trying to control the cache by writing a HTTP Expires instruction with a date very far in the past.
Expires: Mon, 15 Sep 2003 1:00:00 GMT
Remember that I am on the administrative side and I don't really care if the pages takes a little longer to load because they are always expired.
But, this does not work either.
Notes
When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it). When replacing the existing image with a new one, the name doesn't change either. Just the content of the image file changes.
The webserver is provided by the hosting service/ISP. It uses Apache.
Question
Is there a way to force the web browser to NOT cache things from this page, not even images?
I am juggling with the option to actually "save the filename" with the database. This way, if the image is changed, the src of the IMG tag will also change. However, this requires a lot of changes throughout the site and I rather not do it if I have a better solution. Also, this will still not work if the new image uploaded has the same name (say the image is photoshopped a bit and re-uploaded).
Armin Ronacher has the correct idea. The problem is random strings can collide. I would use:
<img src="picture.jpg?1222259157.415" alt="">
Where "1222259157.415" is the current time on the server.
Generate time by Javascript with performance.now() or by Python with time.time()
Simple fix: Attach a random query string to the image:
<img src="foo.cgi?random=323527528432525.24234" alt="">
What the HTTP RFC says:
Cache-Control: no-cache
But that doesn't work that well :)
I use PHP's file modified time function, for example:
echo <img src='Images/image.png?" . filemtime('Images/image.png') . "' />";
If you change the image then the new image is used rather than the cached one, due to having a different modified timestamp.
I would use:
<img src="picture.jpg?20130910043254">
where "20130910043254" is the modification time of the file.
When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it). When replacing the existing image with a new one, the name doesn't change either. Just the content of the image file changes.
I think there are two types of simple solutions: 1) those which come to mind first (straightforward solutions, because they are easy to come up with), 2) those which you end up with after thinking things over (because they are easy to use). Apparently, you won't always benefit if you chose to think things over. But the second options is rather underestimated, I believe. Just think why php is so popular ;)
use Class="NO-CACHE"
sample html:
<div>
<img class="NO-CACHE" src="images/img1.jpg" />
<img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>
jQuery:
$(document).ready(function ()
{
$('.NO-CACHE').attr('src',function () { return $(this).attr('src') + "?a=" + Math.random() });
});
javascript:
var nods = document.getElementsByClassName('NO-CACHE');
for (var i = 0; i < nods.length; i++)
{
nods[i].attributes['src'].value += "?a=" + Math.random();
}
Result:
src="images/img1.jpg" => src="images/img1.jpg?a=0.08749723793963926"
You may write a proxy script for serving images - that's a bit more of work though. Something likes this:
HTML:
<img src="image.php?img=imageFile.jpg&some-random-number-262376" />
Script:
// PHP
if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {
// read contents
$f = open( IMG_PATH . $_GET['img'] );
$img = $f.read();
$f.close();
// no-cache headers - complete set
// these copied from [php.net/header][1], tested myself - works
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
// image related headers
header('Accept-Ranges: bytes');
header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
header('Content-Type: image/jpeg'); // or image/png etc
// actual image
echo $img;
exit();
}
Actually either no-cache headers or random number at image src should be sufficient, but since we want to be bullet proof..
I checked all the answers around the web and the best one seemed to be: (actually it isn't)
<img src="image.png?cache=none">
at first.
However, if you add cache=none parameter (which is static "none" word), it doesn't effect anything, browser still loads from cache.
Solution to this problem was:
<img src="image.png?nocache=<?php echo time(); ?>">
where you basically add unix timestamp to make the parameter dynamic and no cache, it worked.
However, my problem was a little different:
I was loading on the fly generated php chart image, and controlling the page with $_GET parameters. I wanted the image to be read from cache when the URL GET parameter stays the same, and do not cache when the GET parameters change.
To solve this problem, I needed to hash $_GET but since it is array here is the solution:
$chart_hash = md5(implode('-', $_GET));
echo "<img src='/images/mychart.png?hash=$chart_hash'>";
Edit:
Although the above solution works just fine, sometimes you want to serve the cached version UNTIL the file is changed. (with the above solution, it disables the cache for that image completely)
So, to serve cached image from browser UNTIL there is a change in the image file use:
echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";
filemtime() gets file modification time.
I'm a NEW Coder, but here's what I came up with, to stop the Browser from caching and holding onto my webcam views:
<meta Http-Equiv="Cache" content="no-cache">
<meta Http-Equiv="Pragma-Control" content="no-cache">
<meta Http-Equiv="Cache-directive" Content="no-cache">
<meta Http-Equiv="Pragma-directive" Content="no-cache">
<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">
Not sure what works on what Browser, but it does work for some:
IE: Works when webpage is refreshed and when website is revisited (without a refresh).
CHROME: Works only when webpage is refreshed (even after a revisit).
SAFARI and iPad: Doesn't work, I have to clear the History & Web Data.
Any Ideas on SAFARI/ iPad?
When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it).
Change this, and you've fixed your problem. I use timestamps, as with the solutions proposed above: Image-<timestamp>.jpg
Presumably, whatever problems you're avoiding by keeping the same filename for the image can be overcome, but you don't say what they are.
You must use a unique filename(s). Like this
<img src="cars.png?1287361287" alt="">
But this technique means high server usage and bandwidth wastage.
Instead, you should use the version number or date. Example:
<img src="cars.png?2020-02-18" alt="">
But you want it to never serve image from cache. For this, if the page does not use page cache, it is possible with PHP or server side.
<img src="cars.png?<?php echo time();?>" alt="">
However, it is still not effective. Reason: Browser cache ...
The last but most effective method is Native JAVASCRIPT. This simple code finds all images with a "NO-CACHE" class and makes the images almost unique. Put this between script tags.
var items = document.querySelectorAll("img.NO-CACHE");
for (var i = items.length; i--;) {
var img = items[i];
img.src = img.src + '?' + Date.now();
}
USAGE
<img class="NO-CACHE" src="https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png" alt="">
RESULT(s) Like This
https://example.com/image.png?1582018163634
Your problem is that despite the Expires: header, your browser is re-using its in-memory copy of the image from before it was updated, rather than even checking its cache.
I had a very similar situation uploading product images in the admin backend for a store-like site, and in my case I decided the best option was to use javascript to force an image refresh, without using any of the URL-modifying techniques other people have already mentioned here. Instead, I put the image URL into a hidden IFRAME, called location.reload(true) on the IFRAME's window, and then replaced my image on the page. This forces a refresh of the image, not just on the page I'm on, but also on any later pages I visit - without either client or server having to remember any URL querystring or fragment identifier parameters.
I posted some code to do this in my answer here.
From my point of view, disable images caching is a bad idea. At all.
The root problem here is - how to force browser to update image, when it has been updated on a server side.
Again, from my personal point of view, the best solution is to disable direct access to images. Instead access images via server-side filter/servlet/other similar tools/services.
In my case it's a rest service, that returns image and attaches ETag in response. The service keeps hash of all files, if file is changed, hash is updated. It works perfectly in all modern browsers. Yes, it takes time to implement it, but it is worth it.
The only exception - are favicons. For some reasons, it does not work. I could not force browser to update its cache from server side. ETags, Cache Control, Expires, Pragma headers, nothing helped.
In this case, adding some random/version parameter into url, it seems, is the only solution.
Add a time stamp <img src="picture.jpg?t=<?php echo time();?>">
will always give your file a random number at the end and stop it caching
With the potential for badly behaved transparent proxies in between you and the client, the only way to totally guarantee that images will not be cached is to give them a unique uri, something like tagging a timestamp on as a query string or as part of the path.
If that timestamp corresponds to the last update time of the image, then you can cache when you need to and serve the new image at just the right time.
I assume original question regards images stored with some text info. So, if you have access to a text context when generating src=... url, consider store/use CRC32 of image bytes instead of meaningless random or time stamp. Then, if the page with plenty of images is displaying, only updated images will be reloaded. Eventually, if CRC storing is impossible, it can be computed and appended to the url at runtime.
Ideally, you should add a button/keybinding/menu to each webpage with an option to synchronize content.
To do so, you would keep track of resources that may need to be synchronized, and either use xhr to probe the images with a dynamic querystring, or create an image at runtime with src using a dynamic querystring. Then use a broadcasting mechanism to notify all
components of the webpages that are using the resource to update to use the resource with a dynamic querystring appended to its url.
A naive example looks like this:
Normally, the image is displayed and cached, but if the user pressed the button, an xhr request is sent to the resource with a time querystring appended to it; since the time can be assumed to be different on each press, it will make sure that the browser will bypass cache since it can't tell whether the resource is dynamically generated on the server side based on the query, or if it is a static resource that ignores query.
The result is that you can avoid having all your users bombard you with resource requests all the time, but at the same time, allow a mechanism for users to update their resources if they suspect they are out of sync.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="mobile-web-app-capable" content="yes" />
<title>Resource Synchronization Test</title>
<script>
function sync() {
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var images = document.getElementsByClassName("depends-on-resource");
for (var i = 0; i < images.length; ++i) {
var image = images[i];
if (image.getAttribute('data-resource-name') == 'resource.bmp') {
image.src = 'resource.bmp?i=' + new Date().getTime();
}
}
}
}
xhr.open('GET', 'resource.bmp', true);
xhr.send();
}
</script>
</head>
<body>
<img class="depends-on-resource" data-resource-name="resource.bmp" src="resource.bmp"></img>
<button onclick="sync()">sync</button>
</body>
</html>
I've found Chrome specifically tries to get clever with the URL arguments solution on images. That method to avoid cache only works some of the time.
The most reliable solution I've found is to add both a URL argument (E.g. time stamp or file version) AND also change the capitalisation of the image file extension in the URL.
<img src="picture.jpg">
becomes
<img src="picture.JPG?t=current_time">
All the Answers are valid as it works fine. But with that, the browser also creates another file in the cache every time it loads that image with a different URL. So instead of changing the URL by adding some query params to it.
So, what we can do is we can update the browser cache using cache.put
caches.open('YOUR_CACHE_NAME').then(cache => {
const url = 'URL_OF_IMAGE_TO_UPDATE'
fetch(url).then(res => {
cache.put(url, res.clone())
})
})
cache.put updates the cache with a new response.
for more: https://developer.mozilla.org/en-US/docs/Web/API/Cache/put
I made a PHP script that automatically appends the timestamps on all images and also on links. You just need to include this script in your pages. Enjoy!
http://alv90.altervista.org/how-to-force-the-browser-not-to-cache-images/
Best solution is to provide current time at the end of the source href like
<img src="www.abc.com/123.png?t=current_time">
this will remove the chances of referencing the already cache image.
To get the recent time one can use performance.now() function in jQuery or javascript.
BackGround Info
Currently working on a C# web api that will be returning selected Img url's as base64. I currently have the functionality that would preform the base64 conversion however, I am getting a large amount of text which also include Img Url's which I will need to crop out of the string and give it to my function to convert the img to base 64. I read up on an lib.("HtmlAgilityPack;") that should make this task easy but when I am use it I get "HtmlDocument.cs" not found. However, I am not submitting a document, but sending it a string which is HTML. I read the doc and it is suppose to work with a string as well, but it is not working for me. This is the code using "HtmlAgilityPack".
NON WORKING CODE
foreach(var item in returnList)
{
if (item.Content.Contains("~~/picture~~"))
{
HtmlDocument doc = new HtmlDocument();
doc.Load(item.Content);
Error Message From HtmlAgilityPack
Question
I am receiving a string which is Html from SharePoint. This Html string may be tokenized with heading tokens and/or picture tokens. I am trying to isolate the retrieve the html from the img src Hmtl tag. I understand that regex may be impractical, but I would consider working with a regex expressions is it available to retrieve the url from img src.
Sample String
Bullet~~Increased Cash Flow</li><li>~~/Document Text Bullet~~Tax Efficient Organizational Structures</li><li>~~/Document Text Bullet~~Tax Strategies that Closely Align with Business Strategies</li><li>~~/Document Text Bullet~~Complete Knowledge of State and Local Tax Obligations</li></ul><p>~~/Document Heading 2~~is the firm of choice</p><p>~~/Document Text~~When it comes to accounting and advisory services is the unique firm of choice. As a trusted advisor to our clients, we bring an integrated client service approach with dedicated industry experience. Dixon Hughes Goodman respects the value of every client relationship and provides clients throughout the U.S. with an unwavering commitment to hands-on, personal attention from our partners and senior-level professionals.</p><p>~~/Document Text~~of choice for clients in search of a trusted advisor to deal with their state and local tax needs. Through our leading best practices and experience, our SALT professionals offer quality and ease to the client engagement. We are proud to provide highly comprehensive services.</p>
<p>~~/picture~~<br></p><p>
<img src="/sites/ContentCenter/Graphics/map-al.jpg" alt="map al" style="width:611px;height:262px;" />
<br></p><p><br></p><p>
~~/picture~~<br></p><p>
<img src="/sites/ContentCenter/Graphics/Firm_Telescope_Illustration.jpg" alt="Firm_Telescope_Illustration.jpg" style="margin:5px;width:155px;height:155px;" /> </p><p></div><div class="ExternalClassAF0833CB235F437993D7BEE362A1A88A"><br></div><div class="ExternalClassAF0833CB235F437993D7BEE362A1A88A"><br></div><div class="ExternalClassAF0833CB235F437993D7BEE362A1A88A"><br></div>
Important
I am working with an HTML string, not a file.
The issue you are having is that C# is looking for a file and since it is not finding it, it tells you. This is not an error that will brake your app, it is just telling you that the file is not found and the Lib will than read the string given. This documentation can be found here https://htmlagilitypack.codeplex.com/SourceControl/latest#Trunk/HtmlAgilityPackDocumentation.shfbproj. The code below is a cookie cutter model that anyone can use.
Important
C# is looking for a file which can not be displayed, because it a string that is supplied. That is the message that you are getting, however your still will work as well with accordance to the doc provided and will not effect your code.
Exmample Code
HtmlAgilityPack.HtmlDocument htmlDocument = new HtmlAgilityPack.HtmlDocument();
htmlDocument.LoadHtml("YourContent"); // can be a string or can be a path.
HtmlAttribute att = url.Attributes["src"];
Uri imgUrl = new System.Uri("Url"+ att.Value); // build your url
string matchString = Regex.Match(original_text, "<img.+?src=[\"'](.+?)[\"'].+?>", RegexOptions.IgnoreCase).Groups[1].Value;
It has been asked multiple times here.
also here
Does anyone know in .Net 2.0 - .Net 3.5 how to load a jpeg into a System.Windows.Forms.WebControl as a byte-array and with the right mimetypes set so it will show?
Something like:
webBrowser1.DocumentStream = new MemoryStream(File.ReadAllBytes("mypic.jpg"));
webBrowser1.DocumentType = "application/jpeg";
The webBrowser1.DocumentType seems to be read only, so I do not know how to do this. In general I want to be able to load any kind of filesource with a mimetype defined into the browser to show it.
Solutions with writing temp files are not good ones. Currently I have solved it with having a little local webserver socket listener that delivers the jpeg I ask for with the right mimetype.
UPDATE: Since someone deleted a answer-my-own question where I had info that others could use, I will add it as an update instead. (to those who delete that way, please update the questions with the important info).
Sample solution in C# here that works perfectly: http://www.codeproject.com/KB/aspnet/AspxProtocol.aspx
You have to implement an async pluggable protocol, e.g. IClassFactory, IInternetProtocol... Then you use CoInternetGetSession to register your protocol. When IE calls your implementation, you can serve your image data from memory/provide mime type.
It's a bit tedious, but doable. Look at IInternetProtocol and pluggable protocols documentation on MSDN.
You cannot do it. You cannot stuff images into Microsoft's web-browser control.
The limitation comes from the IWebBrowser control itself, which .NET wraps up.
If you want a total hack, try having your stream be the HTML file that only shows your picture. You lose your image byte stream and will have to write the image to disk.
I do not know whether the WebBrowser .NET control supports this, but RFC2397 defines how to use inline images. Using this and a XHTML snippet created on-the-fly, you could possibly assign the image without the need to write it to a file.
Image someImage = Image.FromFile("mypic.jpg");
// Firstly, get the image as a base64 encoded string
ImageConverter imageConverter = new ImageConverter();
byte[] buffer = (byte[])imageConverter.ConvertTo(someImage, typeof(byte[]));
string base64 = Convert.ToBase64String(buffer, Base64FormattingOptions.InsertLineBreaks);
// Then, dynamically create some XHTML for this (as this is just a sample, minimalistic XHTML :D)
string html = "<img src=\"data:image/" . someImage.RawFormat.ToString() . ";base64, " . $base64 . "\">";
// And put it into some stream
using (StreamWriter streamWriter = new StreamWriter(new MemoryStream()))
{
streamWriter.Write(html);
streamWriter.Flush();
webBrowser.DocumentStream = streamWriter.BaseStream;
webBrowser.DocumentType = "text/html";
}
No idea whether this solution is elegant, but I guess it is not. My excuse for not being sure is that it is late at night. :)
References:
RFC2397
Image to base64 encoded string
IE only support 32KB for inline images in base64 encoding, so not a good solution.
Try the res: protocol.
I haven't tried it with a .net dll but this post says it should work. Even if it does require a C++ dll it's much simpler to use as far as coding goes.
I've created a post that show you how here that shows you how to create the resource script and use the res: protocol correctly.