PDA

View Full Version : image scaling


pep
05-12-2004, 08:14 PM
I load images from a url given by a dataset in a view like this:


<view name="pic" datapath="mydtpt:/buddies" width="${classroot.photo_wid}" height="${classroot.photo_hei}" stretches="both" >
<attribute name="source" value="photoUrl/text()"/>

</view>

I want to scale the pic to fit in the box when I load the class:


<method event="oninit">
if(this.pic.resourceheight*this.photo_wid>this.pic.resourcewidth*this.photo_hei){
this.photo_wid=this.photo_hei*this.pic.resourcewid th/this.pic.resourceheight;
}
else{
this.photo_hei=this.photo_wid*this.pic.resourcehei ght/this.pic.resourcewidth;
}
</method>


But neither the resourceheight nor the resourcewidth attributes are reconised.

antun
05-13-2004, 08:46 AM
I think that might be a timing issue caused because the oninit event gets sent before the image loads. That's expected if you're setting the source of a view (i.e. loading an image at run-time), because the view has to init, before it can do stuff like attach a resource.

To confirm, try adding a Debug.write('oninit event sent') to your oninit method, and add another method:


<method event="onload">
Debug.write( "onload event sent" );
</method>


(onload is what gets sent when a view attaches its resource - that's when you should have access to resourcewidth and resourceheight).

If that's the case, put the logic in the onload method.

-Antun

pep
05-13-2004, 09:19 AM
I moved the above code to the load() method, and I call it with both onload and on mouseover events:

like this:

<method event="onmouseover">
debug.write('mouseover');
classroot.load();
</method>


but I still have no result (excepted the expectable debug 'mouseover' message).

So I think it is no timing issue,

antun
05-13-2004, 09:23 AM
Can you post your full code and the debugger error too?

-Antun

pep
05-13-2004, 09:39 AM
I have no debug message excepted 'mouseover'


<canvas>
<dataset src="./dat.xml" name="truc" autorequest="true" type="http"/>
<!-- a document like:
<root>
<buddy>
<name>
henri
</name>
<photo>
henri.jpg
</photo>
</buddy>
<buddy>
<name>
peter
</name>
<photo>
peter.jpg
</photo>
</buddy>
...
-->

<class name="buddythumb" extends="view" width="${this.all.width}" height="${this.all.height}">
<attribute name="photo_wid" value="40"/>
<attribute name="photo_hei" value="50"/>
<method event="oninit">
// load()
</method>
<method event="onload">
load()
</method>
<method name="load">
//then we resize the image
if(this.all.pic.resourceheight*this.photo_wid>this.all.pic.resourcewidth*this.photo_hei){
this.photo_wid=this.photo_hei*this.all.pic.resourc ewidth/this.all.pic.resourceheight;
}
else{
this.photo_hei=this.photo_wid*this.all.pic.resourc eheight/this.all.pic.resourcewidth;
}

</method>

<view name="all" height="${this.pic.height+2+this.budname.height}"
width="${Math.max(this.pic.width,this.budname.width)}">
<simplelayout axis="y" spacing="2"/>
<view name="pic" datapath="photo/text()" width="${classroot.photo_wid}" height="${classroot.photo_hei}" stretches="both" >
<method event="onload">
//classroot.load();
</method>
<method event="onmouseover">
debug.write('mouseover');
classroot.load();
</method>
<attribute name="source" value="${'../pics/'+this.data}"/>

</view>
<text name="budname" datapath="$name/text()" width="${this.getTextWidth()}"
bgcolor="0xEEEEEE" resize="true"/>
</view>
</class>
<simplelayout axis="x"/>
<buddythumb name="bt" datapath="truc:/root/buddy"/>
</canvas>


the photos are displayed but not resized.

antun
05-13-2004, 04:27 PM
I see now. Common problem. In the Laszlo events system, for any attribute that changes, an onATTRIBUTENAME event can be sent, but it won't get sent if you assign the attribute using an equals sign.

i.e.
this.photo_wid=this.photo_hei*this.pic.resourcewid th/this.pic.resourceheight;

... will not send the onphoto_wid event, so this view, which is constrained to the photo_wid attribute will not update:


<view name="pic" datapath="photo/text()"
width="${classroot.photo_wid}"
height="${classroot.photo_hei}"
stretches="both" >


You need to use the setAttribute() method to have the event get sent:


this.setAttribute("photo_wid",
this.photo_hei * this.pic.resourcewidth / this.pic.resourceheight );


PS Also, if you're going to be using <'s and >'s in <method> blocks, you should encapsulate the contents of the method block in <![CDATA[ ]]> tags.

-Antun

pep
05-13-2004, 06:20 PM
thank you very much

maritimesource
03-07-2006, 07:26 PM
I'm trying to do this as well... Assign a resource to a view at runtime, and have the image scale to within the maximum dimensions of the view.

Is all of pep's code still neccesary or does laszlo support this now?

I was looking at updateResourceSize but didn't get the results I was looking for.

Example:

<view width="100" height="100"/>

if the view source is set to an image that is 640x480 then the view would be: width="100" height="75"

but if it's a portrait image, like 480x640, then the view would be: width="75" height="100"

Thanks

rcyeager
03-08-2006, 11:41 AM
For my application at http://www.cooqy.com I have had to calculate the width/height ratios and scale the view sizes manually to retain the correct aspect ratios of the images. I'm using 3.2cr2.

I recommend peeking at the photo class within the new LZPIX application posted online yesterday http://www.openlaszlo.org/, to see how the Laszlo coders themselves manipulate images.

Turns out they used the same techniques I had to build for my own app. Hopefully one day they will bubble up their functionality into the OpenLaszlo classes, like they did with much of the LaszloMail classes appearing in the 3.2cr2 incubator directories.

maritimesource
03-08-2006, 02:46 PM
I ended up porting some code over from a java app, where I did the same thing. Here are the results, which maintain ratio, whether it's portrait or landscape:


var width = vPlayer.getAttribute('resourcewidth');
var height = vPlayer.getAttribute('resourceheight');
var scalefactor = vPlayer.getAttribute('defaultwidth') / width;

if (height > width) {
scalefactor = vPlayer.getAttribute('defaultheight') / height;
}

var scaledW = (scalefactor * width);
var scaledH = (scalefactor * height);
vPlayer.setAttribute("width", scaledW);
vPlayer.setAttribute("height", scaledH);

phillipsmn
05-03-2006, 03:36 PM
In your code above, is your dataset just returning the file name, and then you are loading the local copy of that image, or are you actually including the image in the XML and loading it as a resource (is this done by serializing?)...Basically I have an image stored in a mysql db and I use php to generate a dataset which returns the image. Unfortunately, I haven't figured out a way to load that image on a view.

Any guidance would be nice.

maritimesource
05-03-2006, 03:57 PM
in my case the server path to the image is contained within the xml. I fetch that path, then I use that in the the vPlayer.setSource method to specify the source image.

As I understand it, when using setSource once the resource is actually loaded, this method is automatically called:

<method event="onload">.....


And it's in here where I do the scaling.

phillipsmn
05-03-2006, 05:31 PM
My problem is that I need to load an image after I show a window, yet the window exists during compile time and the controls are bound -it is just not visible. Right before I show the window, I refresh the dataset using:

<method event="onclick">
/* Reload dsMembers dataset based on leaderID (so don't get all
* members in the table). Then open the submit form (which has
* the dsMembers dataset databound).
*/
var d=canvas.datasets.dsMembers;
var p=new LzParam();
p.addValue("leaderID", leaderID.getText(), true);
d.setQueryString(p);
d.doRequest();

choice_form.close();
submit_form.open();
</method>

Now, for all of my text fields (i.e. specific individuals information) they load perfectly. For the image, I get nothing. In the database (which I call using a PHP script) the image path is set as "/images/picture.jpg"

I am having trouble loading the image.

The refresh is necessary because I am showing the form after a login. After I get the username and verify authenticity, I then refresh the dataset (passing the username) to get the specific info (see above).

Can anyone help me with the image issue? I've tried a number of ways, and still come up short.

maritimesource
05-03-2006, 06:19 PM
Is the window bound to the dataset that supposed to contain the image? If so, checkout the "ondata" method. In that method all of your data should be readily available, and from there you can call setSource and resize...

phillipsmn
05-03-2006, 06:40 PM
<!-- Define the choice form -->
<window name="choice_form" id="choiceID" visible="false" width="500" height="500" x="50" y="50">

<view name="header" datapath="dsLeader:/userinfo/user" visible="true">
<!-- Header area -->
<image resource="/images/person.jpg" width="100" height="100" x="50" y="50"/>


<text id="groupID" datapath="@groupname" width="175" height ="20" fontsize="10" x="170" y="50"/>
<text datapath="@address" width="150" height="50" x="170" y="100" multiline="true"
fontsize="10" fontstyle="plain"/>
<text datapath="@leaderID" visible="false" id="leaderID"/>
<image resource="logo" width="100" height="50" x="350" y="50"/>
</view>
<!-- Button section -->
<image resource="data" x="50" y="210"/>
<button name="submit" x="110" y="220" width="60">Submit
<method event="onclick">
/* Reload dsMembers dataset based on leaderID (so don't get all
* members in the table). Then open the submit form (which has
* the dsMembers dataset databound).
*/
var d=canvas.datasets.dsMembers;
var p=new LzParam();
p.addValue("leaderID", leaderID.getText(), true);
d.setQueryString(p);
d.doRequest();

choice_form.close();
submit_form.open();
</method>
</button>
<image resource="reports" x="50" y="260"/>
<button name="reports" x="110" y="270" width="60">Reports
<method name="onclick">

</method>
</button>
<button name="quit" x="400" y="400" width="60" onclick="doQuit();">Quit</button>


</window>

Above is my code for the window. Very simple. It is the image that I want to delay the loading until I have the leaderID (see my previous post). Once I have the leaderID, as I posted before, I refresh the dataset (that the window's components are bound to) and then show the window. Unfortunately, because the window exists, but is hidden, it connects to the dataset at compile time, before I get the leaderID (from my authentication routine) and that is why I have to do the refresh before showing the window. It's just that I can't figure out how to bind the image source to the @picture path of the dataset. I've tried a number of things and although the text works, the image doesn't.

guyr
08-01-2006, 12:05 PM
Laszlo newbie. I'm having trouble getting image scaling to work in a gridcolumn. I have a resource defined like this:

<resource name="normal" src="../img/circle-normal.jpg"/>

The grid column is defined like this:
<gridcolumn sortable="false" resizable="false">Normal
<image resource="$path{'normal/text()'}" width="5" height="5"/>
</gridcolumn>

Confusing naming, I realize, but normal/text() pulls from a dataset with a value "normal", which then selects the corresponding resource. That part all works. But the image does not scale; it shows the same size as the source image, cut in half horizontally because that is all that will fit. I've tried png, jpg and gif; all display fine, but none scale. I tried adding stretches="none", but Laszlo rejected "none" as an invalid value.

I'd appreciate if anyone knows why these images won't scale. Thanks.

maritimesource
08-01-2006, 12:12 PM
Try:

stretches="both"

From the reference docs:
setting stretches causes a view to change its coordinate space so that everything it contains (resources and other views) fit exactly into the view's width and/or height. The default for this property is "none". This is used to resize a view's contents by setting its width and/or height.

guyr
08-02-2006, 11:39 AM
I tried stretches="both". It doesn't just cut the image in half like before. However, it does what I thought it would do: it distorts the circle (the image I'm displaying) so that it fills the allotted space of the grid cell, resulting in an elliptical shape. But then it does something I didn't expect: when I scroll those ellipes off screen and then back on screen, they are now circles of the correct shape and size.

Perhaps this would be addressed by modifying the basegrid component to eliminate lazy write as suggested in the other thread. But now that I've generated images of the proper size, I'll just stick with those. Thanks.