apeisa Posted November 4, 2011 Share Posted November 4, 2011 Thanks ryan! I actually got that part pretty well handled (well, my code was obviously messier than yours so took yours as a new starting point). Yes, I have extended FieldtypeFile here. What is causing me problems is dealing and saving individual Pagefile. This is where I try set $img->crop value and save it. <?php $img = wire('pages')->get($pages_id)->{$field}->get("$filename"); // Just realized that individual files are also wirearrays, clever! $img->crop = $crop; // Values in array, since sleepvalue expects an array wire('pages')->get($pages_id)->save(); If I try to save the field or pagefile alone it gives me error - now when I try to save the whole page the crop value doesn't get saved. Link to comment Share on other sites More sharing options...
ryan Posted November 5, 2011 Share Posted November 5, 2011 What error message are you getting? If you export the structure of the field_$name table using your field, what does the structure look like? (can you paste in)? Since you are keeping $img->crop as an array, do you have something in your sleepValue that converts it to a string (like the CSV one I mentioned) or something to keep it consistent with the format needed in the DB? Link to comment Share on other sites More sharing options...
apeisa Posted November 5, 2011 Share Posted November 5, 2011 What error message are you getting? Not errors at all, but nothing gets saved. Actually if I try to save just the description, it fails also. But $img has right image, since I can use $img->url etc. My field_cropimages is like this: pages_id int(10) data varchar(255) sort int(10) description text crop varchar(60) And images saved through admin will have values like this: 1001 penguins.jpg 1 0,0,0,0,0,0 Now I have tried to save only description, to make sure problem isn't in how I handle the sleepvalue (currently I have your example code). Here is my current code on my processmodule executeSave: $page = wire('pages')->get($pages_id); $img = $page->{$field}->get("$filename"); echo $img->url; // This works $img->description = "Why don't you save me?"; // Nope, description doesn't get saved $page->title = "New page title"; // This also get saved $page->save(); // No errors at all, using debug mode Link to comment Share on other sites More sharing options...
ryan Posted November 5, 2011 Share Posted November 5, 2011 Can you try adding this right before your save? I'm wondering if this makes it save: $page->trackChange($field); // where $field is the name of the field, 'images' or whatever it is Link to comment Share on other sites More sharing options...
apeisa Posted November 6, 2011 Share Posted November 6, 2011 Yep, that works! Does it mean here is bug or something strange - or is it required to use that in some scenarios? Link to comment Share on other sites More sharing options...
apeisa Posted November 6, 2011 Share Posted November 6, 2011 Ok, I have made good progress here. And as always, when you start implementing something simple, you want something more. So instead of single cropping value, I want ahead and implemented the way that you can add multiple dimensions. Now you can set in your image field's input tab all the different cropping settings you want (currently in csv), like this: Tiny thumb,60,60 Bigger thumb,200,200 Portrait image,150,200 That gives you corresponding links in your edit page view. Clicking that tilte (ie. "Portrait image") gives you this view in modal, so it is very easy to get just the right cropping. This is also what I have implemented so far. But now that I allow multiple croppings, I am considering the implementation. Instead of saving cropping values in db and do cropping on runtime (if not done before), wouldn't it be easier to just do cropping as is, and save the image with cropped suffix. So if my image file is image.jpg, and then I crop it, it would be saved like this: image.portrait-image.jpg And in templates usage would be something like this: <?php $images = $page->images; $portrait = $images->eq(0)->getCrop('Portrait image'); echo "<img src='$portrait->url' />"; If there isn't required file (image.portrait-image.jpg in this case), it will create one using pw's default cropping (center). Just got this idea, but I think that is much simpler solution than the one I was heading to... What do you guys think? Link to comment Share on other sites More sharing options...
martinluff Posted November 6, 2011 Share Posted November 6, 2011 Sounds logical to me (+ cool and in spirit of PW's logical simplicity and human-readable coding). You're just a factory for good stuff eh! Link to comment Share on other sites More sharing options...
Pete Posted November 7, 2011 Author Share Posted November 7, 2011 Just a thought - but the next step might be image tagging like FB? Not sure that falls under the remit of a separate module but I can think of lots of places where that might be useful, though I appreciate that a lot of the time it won't be. Link to comment Share on other sites More sharing options...
ryan Posted November 7, 2011 Share Posted November 7, 2011 Does it mean here is bug or something strange - or is it required to use that in some scenarios? It sounds like a bug, but it's actually just something that's not automated in the system (and I'd forgotten that it wasn't). A page checks for changes when something is set or added to the page itself. But a property down two levels of objects is not something a Page knows internally to check (and it wouldn't make sense for it to). So that object has to instead notify the page, or at least its parent object, that something has changed. So it's something that I think I can automate, but it's one of those things I'd want to do a lot of testing with to make sure I'm not screwing up anything else. So in the short term, I would suggest continuing to use the $page->trackChange method to let the page know about the change. In the future when this is built in, it won't be necessary, but also won't hurt anything to keep it there. The reason this isn't an issue with PageEdit (for example) is that PageEdit doubles up on change tracking by checking the Inputfields themselves for changes. It basically does this: if($inputfield->isChanged()) $page->trackChange($inputfield->name); Btw, the purpose of change tracking is so that PW can avoid the overhead of saving all fields on the page, and instead just focus resources on the fields that have actually changed. Link to comment Share on other sites More sharing options...
apeisa Posted November 11, 2011 Share Posted November 11, 2011 I got hour or so with this and got it working. I don't want anyone using this on production site yet, since this was late night coding and I haven't given any testing or cleaning. But if you guys wanna take a look, then go for it. The feedback I am interested to is that if I have nailed the most of the "thumbnail scenarios" that people have had - especially stillmovingdesign's since he was kind enough to sponsor this development. I think there is one required feature missing and that is autogenerating thumbnails if you haven't set those yet. Also it would be nice to track the thumbnail size also - so if you change thumb setup it would generate new images. How to install: -Add FieldtypeCropImage.module, InputfieldCropImage and ProcessImageEditor folders to your site modules folder. Install those modules from PW admin. -Add this method to /core/Pageimage.php file (I know this is core hack, but only now for testing - need to discuss with Ryan how to implement this). public function getThumb($thumb) { $prefix = $this->sanitizer->name($thumb); $imgPath = $this->pagefiles->path . $prefix . "_" . $this->basename; $imgUrl = $this->pagefiles->url . $prefix . "_" . $this->basename; if (is_file($imgPath)) { return $imgUrl; } else { return false; } } -Create new field or edit current image field and choose it fieldtype as "CropImage" -Edit field and input tab, there last setting: "crop setups". Add as many crop setups you like, here is example: thumb,100,100 portrait,100,180 -Add field to your template and edit template file and add this: foreach ($page->cropImages as $image) { //cropImage is your field name if ($image->getThumb('portrait')) { // "portrait" needs to be something from your crop setups echo "<img src={$image->getThumb('thumbnail')} />"; } } EDIT: Tried to upload small screencast, but my Jing didn't want to co-operate with me. I'll try later again. pwCrop.zip Link to comment Share on other sites More sharing options...
ryan Posted November 12, 2011 Share Posted November 12, 2011 Nice work Antti! Just tried it out and all seemed to work well, and I love having this capability! It did take me a couple minutes to understand how it works from the cropping side. For instance, I wasn't sure why the pixels weren't locked when selecting a crop area. But then realized it'll let me crop and scale at the same time (cool!). I had a couple questions/comments: 1. After submitting a crop, the screen that follows just says "Cropped Image: 1" rather than a look at the crop. I'm assuming that's because it's a work in progress, but just wanted to mention it in case I was getting a debug message or something. Though it does appear that the crop did work. 2. Is there any way to get back to the crop? If I click the "thumbnail" link again, I'm starting a new crop rather than seeing the existing one. 3. When making a crop, the crop appears on the left and the large image on the right. I was making a crop of 400px wide, but could only see part of it on the left. I was wondering if maybe the crop should appear below the large (rather than next to it), as I'm thinking I just ran out of screen width? -Add this method to /core/Pageimage.php file (I know this is core hack, but only now for testing - need to discuss with Ryan how to implement this). You can add a new function to any other core class or module, just by adding a hook for a function that isn't already there. I would suggest removing the function from Pageimage.php and instead adding it to your FieldtypeCropImage class. I just tested this exact code below and it works exactly the same as if getThumb() was in Pageimage: <?php class FieldtypeCropImage extends FieldtypeImage { public static function getModuleInfo() { return array( 'title' => 'Crop Images', 'version' => 100, 'summary' => 'Field that stores one or more GIF, JPG, or PNG images', ); } public function init() { $this->addHook('Pageimage::getThumb', $this, 'getThumb'); } public function getThumb(HookEvent $event) { $thumb = $event->arguments[0]; $prefix = $this->sanitizer->name($thumb); $img = $event->object; $imgPath = $img->pagefiles->path . $prefix . "_" . $img->basename; $imgUrl = $img->pagefiles->url . $prefix . "_" . $img->basename; if(is_file($imgPath)) { $event->return = $imgUrl; } else { $event->return = false; } } } So the above adds a getThumb() function to the Pageimage class without you having to hack the core to add it. The behavior of it from the API side is identical, so you don't have to change anything else. Great work with this new fieldtype! I look forward to using it. Link to comment Share on other sites More sharing options...
apeisa Posted November 12, 2011 Share Posted November 12, 2011 1. After submitting a crop, the screen that follows just says "Cropped Image: 1" rather than a look at the crop. I'm assuming that's because it's a work in progress, but just wanted to mention it in case I was getting a debug message or something. Though it does appear that the crop did work. Yep - that is wip-stuff. I am thinking of showing cropped result + two actions: re-crop or close modal. 2. Is there any way to get back to the crop? If I click the "thumbnail" link again, I'm starting a new crop rather than seeing the existing one. Currently no. But if you crop again, it will rewrite your existing crop image. I don't save any details about cropping on db, it's only a file. Though I could save those values to image name also and read from there - but I think there is not much value to get back to old crop instead of re-cropping? Or how do you guys think? 3. When making a crop, the crop appears on the left and the large image on the right. I was making a crop of 400px wide, but could only see part of it on the left. I was wondering if maybe the crop should appear below the large (rather than next to it), as I'm thinking I just ran out of screen width? Yep, that was very quickly done UI there. I have probably hard coded the width of the left panel. It is kind a problematic in all situations, if you have very large images. I'll probably show the preview under the image. You can add a new function to any other core class or module, just by adding a hook for a function that isn't already there. I would suggest removing the function from Pageimage.php and instead adding it to your FieldtypeCropImage class. I just tested this exact code below and it works exactly the same as if getThumb() was in Pageimage: Thanks for this, again great example how easily extendable PW is! I will update my module soon to have this and other tiny fixes. Thanks for testing Ryan. Others, here is quick screencast about this module: http://screencast.com/t/me9CSapXF Link to comment Share on other sites More sharing options...
ryan Posted November 12, 2011 Share Posted November 12, 2011 Currently no. But if you crop again, it will rewrite your existing crop image. I don't save any details about cropping on db, it's only a file. Though I could save those values to image name also and read from there - but I think there is not much value to get back to old crop instead of re-cropping? Or how do you guys think? While it would be nice to have it remember the crop, I agree it's something that isn't technically necessary and probably not a real time saver. But maybe just a nice feature to add in version 2.0 or something. And then in version 3.0, you could add little overlays to the main image to show where the crops are... I'm kidding, but this is just fun stuff to think about. Instead, I think the most value would be in just being able to see the existing crop from the admin without having to go view the page. For example: Display it in the image list below the large image with the existing "thumbnail" label/link above or below it. Or just a simple link to see it, like: "thumbnail: view / change". Or show the crop in the crop editor with the label "your current crop". It is kind a problematic in all situations, if you have very large images. I'll probably show the preview under the image. Could the large images be scaled to the width of the window, or would that break jCrop's ability to track the pixels of the image? I'm guessing it would break jCrop, but just curious. Thanks for posting the screencast too! Link to comment Share on other sites More sharing options...
Soma Posted November 12, 2011 Share Posted November 12, 2011 Great work on this module so far. I implemented the function like ryan suggested and it works great. I used this jQ plugin also in some project and it's a nice one. I agree with the feedback Ryan gave already. But since it's a WIP it's hard to give suggestions to current version since I don't know what's planned. Also since there's already many posts and I don't have the time to read and valuate all, aswell there's so many things and ways, options that it could need/have. I think it's a nice image extension for galleries, as I think using it for regular content (wysiwyg) images it's not suited. Just thinking loud, it need more love in the UI and having previews of the croped versions would be nice. But I think you already know that. Remembering the thumbs would be nice as if you edit/change an already edited it would be nice to start with the area already selected. Also autocrop was something that poped up in my mind imediately after trying. Would be nice feature like default croped image. Issues: Not sure if you are aware that when I upload (drag) it doesn't get shown, it stops for me by 100%. When I upload with dialog it works, but it doesn't invoke fancybox preview and crop fancybox function... so only after reloading page they work again. Some notice shown when debug on: Notice: Undefined offset: 1 in /Applications/XAMPP/xamppfiles/htdocs/pw2.ch/site/modules/pwCrop/InputfieldCropImage/InputfieldCropImage.module on line 79 Notice: Undefined offset: 2 in /Applications/XAMPP/xamppfiles/htdocs/pw2.ch/site/modules/pwCrop/InputfieldCropImage/InputfieldCropImage.module on line 79 Notice: Undefined offset: 1 in /Applications/XAMPP/xamppfiles/htdocs/pw2.ch/site/modules/pwCrop/InputfieldCropImage/InputfieldCropImage.module on line 79 Notice: Undefined offset: 2 in /Applications/XAMPP/xamppfiles/htdocs/pw2.ch/site/modules/pwCrop/InputfieldCropImage/InputfieldCropImage.module on line 79 Link to comment Share on other sites More sharing options...
apeisa Posted November 12, 2011 Share Posted November 12, 2011 Thanks guys for the great feedback. When I posted this I was little bit hesitant since I think it is little bit too rough from the edges to be posted, but I have got very valuable feedback. Since this is something where I don't have urgent need myself - I also don't have very strong opinions how it should function. I will make this more polished and version 1.0 soon, which will include these features: When you click thumbnail -link, it will open modal which shows that thumbnail. There is link to re-crop or possibility to close modal. It will autogenerate thumbnails, using default PW-method: center and no zooming Cleaner UI for cropping and after cropping it goes back to first view (shows cropped image and possibility to re-crop) I clean code and add some error handling. Also might hook to ImageSizer class to add Crop-method there Soma: yes, this is only for template usage. You cannot even use this on wysiwyg-editors. I couldn't reproduce the drag & drop problem, so it must be something else on your install that is causing that. Those notices indicate that you have something strange on your crop setups - but I will add better error handling there. Link to comment Share on other sites More sharing options...
apeisa Posted November 12, 2011 Share Posted November 12, 2011 I get these error messages when I use that hook: Notice: Trying to get property of non-object in C:\apache\htdocs\discussions\site\modules\FieldtypeCropImage.module on line 20 Notice: Trying to get property of non-object in C:\apache\htdocs\discussions\site\modules\FieldtypeCropImage.module on line 21 Does it require uninstall/install to make it work? I have changed few aspects of my code, but not the template side of it. Also - using core hack it does work. Link to comment Share on other sites More sharing options...
ryan Posted November 13, 2011 Share Posted November 13, 2011 Does it require uninstall/install to make it work? I have changed few aspects of my code, but not the template side of it. Also - using core hack it does work. Can you post what's on lines 20 and 21? Or just post the entire code of the function you are using. I'd tested it out here and all worked well. The error message you posted sounds like $img->pagefiles isn't recognized (that's my best guess). Access to that property was added in a Nov 1st commit (less than 2 weeks ago), so you might want to double check the the system you are testing on has a relatively recent version, just in case. Link to comment Share on other sites More sharing options...
apeisa Posted November 13, 2011 Share Posted November 13, 2011 Yep, that was it (I was running the one where you added ::ready for modules). Thanks Ryan! Link to comment Share on other sites More sharing options...
apeisa Posted November 14, 2011 Share Posted November 14, 2011 Small problem (again): How do I get my inputfield setting value? I have this code in my fiedtype: $this->modules->get('InputfieldCropImage')->get('crops'); But it returns always the default value I have set in my InputfieldCropImage class Init: public function init() { parent::init(); $this->set('crops', 'thumbnail,200,200'); } Saving and editing that value works in admin and also when I read $this->crops in my inputfield, it get's modified values. But outside inputfield (on my fieldtype, to be exact) it just returns the default. This got me thinking that if I have those crop setup settings in wrong place all together - should they be in fieldtype instead of inputfield? Link to comment Share on other sites More sharing options...
ryan Posted November 15, 2011 Share Posted November 15, 2011 How do I get my inputfield setting value? I have this code in my fiedtype: Whe you call $modules->get('InputfieldCropImage') it is returning an Inputfield to you without any state or connection to a field in the system. So the only config values it would have would be those that are defined with the module itself (on Modules > Inputfield > InputfieldCropImage). Also note that it's better to set defaults in a __construct() rather than an init() because PW populates that module configuration after __construct() and before init(). So you could be overwriting the config values PW set if you were doing it in init(). I don't have the module's code in front of me here, but if I recall, that 'crop' value was set when editing the field under Setup > Fields? If so, you could just get it from the field. So if the field was called 'images', you could get it like this: $crops = wire('fields')->get('images')->crops; The reason your Inputfield may have had that crops value before is because it likely had the context of a field, like 'images'. But if you don't have that context, then you can just as easily grab it from the field directly. This got me thinking that if I have those crop setup settings in wrong place all together - should they be in fieldtype instead of inputfield? PW stores both the Fieldtype and Inputfield context with the PW field itself, so it doesn't necessarily matter much. But in general, it's better to define any values you would need in the API with the Fieldtype rather than the Inputfield. The reason is that the Inputfield is only applicable when editing in the admin. Whereas the Fieldtype is always applicable in the API. So in your case, I think it probably is better to store them with the Fieldtype, but I wouldn't bother to switch it unless it's easy to do. Link to comment Share on other sites More sharing options...
apeisa Posted November 15, 2011 Share Posted November 15, 2011 Ah, I understand. I actually can have different thumb setups for different fields (didn't realize that first) Btw, if I have this on my template file: echo $page->fieldname->getThumb('thumbnail'); Can my getThumb-method know about fieldname? Or should I just add it as variable? Link to comment Share on other sites More sharing options...
ryan Posted November 15, 2011 Share Posted November 15, 2011 Your getThumb method could figure out the field, but not a very direct way. It would have to go back to the owning $page and see what fields it had, and match that up to the type you are looking for. I'm thinking something like this: <?php foreach($img->page->fields as $field) { if($field->type instanceof FieldtypeCropImage) { // $field may be the one you want // unless multiple FieldtypeCropImage fields on this page } } If you defined your crop settings with the module itself, then it might be simpler as it would already have the crop settings available to it. Link to comment Share on other sites More sharing options...
apeisa Posted November 15, 2011 Share Posted November 15, 2011 Thanks for your time and help Ryan. I'll go now with two variables, and finish other aspects. I will clean and re-factor parts of the code. One downside defining crops directly in fieldtype settings (or plus, depends on usage) is that you cannot define crops per field basis. I think that would make it easier on huge sites, but on most scenarios it will be unnecessary. Link to comment Share on other sites More sharing options...
apeisa Posted November 15, 2011 Share Posted November 15, 2011 Ok fellows, I cleaned code quite a bit and it's not that bad anymore. I pushed it also into github: https://github.com/apeisa/CropImage I need to write better readme for this, but basic usage in templates is like before: <?php echo $page->cropimagefield->eq(0)->getThumb('thumbnail'); And that returns url to your image. This does all the magic I wanted it to do: If there isn't cropped image, it crops one for you (using default center cropping) If you change your crop width and/or height, it recrops images - so your image is always on right size There is little preview when you hover over crop link I got few items on todo list, and one for those is to provide nicer UI (at least for links and preview). Happy testing and all feedback is most welcome! Link to comment Share on other sites More sharing options...
apeisa Posted November 15, 2011 Share Posted November 15, 2011 I think this topic is done. Feel free to open new topic if you have need or idea how to make images better in PW. Topic for CropImage-module can be found from here: http://processwire.com/talk/index.php/topic,705.msg5343.html Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now