picture size limit to define
Nine1724
Joined: 2002-12-22
Posts: 67 |
Posted: Sat, 2004-12-25 13:25 |
Is there in G2 also an option to limit the picture size like in G1? I dind't find anythin in the Alphy 4 release. Simon |
|
Posts: 314
not yet as far as I know Desparately waiting!
Posts: 67
so, to all developer: please don't forget ;-)
Posts: 3236
The best way to make sure they don't forget is by adding an RFE, though it has been said that they plan on releasing G2 with nearly all or all the features of G1. So its probably that this feature simply hasn't made it in yet.
Posts: 8601
I added this task
Posts: 8601
virshu has volunteered to work on this feature.. thanks, virshu! I'll help out by providing design and technical guidance...
virshu, let's start with creating a new module.. we can merge into core later if we decide that's where it belongs. So start with a new module.inc that registers a new ItemEditAlbumOption (see randomhighlight/module.inc). The ItemEditOption should offer controls for:
The option can save these settings in the PluginParameterMap (using the itemId of the album).
I'll provide more detail later on the next steps (event handler so that new albums will inherit the settings from its parent, and itemaddoption to apply the settings to newly uploaded images).[/]
Posts: 314
OK, here is the first draft. I can fiddle with JavaScript to enable/disable text fields based on the radio button; but it looks like it does the job. I need some advice on the next steps that you described....
Posts: 8601
wow virshu, fast work
looks good so far.. my comments/questions:
Next step: event handler so new albums inherit settings from parent.
Finally, make it happen: take a look at exif ExifDescriptionOption.inc.. you'll want an ItemAddOption like this (with no UI, ie empty template). When your ItemAddOption is called then load the sizelimit prefs for the parent album and apply them to the newly added image (make sure it's a GalleryPhotoItem).[/]
[/]
Posts: 314
mindlessThanks for nice words... it has been 10 years since I earned a living as a programmer; maybe it's time to go back 8)
Anyway, here are some answers.
"default" means "take it from the parent album". This would allow me to set these values in root album, and it will apply in all albums (or in top user album - you get the point)...
I certainly intended to maintain the ratio (first, because I know about the square derivative; second because I always want to maintain the ratio). So, if there is 800 in one (or both) fields, it means that the largest side will not exceed 800 pixels. I think that's how G1 works (it only has one field, anyway). I don't know how to make it clear... hopefully, somebody with better UI skills can help!
Because I cut'n'pasted from G1 screen
If you say so :wink: I'll test and remove it...
Sure.
I need to understand the "next steps a little bit better. Let me play with it; but I'll probably bug you for help :-?
Posts: 314
as far as isAppropriate() is concerned, I think it is not appropriate to remove it... The call falls back to ItemEdit:isAppropriate which returns false, and the snippet doesn't come up...
Posts: 8601
"default" -- I'm thinking we'll copy the settings at the time new albums are created (as I described in next steps), so you wouldn't need this default setting. does this sound better? it will avoid having to search up the tree to find an album with a setting defined, and maybe avoid confusion where changing one album affects other albums.
isAppropriate -- i didn't mean remove it, just to always return true.
Posts: 314
I was just thinking about two approaches to "default" implementation ('traverse' and 'copy')... I think both approaches have some pros and cons... 'Traverse' is more dynamic - which may be good or confusing. Would 'copy' be consistent with other components in the gallery? That sure would tip the scale!
my biggest concern with 'copy' approach is applying these settings to existing albums; specifically, migrated from G1. Do you think, it will be possible to apply the settings from G1 during migrations (in other words, do you think, jmullan could retrofit the migration module to carry this setting over?)
In short, I am not married to one approach over another... If you feel that copying is better - so be it (it sure is easier to implement )
I got so far as to handleRequestAfterAdd. But I have no idea how different toolkits actually do the conversion... OK, tomorrow!
Posts: 8601
yeah, other things copy which is why i started with that approach in mind.. permissions copy when a new item is created. album settings like layout/theme also copy to new albums, but they also offer "default" as a choice.. default in this case means use the site-wide default defined in site admin, not to look up the parent chain to find a setting. so, i think we should use the copy method, and possibly offer a default defined in site admin if desired.
for toolkit stuff you'll want to look at core/ItemEditRotateAndScalePhoto.inc. it does stuff with preferred derivatives and also can perform an operation and replace the original file.. you'll be doing both those things based on the checkbox selection.. the particular toolkit operation to use is "resize" which is the one that can take 2 dimensions. we'll have to add a new operation for file size.. i can help with that once you get size-to-dimensions working.
Posts: 8601
ok, here's one idea for the dimensions UI.. try it out
what do you think? it copies the width val to height after a delay.. but if you change the height to be different then it won't overwrite when you change the width.
Posts: 8601
ok, i just committed the code so you can put {g->dimensions formVar="varname"} in your template and you'll get form inputs for width/height like in my test file above.. when the form is submitted you'll get varname[width] and varname[height] in the post data.
Posts: 314
I like "copy" with site-wide deault the best (if you remember, that was my original implementation of "new items" as well). Anyway, I'll do "copy" for now; it won't be a big deal to add site-wide default later. Moreover, my original concern about migration isn't relevant - now that I am thinking clearly. If we subclass addAlbum functionality, then I can set up the preferences for the root (or other parent) album, and these settings will be copied to the migrated album automatically, right?
I love the dimension UI implementation... Can I take it as is? Who do I need to credit/thank/bribe?... Oh, never mind - I just read your latest message. I think there is a delay for anonymous checkout, right? which module should I be looking for specific version?
I'll play with toolkit operations today and tomorrow (my teenage son took my car; can't go anywhere anyway :roll: ) I will probably have questions after that.
Somewhat off-topic: it seems that ItemEditOption:IsAppropriate and ItemAddOption:IsAppropriate are implemented very differently. ItemAdd is static function that doesn't have access to the $item... I could really use it! Is that by design or by accident 8)
Alright; back to work now!
Posts: 8601
"copy" stuff -- sounds good.
migration -- you've got it right.. you just have to remember to make the settings before your migration!
dimensions -- i wrote that little thing.. when you get modules/core/templates/Dimensions.tpl in your cvs update then you've got it.
isAppropriate -- ah, think about ItemAdd.. isAppropriate is called before showing the add-items page.. ie, you don't have the $item yet! You have to examine $item afterAdd to see if it applies to your operation, and just return if it doesn't.
Posts: 314
Here is the code or the easy stuff (that is, without actual conversion... And I don't have the new template yet...
Just to clarify - I am planning to maintain the ratio (if I figure out how) - that is, if the values are 800x800 - it means that neither of the sides will exceed 800 pixels; not that my 3264x2448 rectangle will become 800x800 square (it will become 800x600, maintaining the ratio).
Also, I just realized something... when I have "default" sort order in subalbum - it means the global setting; not the parent album! I thought the opposite - that sort order traverses to the parents, and only if all the parents are "default" - it will go to the global setting. OK, my bad. That solves "traverse" vs. "copy" dilemma (at least in my mind). So, at some point it would be nice to set these global settings...
Posts: 8601
i just finished up supporting both width and height bounds for resizes..so you have some more code to work from.
you don't need to do anything special to maintain the image aspect ratio.. the "resize" operation the G2 toolkits support already does that.. so if you create a derivative with operation = 'resize|800,800' it will fit the image to an 800x800 bounding box, but maintain aspect ratio as you described.
Posts: 314
awesome! I was already panicking a little :cry: I think I am pretty much on my way for dimensions. The only remaining thought... if you specify 600x800 ('portrait'), and the picture is 1024x780 (landscape) will resize understand? or it will force 1024 into 600? Well, once it works - I can try, of course!
As far as filesizes... I remember in G1 it was like "trying 95% - size nnn; too much. trying 90% - size mmm. OK" Is this how it should be done?
Posts: 8601
i don't know how to get a desired file size.. i suppose we should go with the G1 method.
will i see some unit tests in your next code? (hint, hint..)
Posts: 314
OOOHHH! It's my 100th message! I am an artiste now! Exciting![/]
Posts: 32509
@4. sadly no. the simplest way to learn how to write these unit tests is to copy the style of the already existing unit tests. write done the specification of your module / what you expect from it (if the state of G2 is x and the input is y the output is z. first bring G2 into state x, then apply y and check if z is the expected response (new G2 state, output).
i'm developing a VLSI chip these days and we have almost the same testing / verification method.
first design the architecture, then write parallel the architecture and a testbench to test the architecture, create stimuli and expected response, apply the stimuli to the architecture and the golden model and check if the actual response is the expected response
Posts: 8601
1. good point.. i'll make the dimensions change in that view too.
note that {g->dimensions} now also takes width= and height= parameters for the initial values to place in the input boxes.
Posts: 314
Here is the module that maintains the settings, changes the dimensions, uses the new g->dimension, and generally is kick-ass code! 8)
However, it doesn't apply the filesize limits. Instead, it uncovers some deficiencies in the core libraries (or so it seems to me). The operations in graphic toolkits don't have any operation to "compress" the image. In GD it would eventually lead to imagecopyresampled(). Note that there is a wrapper to the function; but there is no interface to the wrapper. Similar in NetPBM.
I feel comfortable (or arrogant) to start messing around with the core... I am not sure that mindless or baschny are comfortable :wink:
Any comments/suggestions?
Posts: 314
One other question/problem/enhancement request:
Is it possible to pass it "disabled"? If the current value is missing then I enable "none" and disable the text fields. Then I have some JavaScript that responds to clicks and toggles the fields. The toggling part works; but the initial state is always enabled...
Thanks
Posts: 8601
hmm.. rather than adding an option to g->dimension how about you just write javascript in your page to disable/enable... the id of the text fields will be the value you pass for formVar (for the width field) and the same string with _h on the end for the height field.
good point on the filesize setting.. this will require a new toolkit operation.
Posts: 314
I have javascript to disable/enable on click (that is, when the user switches between "none" and "explicit" radio buttons). But I can't see the way to set the initial state (it's either in the field, or "body onload=" - I don't know any other way...
Posts: 8601
sorry, when you said above "the initial state is always enabled" I thought you meant that's what you wanted. i can add a param to disable if you want.. otherwise just do <script ..> document.getElementById(..).enabled = false; </script> or whatever the javascript is...
Posts: 314
done... I forgot about this way :oops:
let me know what you decide about the toolkit!
Posts: 8601
how about i add the toolkit operation while you add unit tests for your module? find other ItemAddOption and ItemEditOption tests to copy from to get started.. perhaps you could also add the site admin view for setting the site default?
Posts: 8601
try setting "no limit" for both settings and then adding a photo to the album.. i get an error.
Posts: 314
It's unfair!!! :evil: Oh, well - that's what an apprentice gotta go through to reach the pantheon :lol:
eeeh... I didn't. What kind of error?
Posts: 8601
haha.. but don't forget the toolkit changes will have unit tests too.. not like i'm getting off easy. though after 9000 lines of unit tests, they do get easier to write.
Posts: 314
Ok, I feel muche better now :P But seriously, though - I can't figure even how to run those numerous tests (except the Test Harness in lib/tools/test - which are not the ones that I am looking for); let alone how to write them... Is there a common front end to start the test - some index.php that I am missing?
I think I read some Wiki about it... I'll try to search; but if you can point me - I'd appreciate!
Thx
Oh, I just noticed that setting same sizes actually makes an ugly square out of the picture - and doesn't maintain the ratio! Either I am doing something wrong, or I'll need to calculate the proportions and not to rely on toolkit to "fit it" into the bounding rectangle
BTW - you saw the bug report about small pictures?
Posts: 8601
oh, sorry! lib/tools/phpunit/index.php is what you're looking for. you can enter sizelimit in the filter box to run just your tests (once you start writing them).
create modules/sizelimit/test/phpunit directory and put *.class files in there for your tests. each *.class can have a setUp() function to create any test data used in the tests and tearDown() to do any needed cleanup. each test is a function with the name starting with "test".
try copying modules/randomhighlight/test/phpunit/RandomHighlightOptionTest.class to start out your ItemEditOption test. you'll see how it calls handleRequestAfterEdit with various inputs.. and the basic checks are $this->assert(boolean, message) and $this->assertEquals(expectedval, actualval, message). you'll have more checks than this class because your form has more than a single checkbox. also don't put too many tests in a single test* function.. for example, tests for error conditions (user enters a blank or negative width/height/size) is usually a separate test from testing valid conditions.
i hadn't seen the bug report, but i'll take a look. i'll also test Gd with resize operation.. using imagemagick it seems the aspect ratio is maintained.. Gd should do the same.
Posts: 8601
ack! imagemagick is the only toolkit that maintains aspect ratio for resize operation.. grumble, grumble... erg. i think i'll have scale take an optional 2nd parameter instead.
Posts: 8601
ok, changed the operation to scale.
also added the compress operation to all 3 toolkits.
you should code your module to check for toolkit support of the compress operation.. if there aren't any then don't show the filesize controls.. if there is support you can customize the message for which file types will work.. maybe get the mime types and strip "image/" off the front of each and show the list. Right now imagemagick supports jpeg and png, netpbm is jpeg and pjpeg and gd is just jpeg.
Posts: 314
mindless, I spent last day or two building the testcases; and it was going well pretty dandy. I did run into a problem, though - that I am completely baffled... In the tests ("don't keep original") item->rescan is calling filesize that is returning old filesize even though the file has changed... I even deleted the file, and I am still getting the old (large) size. So, either the file wasn't closed, or handle got stuck, or something like that. I would blame Windows, Apache, or PHP5 except that the real thing returns the correct size. The attachment doesn't have the sample picture; you can use any large file, or download mine (that has the right name and resulting size) from here
I am gone for the year :-? I'll try again tomorrow
Posts: 314
Here is the culprit:
will return the same number twice despite the fact that the second time is obviously smaller...
Posts: 8601
check php docs for clearstatcache().. that may help.
happy new year!
Posts: 314
Real men don't read manuals :evil: Which caused me better part of New Year's eve of wasted time and frustration :oops:
Posts: 314
here is a big step forward (small step for mankind, but a giant leap for this man). The attached code compresses both for dimensions and filesize; it includes testcases for a lot of scenarios (I think I overdid it a little bit - but hey, you can never be rich).
I only tested it on GD and JPEG. I need to deal with special cases. I was thinking where to put the warning messages. Seems, the most natural place is the summary page (ItemAddConfirmation), but I would need to bite into core.
mindless, I also ran into a problem (fix it - or I'll open a bug 8) ) : GDFunctionality::imageJpeg has to take third parameter for jpegQuality... I was kinda curious why my resized files are always the same size (trying 95% - 1234KB; trying 20% - same 1234KB).
One other thought... Since all three supported toolkits now support "compress" it's difficult to test for absence of such support, as you suggested. The only situation that I can think of is when somebody has the older version of the toolkit - but this can be easier solved through version dependencies (although I didn't figure out how to do it yet :oops:
Posts: 314
I noticed one other thing that I would like to change... I see that ItemAdd expects plugins to return status among other things:
However, the plugins (ItemAddFromBrowser, ItemAddFromServer, ItemAddFromWeb) don't allow options to return status, but only errors:
list ($ret, $optionErrors) = $option->handleRequestAfterAdd($form, $newItem);
I think I could use status to show warnings in the ItemAddConfirmation screen. So, how about something like this:Whadayathink?
Posts: 7994
Mindless is going to be really busy for a while (his wife just had their first baby!) so I'm going to pick this one up.
The ItemAddOptions are only as sophisticated as they needed to be to complete the tasks I originally created them for. Let's make them better. I just committed a fix so that you can now return warnings from ItemAddOptions and they will be passed through to the ItemAddConfirmation page, so that should keep you moving along.
I fixed the GDFunctionality::imageJpeg issue, so that should be working fine for you now.
I'll review your code ASAP!
Posts: 314
One other observation... Per mindless advice I started reading the manual, and I think the way we are compressing the pictures (95, 50, 75, 62, etc.) is not appropriate for IM+PNG situation:
So, if I am reading it correctly, the two digits are evaluated independently. The tens affects the size (at the expense of de-compressions peed; not quality like in JPEG) and the singles define filter-type (which I have no clue about). But if the goal is to target certain size - we must treat the quality for PNGs differently...
Posts: 314
I see warnings in ItemAdd... I can't believe it :o Making fixes at a speed of light :lol:
Anyway, here is the code. It does pretty much all that I was set out to do (unless I forgot something). The size of PNG file is kinda unpredictable (see my note above), other than that it rocks!
I have some questions about unit tests; but I don't want to be a spoiler for myself 8)
Posts: 7994
Ok! I found some time to review this. In general, it looks like good work. I think that you've covered most of the cases that need covering. However, in order to get it into the codebase there are a lot of things (big and small) that need to be fixed up. The list is long, but for the most part it's pretty cosmetic stuff that won't take you too long to resolve. Since this list is so long, we should do another round or two of reviews after you fix all this stuff because I'll probably find more issues (it's hard sometimes to find all of the issues when there are a lot of little things).
This is pretty standard for a first round submission of code to G2. I'm being very, very stringent about this code base As is usual for me with the first round, I haven't tried to run the code yet -- I've only done a full read through. Next round I'll start playing with the functionality.
----------
General comments:
- use /* */ instead of // comment style
- use longer variable names instead of abbreviating (dimensionNone
instead of dimNone, etc)
- your tests look fairly complete and seem to cover the appropriate
cases -- good work!
SetSizeOption.inc:
- I changed it so that you can return a null template for loadTemplate
and it won't load anything, so you can get rid of Empty.tpl
- The underscore in Sizelimit_helper::_applyLimits and _buildDerivativeWithLimits
implies that they are private methods, so you should not be calling them from outside
the helper class, unless you want to make them public and remove the underscore.
- You don't check the error result from either of those calls (4 places)
- "x >> 10" is fine, but please add a comment explaining what it means
SizeLimitOptionTest.class:
- testTrivial() is unnecessary (unless I'm missing something)
- testNone() - form variables like 'rbDim' and 'rbSize' are unnecessarily
short -- why not just spell out what they mean, like radioButtonDimension
and radioButtonSize. When we spell it out that way, is it really necessary
for the code to know that these are from radio buttons? maybe dimensionChoice
and sizeChoice might be more appropriate names.
- avoid using print_r(..., true) because it requires PHP 4.3.0. For
assertEquals() you don't need to print out the result; it will do
it for you (and tell you where they differ).
- line 80: put spaces around => in array assignments
- testDimWidth() it's easier to do:
$this->assertEquals(array('x' => 1024, 'y' => 1024, 'keepOriginal' => 0), $params);
because assertEquals will display them nicely and tell you exactly what's different
- use single quotes instead of double quotes around any strings that don't
contain variables or control characters (\n, \r, etc) so that PHP doesn't
bother trying to do variable expansion
- the last few things are repeated in all of your tests
SizeLimitOption.inc:
- You should be storing your data in $SizeLimitOption not $SizeOptions; that way
your namespace matches your class name (and you won't conflict with another
class's template variables)
- handleRequestAfterEdit(): your GalleryCoreApi::xxxPluginParameter calls don't
check the return code
- in form[error][sizelimit][size][invalid], the convention is that the [size] part
matches the name of the form variable (so in this case it should be [rbSize]).
See my general comment about variable naming
- the form should be form[SizeLimitOption] to maintain namespacing (see my
comment above)
- <dimNone vs. dimYes> and <sizeNone vs. sizeYes> -- these don't really speak
to me. It's already in form[sizelimit][rbDim] so you don't really need the
dim prefix. For example, how about:
form[SizeLimitOption][dimension][unlimited]
form[SizeLimitOption][dimension][limited]
these make more sense to me.
SetSizeLimitOption.tpl:
- our templates are indented in steps of 2, so for example it should be:
- all of your Javascript functions should have your namespace; remember that
you're potentially sharing a page with other Javacsript. Eg:
SetSizeLimitOption_toggleXY
- You can't count on document.forms[0].elements['g2_dims[width]'] because
we may not be using g2_ as our form prefix in all cases. You can use the
{g->formVar} there also, but you're really better off using a namespaced id
instead, so your input would be:
<input id="SetSizeLimitOption_foo">
and your Javascript would be:
document.getElementById("SetSizeLimitOption_foo")
look at WatermarkOption.tpl to see a clean way to do this
- "No Limits" and "Keep original image?" are not in {g->text} blocks
AddPhotoOptionTest.class
- Laima.jpg appears not to be part of the tarball. Is it required?
- tearDown(): You should not need to remove the item specific plugin
parameters; the framework will take care of that for you
- 112, 146, etc.: the assertEquals should be in the comment (ie, have a "* " prefix)
- 141, 187: youdon't check the return status on rebuildCache()
Empty.tpl:
- no longer required (see comment above)
module.inc:
- should be a blank line between performFactoryRegistrations() and handleEvent()
- 100: should be indented under the left paren
- in handleEvent() if it's not a save, you return a $ret->wrap() but you have
no ret. I prefer to structure it like this:
Sizelimit_helper:
- this code looks very familiar Once your stuff is in and tested
we should consider refactoring this and the ItemEditRotateAndScalePhotoPlugin
code together in some fashion so that we don't have excess duplication.
- line 33 is missing a semicolon -- PHP should barf on this
- This class should be renamed to SizeLimitHelper in accordance with our
naming convention
- the function should have phpdoc
- 54: if you use $gallery->i18n() you're saying that you're returning an
internationalized string that will be localized later. However, I believe
that we pass those warnings directly out to the browser so it must be
localized at this time. You need to load the sizelimit module and then
call $module->translate() on your string before returning it.
- I don't see any tests for this code. You can probably adapt the ones from
ItemEditRotateAndScalePhotoPluginTest to get yourself started, though...
Posts: 314
Wow, Bharat - that's amazing! Thank you for your comments. And you are in California, too - right? so, my 3:15am is your 3:15am. Wow, indeed!
And the most annoying part - is that I can't find anything on what to push back :oops: - that's so unfair :x
Oh, I found two things to push back (not much of vindication, but still):
It's too large to put in the Forum (it limits to something like 300K); it's here There will be another file there - for PNG testing
This is a new construct - {g->dimensions} and I don't think it accepts id in the same way as <input> does... This was the only way that I could figure out how to refer to.
As far as the other comments - I think I took care of them all. Please take a second look!
I will start remaining testcases later tonight. I have a question, though - how to write testcases that hook into GalleryEntity:save event. module.inc subclasses GalleryModule class, but how should it be reflected in the unit test?
Posts: 7994
That is a terrible API! But what can ya do. We can extend the imagemagick module to have a separate compression and filter settings for PNG, but nobody is going to take the time to figure out what's the right filter to use. I changed it for now to hardcode the filter to "adaptive" for PNGs, but retain the compression setting.
Later on if we want to do it right we can let users specify both settings...
Posts: 7994
Wow that was a fast turnaround! I thought I had at least a day to rest in between :-o
Ah, I see that I missed something in my review (probably missed a lot, but we'll do more reviews). In AddPhotoOptionTest you're using an actual JPG and doing operations on it. That's good, but it's not really necessary. It's more important to verify that the right commands are being executed than it is to actually execute them so there's no real need for an actual image. Instead a better approach is to create a mock GalleryPlatform instance and have it respond correctly as if the JPG or PNG that you require actually existed. Ie, if you ask $platform->filesize("Laima.jpg") it returns 300K (or whatever the right answer is). This is a very effective approach because it lets you simulate any environment that you want. (sidebar: the imagemagick module uses these mock platforms to simulate testing on 6+ different ImageMagick environments, even though none of them may actually be installed).
It doesn't accept ids, but it uses the form var as the id so you should be able to do it. I only read through Dimensions.tpl, didn't look through the HTML so you'll probably have to tinker a bit.
The easiest way to test it is to hand craft an event and call SizeLimitModule::handleEvent() by hand with it. We have tests to verify that the event passing mechanism works so there's no need for you to test anything beyond the code that you just wrote.
I don't have time to re-review your code tonight but I'll give you a full review again tomorrow!