
I've seen a few discussions like "Where's my Image file when I publish my dashboard?" or similar. It might be related to someone having put the image in a Favorites folder in the BO Platform or forgetting to migrate it up in whatever folder it's in, or likewise in the SE80 MIME Repo on the NetWeaver side.
What a pain, I say. Images should be a simple thing to deal with. I lamented about this in a recent document with a workaround of Base-64 encoding the URI of the Image.
How to embed images inside of a Design Studio App without uploading to server.
This works, still, but I wanted to make it easier without leaving Design Studio to go off and Base-64 encode an Image and then copy and paste it back into Design Studio. So I made (gasp) an SDK Component to do it for us. I called it 'SuperImage' but in hindsight, maybe 'SimpleImage' is more accurate, as this is the smallest snippet of SDK code that was needed. I decided to again use the SAPUI5 handler to get this done. Here's the component.js in its entirety. You can see that it's more comments than code.
sap.ui.commons.Image.extend("com.sample.superimage.SuperImage", {
renderer : {},
metadata : { // Not to be confused with the Data Source metadata property
properties : {
onclick : "string" // While 'onclick' is technically a DS Event, it does pass some information, so let's take it.
}
},
initDesignStudio : function() {
// Called by sap.designstudio.sdkui5.Handler (sdkui5_handler.js)
},
// Override onclick setter to then attach/detach Design Studio event raising.
setOnclick : function(s){
/*
* Geeking out for a moment:
*
* Conjecture, but the string that is passed appears to be a supporting JS command string.
*
* Example:
* sap.zen.request.zenSendCommandArrayWoEventWZenPVT([['GUID','1',0],['BI_COMMAND_TYPE','ABSTRACT',0]]);
*
* This Command Array is ultimately passed to object 'sapbi_page' to so some server-side processing with.
* The actual 'sap.zen.request.zenSendCommandArrayWoEventWZenPVT' should only be actually evaluated when the event is raised (on click).
*
* Those who enjoy picking through code can find this function call also on line 74 of 'sdkui5_handler.js' as well as other places
* It also looks like it supports some sort of undocumented or yet-unimplemented SDK funclet thing...
* The function itself is defined in 'bi_command_util.js' which is contained in 'com.sap.ip.bi.zen.rt.framework_12.0.2.201311041742.jar'
*
* Long story short, let's not eval it in the setter, and leave it alone. But, let's see if there's any value so we can
* attach or detach an event listener (so we get a proper mouse cursor)
*
* PS. Anyone having BEx WAD 7.0 flashbacks with references to 'sapbi_page' references? 😉
*
*/
if(s && s != ""){ // If there's onclick BIAL, then add an event listener (and get a hand cursor).
this.attachPress(this.clickHandler);
}else{ // If not, remove the event listener (which will get rid of the hand cursor, too)
this.detachPress(this.clickHandler);
}
},
clickHandler : function(){
this.fireDesignStudioEvent("onclick");
}
});
(Most people won't care about the onclick commentary, but I found it interesting). Moving on, the real magic happens in the additional_properties_sheet.js. Using no server upload, I do all this within the JavaScript layer by using the FileReader API (FileReader - Web API Interfaces | MDN).
sap.designstudio.sdk.PropertyPage.subclass("com.sample.superimage.SuperImagePropertyPage", function() {
var that = this;
this._src = "";
this.init = function() {
var that = this;
$("#imageFile").change(function(e) {
var input = e.target;
if ( input.files && input.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
that._src = e.target.result;
that.updateImage();
that.firePropertiesChanged(["src"]);
};
FR.readAsDataURL( input.files[0] );
}else{
alert("A problem occured reading the file.");
}
});
if (window.File && window.FileReader) { /* Good to go... */ } else { // Display warning for pre-IE10 versions.
alert('File APIs are not supported in this browser. You probably need to be at IE10 or higher.');
}
};
this.updateImage = function(){
// Compute dimensions for image description snippet.
var i = new Image();
i.onload = function(){
var w = i.width;
var h = i.height;
var imgDesc = w + " x" + h + " ("+i.src.length+" bytes)";
$('#imgInfo').text(imgDesc);
$('#base64').text(i.src);
};
i.src = that._src;
$('#img').attr( "src", that._src );
};
this.src = function(value){
if( value === undefined){
return this._src;
}else{
this._src = value;
this.updateImage();
return this;
}
};
});
So what does the component do at runtime? Let's start and see:
Start by dragging in the component, and be greeted with a placeholder image:
Let's change the image by clicking on the Browse button and then selecting a local file:
We can see that the image instantly changes (and has auto width and height, as a bonus). You can then resize the image just like any other component, if you wish.
But what about reuse? Hosted Image URLs can be referenced multiple times at no additional size costs. If we were to copy this image over and over, yes the image data is copied. For small iconography, who cares, but for larger backgrounds such as the one above, this could be a performance hit. How to overcome? One option would be to yes, host the dang image file, or..... use the scripting layer to copy image sources between images. Provided with the source code is a full example, but for now, a snippet of the BIAL along with a short animation of the end-result:
Example at run-time showing image data re-use (Click image not animating):
Full source and example app is in the attached .zip (remove the .txt after downloading)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
10 | |
7 | |
7 | |
7 | |
6 | |
5 | |
5 | |
4 | |
4 | |
4 |