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) ;
}
function extractTextFromPDF() {
// PDF File URL
// You can also pull PDFs from Google Drive
// this Fall2019_LLFullCatalog.pdf will not insert - internal error on insert is all the feedback that gets logged"
// doesn't matter if I retrieve it from the university website or if I first copy it to my google drive and then retrieve it from there
//var url = "https://uwf.edu/media/university-of-west-florida/offices/continuing-ed/leisure-learning/docs/Fall2019_LLFullCatalog.pdf";
//var url = "https://drive.google.com/drive/u/0/my-drive/Fall2019_LLFullCatalog.pdf";
// both of these pdfs will insert just fine. Size is not the issue because this one is much larger than the one I need to insert
var url = "https://eloquentjavascript.net/Eloquent_JavaScript_small.pdf";
//var url = "https://img.labnol.org/files/Most-Useful-Websites.pdf";
var blob = UrlFetchApp.fetch(url).getBlob();
var size = blob.getBytes().length;
var resource = {
title: blob.getName(),
mimeType: blob.getContentType()
};
// Enable the Advanced Drive API Service
var file = Drive.Files.insert(resource, blob, {ocr: true, ocrLanguage: "en"});
// Extract Text from PDF file
var doc = DocumentApp.openById(file.id);
var text = doc.getBody().getText();
return text;
}
See comments in code above that describe the problem.
The PDF that I need to insert with OCR is not working - regardless of whether I retrieve it from the original site or retrieve a copy that I put on google drive. However, two other PDF urls will insert just fine and one of them is considerably larger than the one that fails.
What else could be the issue, if not size limitation?
Thanks,
Steve
It could very well be a bug in the Chrome API. Not all PDF software is created equal, check if the PDF can be read in Adobe Acrobat as a simple test.
I have an image saved in my Google drive called "logo.png".
I want to add the image to a Google document so that it's in the top left corner and so that it does not distort the text around it. (In other words, I want the text to "wrap" around the image).
How do I add an image to a Google Doc using Google Script so that surrounding text wraps around the image?
My script so far:
function myFunction(e) {
var t1 = 'Center for Success';
var t2 = 'Foundational Hall';
var t3 = 'Instruction Sheet for Testing Requirements';
var boldRight ={};
boldRight[DocumentApp.Attribute.BOLD]=true;
boldRight[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT]=DocumentApp.HorizontalAlignment.RIGHT;
var boldCenterUnderline ={};
boldCenterUnderline[DocumentApp.Attribute.BOLD]=true;
boldCenterUnderline[DocumentApp.Attribute.UNDERLINE]=true;
boldCenterUnderline[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT]=DocumentApp.HorizontalAlignment.CENTER;
var filename = 'fileTest';
var doc = DocumentApp.create(filename);
var body = doc.getBody();
body.appendParagraph(t1).setAttributes(boldRight);
body.appendParagraph(t2).setAttributes(boldRight);
body.appendParagraph(space);
body.appendParagraph(t3).setAttributes(boldCenterUnderline);
doc.saveAndClose();
}
Desired Result:
I saw here that an image can be added in various ways, but neither approach has worked for me AND I do not see how I can control a wrapping attribute.
Update
I tried using the following code (with fake ID shown in URL), but it just created a blank document:
var image = "https://drive.google.com/open?id=2PJGK5C64HLKKoQIv52jGhUjjdiXU34Mp";
var fileID = image.match(/[\w\_\-]{25,}/).toString();
var blob = DriveApp.getFileById(fileID).getBlob();
body.appendImage(blob)
I have google spreadsheet with direct links to images (jpg and png):
https://docs.google.com/spreadsheet/ccc?key=0AoPGWppcjtzhdDh6MW1QNVJhSHlwVTlfRnRtd0pvNGc&usp=sharing
I want to increase rows heights starting from "2nd row" to 100px and render images there.
It's possible to do via Find&Replace:
Find jpg and Replace to jpg", 1)
Find http://img and Replace to =image("http://img)
Select rows and Scale them
and the same for png image-urls.
Watch this screencast http://www.screenr.com/S0RH
Is it possible to automate it via script? I think - YES! It have to be pretty simple but I googled a lot but haven't found the solution. I can't do it myself as don't know coding. Will anyone help and make this script?
A function to do what you ask is simple, if you have a basic understanding of the language (Javascript), know how to use the development environment, and read the API documentation.
For example, see this script. It's been added to your shared spreadsheet, so you can also view it (and run it) in the script editor there.
/**
* Scan column A, looking for images that have been inserted using
* =image() function. For any row with an image, set the row height
* to 100 pixels.
*/
function resizeImageRows() {
var sheet = SpreadsheetApp.getActiveSheet(); // Get a handle on the sheet
var HEADERS = 1; // Number of header rows at top
var firstRow = HEADERS + 1; // First row with data
var lastRow = sheet.getLastRow(); // Last row with data
var imageRange = sheet.getRange(1, 1, lastRow, 1); // Column A
// Get all formulas from Column A, without Headers
var formulas = imageRange.getFormulas().slice(HEADERS);
// Look for image() formulas, and set the row height.
for (var i = 0; i< formulas.length; i++) {
if (formulas[i][0].indexOf('image') !== -1) {
sheet.setRowHeight(i+firstRow, 100); // Set height to 100 pixels
}
}
}
You can absolutely do this with the find and replace function under the edit menu, just make sure you click "search in formulas" and it will find and replace in the formula.
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 = ...