Context: I want to be able to extract text via OCR from a screenshot that I insert into a Google Sheet cell. I have tried for hours, searching the Internet, trying different tactics, but I cannot find a way to get a file ID, URL, or Blob for the screenshot that has been inserted into the cell (the sheet has only 1 cell). BTW I have already worked out the code I need once I get a fileID, URL, or Blob to do the OCR.
Questions:
First, is it possible to get a reference (file ID, etc.) to an image in a cell?
Second, when I select a function in a dropdown (e.g. .getContentURL) and it produces a “not a function” error, what does that indicate (e.g. there is no content, or something else)?
function getImageHandle()
{
// get the sheet object
var inputSheet = ss.getSheetByName("InPutSheet");
// get the file ID of the cell content
var fileID = inputSheet.getRange("A1").getValue().fileID();
// get the Blob of the cell content
var blob = inputSheet.getRange("A1").getValue().getBlob();
// get the URL of the cell content
var url = inputSheet.getRange("A1").getContentUrl();
// return the reference to the image in the cell
return one of the above (fileID, blob, or URL) ;
}
I run my own fantasy baseball yearly projections and I'm looking to automatically add player images to a sheet I created.
Test Page
I use a formula to create a link to the player's image page on ESPN.
https://a.espncdn.com/combiner/i?img=/i/headshots/mlb/players/full/33859.png
Is there a way to automatically add the player image to the page?
=image("Link") is the formula, but i cant use the cell location as the link.
Any advise or guidance will be helpful and appreciated
I created an Apps Script method to achieve your target as it is not possible to do it using formula.
Here's the script I did with comments:
function SpecialOnEdit(e) {
//Get the edited cell
var range = e.range;
//Get the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
//Download the image. (e.value is the URL in Google sheet)
var response = UrlFetchApp.fetch(e.value);
//Get the binary data of the image and create a blob object
var binaryData = response.getContent();
var blob = Utilities.newBlob(binaryData, 'image/png', 'MyImageName');
//Insert the image into the same row that the user place the image URL link
var image = sheet.insertImage(blob, range.getHeight(), range.getRow());
//Set the height of the row, show that the image can fit the row
sheet.setRowHeight(range.getRow(), image.getHeight() + 10);
}
You should add triggers next after pasting the script. Go to your Script Editor and click Edit->Current project's triggers->Add Trigger->under Select event type, select On edit->click Save
Next, to test the trigger and script, paste a URL of a PNG image format in the spreadsheet to validate the result.
Here's a sample output of the script and trigger:
The excellent dropdown jQuery UI Multiselect widget that supports styling via jQuery UI Themeroller still doesn't have support for including images within the drop down rows.
I didn't see any answers to this problem within Stackoverflow yet it seems to be asked regularly in various areas of the internet, so I am giving the answer to this question below..
(ALSO See my FIDDLE Example to see this in action,)
The following is based on an initial idea by 'pdlove' for introducing the use of images within this excellent UI Multiselect for jQuery.
Adding Image support for line items in check box text area is achieved by setting out the selector option rows html like this:
<option value="somevalue" image="yourimage.jpg" class="multSelktrImg">
normal visible text
</option>
I would also add a class control to your style sheet css file to set the image size being rendered in the option line items of the drop down, along with a couple of position settings for the image, label and span text.
In this example I use the class name 'multSelktrImg', so within the css file it would look something like this:
.multSelktrImg span{position: relative;top: 10px;vertical-align: middle;
display: inline-flex;}
.multSelktrImg input {vertical-align: -2px;}
.multSelktrImg img {position: relative;height: 30px;margin: 2px 6px;top: -10px;}
Now for the change in the src/jquery.multiselect.js file
Search for the following matching code around line 130 (depending on what version id of the script you are using):
// build items
el.find('option').each(function( i ){
var $this = $(this),
parent = this.parentNode,
title = this.innerHTML,
description = this.title,
....
ADD the following line above "title = this.innerHTML,":
image = this.getAttribute("image");
so that it looks like this:
// build items
el.find('option').each(function( i ){
var $this = $(this),
parent = this.parentNode,
image = this.getAttribute("image");
title = this.innerHTML,
description = this.title,
Now Search for the following matching code around line 180:
// add the title and close everything off
html += ' /><span>' + title + '</span></label></li>';
....
Replace the code line with the following to allow for rendering of your images:
// add the title and close everything off
html += ' /><span>';
if (image != null) {
html += '<img src="'+image+'" class="multSelktrImg">';
}
html += title + '</span></label></li>';
save the new version of the script src/jquery.multiselect.js file and now the images will appear in the multiselect drop down. Use the 'multSelktrImg' class value to control the size of the image displayed by altering the pixel size for the class in your css file.
In the FIDDLE version, I have altered the minimized version of the jQuery script, and created an initialisation of the Select object.
I have a telerik RadGrid that gets populated with data from a SQL database when the grid loads. The first column lists a name, which needs to be a hyperlink to another part of the website. I have tried a couple different options, neither of which gets me the results I need.
The first way I tried was using a GridHyperLinkColumn. However that does not allow me to change the displayed text of the hyperlink programmatically when the grid gets populated with data.
<telerik:GridHyperLinkColumn DataNavigateUrlFields="joblink" DataNavigateUrlFormatString="/Job.aspx?id={0}" Text="JobName">
taskDR.Item("joblink") = dataReader("publicID")
taskDR.Item("joblink").Text = dataReader("name") 'This is what I would like to do
The other option was to use a GridBoundColumn and bind a Hyperlink to it.
<telerik:GridBoundColumn DataField="joblink" UniqueName="joblink">
Dim jobhyperlink As New HyperLink()
jobhyperlink.Text = dataReader("name")
jobhyperlink.NavigateUrl = "/Job.aspx?id=" & dataReader("publicID").ToString()
taskDR.Item("joblink") = jobhyperlink
However instead of displaying the hyperlink in the joblink column, all that displays is "System.Web.UI.WebControls.HyperLink"
I looked into the DataTextField and DataTextFormatString properties of GridHyperLinkColumn, but I couldn't find a way to alter those fields programmatically.
you can try a template column and just place a html tag and use Eval function to bind the things the way you want.
Check out this demo - http://demos.telerik.com/aspnet-ajax/grid/examples/generalfeatures/columntypes/defaultcs.aspx
I finally figured it out.
<telerik:GridHyperLinkColumn UniqueName="joblink" Text="jobname" DataNavigateUrlFields="joblink" DataNavigateUrlFormatString="/Employer/Job.aspx?action=edit&id={0}" DataTextField="jobname" DataTextFormatString="{0}">
Dim taskDT As New DataTable
taskDT.Columns.Add("jID")
taskDT.Columns.Add("jobname") 'You need one column for the DataTextField
taskDT.Columns.Add("joblink") 'and another for the DataNavigateUrlField
While dataReader.Read()
Dim taskDR = taskDT.NewRow()
taskDR.Item("jobname") = dataReader("name")
taskDR.Item("joblink") = dataReader("publicID")
Recently i've been working on a rather modest application, which lists contacts. When a detail-link was clicked, a popup would come up with more details and an image of that contact.
The table this was based on contained a column photo_reference, which held a path to a folder under /i/. With this setup, it was easy to get the images working for each contact.
The popup i showed was a bunch of htmlcode i put in the region footer, and hid.
<div id="contact_popup" class="contact_pop">
<div class="contact_pop_imgcontainer">
<img id="id_photo" class="contact_pop" />
</div>
</div>
When the detail was clicked, i retrieved data via an application process, and showed a modal dialog of this container.
Now the scope has changed: users need to be able to upload their own images. So, i went to work and made it so the images get uploaded into wwv_flow_files, and then i move them to a new contact_image table. So far so good. But now i want to display these pictures, and here i'm kind of stuck.
* I could include a column in my IR, and put a blob format mask on it with image. I've got this working, but annoyingly. My image table has as primary key the field 'ID'. My contacts table also has 'ID' as PK.
Since IMAGE:APXT_CONTACTS_IMG:SMALL_PHOTO:ID::::::inline: specifies ID as the PK, it uses ID from my contacts table.
My link between tables is APXT_CONTACTS.CONTACT_IMAGE_ID -> APXT_CONTACTS_IMG.ID.
The way i might make it work is to rename my id field in the image table to contact_image_id. (why couldnt the format mask just take the column it's based on as the value :().
I then could hide the column, and take the image with javascript to show in my popup. However, this preloads all images for the amount of selected rows, which isn't entirely bad, but i'm looking for an alternative first.
get_blob_file_src also seems no use to me because of the limited use of the parameters (file browse item, id field), and even then, could i use this through an ajax callback?
I'd much rather be able to get the image blob via ajax to then display in my popup, but i have no clue as to how to do this. I've made a stored procedure which gets the file to download and call this from an application process (ajax callback), and with firebug i can see the post/response, but i wouldn't know how to get this displayed as an image.
Javascript:
function cimg(){
var get = new htmldb_Get(null, &APP_ID., "APPLICATION_PROCESS=get_img", &APP_PAGE_ID.);
get.addParam('x01', 25);
var greturn = get.get();
alert(greturn);
var pic = new Image();
pic.onload = function(){
document.body.appendChild(pic);
};
pic.src = greturn;
};
Page process:
begin
show_small_photo(apex_application.g_x01);
end;
Stored Procedure:
create or replace procedure "SHOW_SMALL_PHOTO"
(p_contact_image_id IN NUMBER)
is
v_mime apxt_contacts_img.mime_type%type;
v_length NUMBER;
v_filename apxt_contacts_img.filename%type;
v_lob BLOB;
begin
SELECT mime_type, lengthb(small_photo), filename, small_photo
INTO v_mime, v_length, v_filename, v_lob
FROM apxt_contacts_img
WHERE id = p_contact_image_id;
OWA_UTIL.mime_header (NVL (v_mime, 'application/octet'), FALSE);
HTP.p ('Content-length: ' || v_length);
-- needed?
--HTP.p ('Content-Disposition: attachment; filename="'||v_filename||'"');
OWA_UTIL.http_header_close;
wpg_docload.download_file (v_lob);
end;
(I'd rather not have to grant execute to public and call the stored procedure via a link.)
This way i'd only have to load the pictures of links clicked. Though this code doesn't work. I get the alert and see a bunch of those weird chars, so i presume that is the blob talking. But i'm not getting an image anywhere.
Am i missing something? Doing something wrong? I'm totally out of clues.
Instead of my existing code, i might make this work through creating another page, and juggle page items and their values around to try and get the same layout going, and then get that page through ajax?
I'm mainly trying to minimize impact (=work) on the existing app, so i wouldn't have to yet again change pages.
TL;DR: is it possible to retrieve and display an image blob from a table not in the report query, preferably through ajax?
This is Apex 4.02 on an 11g db
Thanks,
Tom
To whom it may concern, here is how i solved/worked around it:
I went with the fetch-another-page route. Maybe i was too technical or too difficult about it in my op, but in hindsight i think i could've boiled it down to:
"retrieve an image blob via ajax and display it".
So if that rings any bells for anyone, let me know.
Some rectifying too:
my images table is a child of the contacts table, as such my FK between those is images.contact_id -> contact.id
I've created a new page in my application, and put a form in based on my images table. I only display 2 items of the type 'display image' (a thumbnail and original size), and 2 hidden items, 'ID' and 'CONTACT_ID'. I've removed all that was not necessary: no buttons, no DML-process, no labels, no templates.
The automated row fetch process takes as 'primary key' my contact id, so i can call the page with contact_id in the url (so that i won't have to do an extra select to retrieve the correct id in the image table).
On the page i need the pictures, i then get the page with the photos on it when required (ie: when the detail icon is clicked and i show my popup).
Following piece of code is called within this function
(only code 'missing' here is where i call another page process to fetch me contact details in a json format)
//page 120 only holds the 2 images for a contact. Due to images being in
//blobs and no easy way to dynamically fetch them, i made a small
//form with the 2 photos on, and id + contact_id
//(contact_id made PK for the ARF-process, since this is what is worked with)
//The page is pulled in, and the photos retrieved
//htmldb_get does not do the job! It only pulls the page from cache, which isnt what i want
// arrays with the arguments and their values for the post
var vArgs = new Array();
var vVals = new Array();
vArgs.push("P120_CONTACT_ID");
vVals.push(cid);
$.post('wwv_flow.show',
{"p_request" : "NULL",
"p_flow_id" : $v('pFlowId'),
"p_flow_step_id" : "120",
"p_instance" : $v('pInstance'),
"p_arg_names" : vArgs,
"p_arg_values" : vVals},
function(data){
var oContainerSmall = $("#id_photo_container").empty(),
oSmallPhoto = $(data).find("#P120_SMALL_PHOTO").attr({"id":"id_photo",
"alt":oContact.lastname + " " + oContact.firstname}),
oLargePhoto = $(data).find("#P120_LARGE_PHOTO").attr("alt",oContact.lastname + " " + oContact.firstname);
$("#large_photo_container").empty().append(oLargePhoto);
$("#large_photo_container").css({"display": "block", "visibility": "hidden"});
//Why remove and remake the container?
//for some reason i couldn't find out, the image width and height get reset to 0 after
// an initial display of the enlarged picture and closing its dialogbox.
//I assume it is an apex+css+javascript issue.
//The only fix i was able to find was to remove the div and remake a new one.
// There have to be some properties set on the div and/or its children through
// the closing of the popup dialog (for the larger picture),
// which then prevents subsequent calls to get the correct values.
$("#large_photo_container").remove();
var oContainerLarge = $("<div></div>").attr("id","large_photo_container").css({"display":"block", "visibility":"hidden"});
oContainerLarge.append(oLargePhoto);
$("body").append(oContainerLarge);
//Hardcoded value here! Adapt when necessary
if($("#id_contact_type").val() == "Conference Room"){
var oLink = $("<a/>").attr("href", "#")
.click(function(event){
explode_headshot(event, this);
});
oContainerSmall.append(oLink.append(oSmallPhoto));
} else {
oContainerSmall.append(oSmallPhoto);
};
$("#contact_popup").dialog({modal: true,
width: 750,
resizable: false,
title: oContact.lastname + " " + oContact.firstname,
close: function(event, ui){
$("#id_photo").attr({"src": "", "alt": ""});
}});
});
I wouldn't call it ideal, but it works, and that's all i need at this time :)
I made a very similar application for showing contact details including photos a few months ago in apex.
I found this web page very useful:
http://blog.hilandco.com/2010/05/how-to-show-blob-type-column-as-image.html
Displaying an image can be as easy as creating an item of type: "display Image". Settings: " Blob column returned by sql statement".
And then an sql statement selecting the correct row:
select blob_content
from my_bitmap_table
where ID = ...