-
Posts
10,877 -
Joined
-
Last visited
-
Days Won
348
Everything posted by adrian
-
I haven't looked over the shuffleAssoc function properly, but you can probably just use PW's shuffle(): $randimages = $bannerimages->shuffle();
-
Ok, I made a very simple hack to the thumbnails module. Inside public function ___executeSave() within the ProcessCropImage.module I added the following lines just before the timestamp comment. if(!$page->$prefix) { $f = new Field(); $f->type = $this->modules->get("FieldtypeImage"); $f->name = $prefix; $f->label = ucwords(str_replace('_', ' ', $prefix)); $f->save(); $page->template->fields->add($prefix); $page->template->fields->save(); } $page->$prefix->deleteAll(); $page->$prefix->add($targetPath); $page->save($prefix); Firstly it checks for the presence of a field named the same as the crops name. So, if you set up your crop as: thumbnail,100,100 then it will look for a field name 'thumbnail'. If it's not found, it creates it and adds it to the current page's template. I would like to be able to set the field visibility and Maximum files allowed settings, but haven't figure that out yet. Then it takes the cropped image and adds it to that field. Only minor inconvenience is that the image won't appear in the thumbnails field until the user saves the page. Not sure if there is any way around that - I feel like there should be a way to hook into the ajax image uploader to refresh the field, but haven't investigated yet. Antti, is this something you'd consider adding (maybe as a configurable option), or do you think my need is too specific?
-
Hey Macrura - good idea - for some reason I always resort to sql when it comes to these one off manipulations. Off topic, but I wonder if a module that allowed you to run code snippets would be a good idea. It could perhaps even have a library of examples to deal with common issues like this, and the ability to store/share your own snippets. Kind if along the lines of Nik's excellent SelectorTest. Ideally it would report all the changes made etc.
-
Thanks for all the great suggestions Ryan. I will definitely add those dependency checks and implement some config options, including the field, max image dimensions etc and make available on github / modules directory. I didn't really have any time to work on this yesterday, but I took a quick look at using $page->isChanged("field") in an attempt to determine whether the user has uploaded a new version of the PDF during the current page editing session, so it knows to regenerate the images. It didn't seem to work as I expected. Looking at the docs and cheatsheet it seems like I don't need to turn on change tracking in this scenario, but maybe I not properly understanding how this works. This seems like it should be the most elegant way to check this. The other thing I need to do is ensure Ghostscript is installed. I don't think there is a PHP way to do this without exec or system, so I am wondering what you think about having the module include a very small PDF file that the module install method can do a test readImage on. Would that be too hackish? I don't want to blemish PW
-
Hey Marty, Great idea on adding the cropped image to an image field. I might take a look at the module and tweak it to do that - I expect it should be fairly straightforward. Hey Soma - I personally like the concept of your imagesManager, but my users are very non-tech, so I don't know how it would fly with them. I am also not a fan of allowing/encouraging users to insert images into a RTE if the site structure can be standardized, but it isn't always possible unfortunately.
-
Ability to define convention for image and file upload names
adrian replied to adrian's topic in Wishlist & Roadmap
Thanks for the explanation Ryan. I had never thought it about it as a lazy way, but I certainly see your point. I initially used to write my little custom CMSs to retain original filenames, but changed to auto-generated because most of my work is for sites which provide lots of materials designed to be downloaded by end users. Having clients upload files with names like: Final ReportV6 web version for John Feb 23.PDF started to drive me a little crazy though. Not very useful or meaningful to the poor end user who downloads it. No amount of training or explanation could get them to make meaningful filenames. Thanks for the example module code - I will definitely make use of that. I really can't believe how easy you have made implementing custom modules. The lack of ability to do this with other system (whether real or perceived) is why I never went the CMS route for so many years It always seemed like I would be hacking away at things to make the functionality I needed. -
I am not sure on the recommended way of avoiding this scenario in the first place, but you could run some SQL to change those links. Something like: UPDATE field_body SET data = REPLACE( data, '/mysite', '' ) This is untested and as with any manual DB manipulation, make sure you have a good backup first.
-
Getting fake URLs (with UrlSegments) returned in search results
adrian replied to adrian's topic in General Support
Just wanted to note that I just updated the code block above. It now includes an additional 'if' to make sure that the checkbox field in question is actually checked. It also accurately counts the number of returned results. And it appends the parent title to the link title so users can see the difference between two links that otherwise look the same - eg Affiliates > Joe Blogs and Contractors > Joe Blogs. Seems to be behaving now, but I am sure I will come across another problem scenario or two before it is fully dialed. -
Sorry, one more thing - is it possible (or should I say, can you make it possible) to set just one dimension, or perhaps neither (set them to 0). I would like to allow the user the ability to crop freeform, and then resize automatically (if one dimension set), or later through a template if no dimensions set. I think this would be really useful - often in layouts you want all images the same width, but you don't care about height, and vice versa.
-
A couple of hopefully quick questions. I can't seem to find a way to use the "Select Image" feature within a text area to select one of the cropped images. It only seems to load up the original uncropped images. Is this possible? Also, is it possible to not do any cropping by default, but rather only if the user chooses to. I want them to be able to choose to crop just one of the images in a multi images field then grab that one (or the first one of the images) that has a cropped version. Make sense? Thanks!
-
Uninstalling AdminBar fixed the redirect issue - thanks, and sorry if I missed that mentioned somewhere else. It would be great to have that simplified version of AdminBar you mentioned too, to work with Fredi. I think the new page option is an important addition - thanks for looking into it. Sorry if my AdminBar and CKEditor inline editing link was confusing. I am not completely convinced about inline editing - I just know there has been a fair bit of discussion about it in this forum. I thought the ability of Fredi to limit editing to specific fields could be tied into inline editing with some visual cue to identify which fields are editable. Anyway, sounds like that is for a future module. renderAll() looks much better
-
Agreed - very nice responsiveness layout! Love seeing what people are creating with PW.
-
Hi Soma, I actually played around with your iframe modal approach for my first PW site a couple of months ago. It gave me lots of idea, so thank you In the end I decided against it - I feel like modal works well for single fields, but not all the fields of a complex pages - seems crowded and messy when you have to scroll in a modal. I actually built a very basic edit mode - actually kind of like AdminBar (but nowhere near as slick) - I hadn't discovered AdminBar at the time. It had the ability to add edit buttons for each repeated section (child page) of content, without needing to be on the specific child page. I think there are so many cool ways to go with this and I am excited to see how this evolves.
-
Hey Antti, I love the flexibility of editing options for this module and since you are doing such an awesome job, can I add some additional 'ultimate goal' options without seeming greedy and unappreciative? I have a structure where I am drawing content from one page structure of people and populating it on several different pages on the front-end based on tags within the main structure (more details here: http://processwire.com/talk/topic/3279-getting-fake-urls-with-urlsegments-returned-in-search-results/). I set up Fredi to use the $another_page option, which is perfect for editing these page fields on the front end. The problem is that when I submit, it redirects to the page that doesn't exist on the front-end. Could Fredi be made smart enough to redirect back to the page it was on when editing was initiated instead? Because of the same issues above, front-end creation of a new child page is difficult. Your excellent AdminBar (which works great on the other sites I am using it with), fails when trying to create child pages in this scenario. Could Fredi handle this with the $another_page option? Maybe it's just me, but I actually liked the quasi tab-like approach of AdminBar, compared with the Fredi modal. That said, do you have any plans to integrate the inline editing of CKEditor into Fredi and make editing seamless? Any chance of an option for all fields, rather than needing to write them all out like echo $fredi->render("headline|title|summary"). As an example, these people pages in my example above have 13 fields. Seems like: $fredi->render("allfields") or something like that would be a nice enhancement. Please let me know if I can provide a better explanation of any of these. Thanks!
-
Ok, here is v2. It now uses a standard multi images field to store the images, and creates an image for each page of the PDF. I figure that way the template can just grab the first one where it needs to generate a cover thumbnail. Not relevant to the module, but I added a document_thumb_override field that allows a user to upload an image to use in place of the first page image if they'd prefer. Obviously the template checks to see if this is available before using the first page image. I have several comments throughout the code on things I will add shortly: Ability to see what images are missing (if any) and just generate those. Check if the PDF was updated (so need to generate images again). Add some loading spinner as this definitely takes a while Ability to control set the required or max limit on the file dimensions - for a standard letter sized doc, the images are currently generated at 2448px x 3168px. The commented out scaleImage code needs to be activated, but tied to module config settings. Also, should I have the module create any required fields, or just provide an explanation of how to adapt it to a user's particular scenario / field structure? Thanks for any comments/suggestions. <?php /** * ProcessWire ProcessPDFImageCreator * * Process PDF Image Creator creates images from PDFs. * * @copyright Copyright (c) 2013, Adrian Jones * */ class ProcessPDFImageCreator extends WireData implements Module { /** * Return information about this module (required) * * @return array * */ static public function getModuleInfo() { return array( 'title' => 'PDF Image Creator', 'summary' => 'Creates images from PDFs.', 'version' => 002, 'author' => 'Adrian Jones', 'singular' => true, 'autoload' => true ); } /** * Initialize the module and setup hook */ public function init() { $this->pages->addHook('save', $this, 'createPdfImages'); } public function getNumPagesPdf($filepath){ //The FPDI method is the best combination of accuracy and efficiency, but introduces yet another dependancy. There are also issues with the free version of FPDI and support for PDF > 1.4 //If you have the paid version, I think this is the best option. It is available here: http://www.setasign.de/products/pdf-php-solutions/fpdi/ /*require_once('/tcpdf/tcpdf.php'); require_once('/fpdi/fpdi.php'); $pdf =& new FPDI(); $pagecount = $pdf->setSourceFile($filepath); return $pagecount;*/ //If you have exec available, you can also try this option: http://stackoverflow.com/questions/14644353/finally-found-a-fast-easy-and-accurate-way-to-get-the-number-of-pages-in-a-pdf/14644354#14644354 //The first of option here is because the imagick method is quite slow. It runs first and only resorts to the imagick option if it fails. Unfortunately, it often fails! $fp = @fopen(preg_replace("/\[(.*?)\]/i", "",$filepath),"r"); $max=0; while(!feof($fp)) { $line = fgets($fp,255); if (preg_match('/\/Count [0-9]+/', $line, $matches)){ preg_match('/[0-9]+/',$matches[0], $matches2); if ($max<$matches2[0]) $max=$matches2[0]; } } fclose($fp); //If above failed ($max==0), then resort to imagick if($max==0){ $im = new imagick($filepath); $max=$im->getNumberImages(); } return $max; } /** * If document_pdf field contains a PDF, generate images for each page, stored in a standard multi images field. * Should maybe switch document_pdf field to a standard files field, or maybe get modules to install the field. Should the module check availability of required fields in general when installing? * */ public function createPdfImages($event){ $page = $event->arguments[0]; if(count($page->document_pdf)>0){ //Need to modify check with an OR to determine if PDF file was just updated from past uploaded version and also see if only some of the images exist and only generate the missing ones //Also need to store number of pages in document_pdf_num_pages field so don't have to run that check every time, unless the PDF changed. if(count($page->images)==0){ $numPages = $this->getNumPagesPdf($page->document_pdf->first()->filename); for ($pn=0; $pn<$numPages; $pn++){ $this->createPdfImage($page, 'images', $pn); } } } } /** * Generate images. * */ public function createPdfImage($page, $image_field, $pn) { $pdf_filepath = $page->document_pdf->first()->filename . '['.$pn.']'; $jpg_filepath = str_replace('.pdf', '-'.$pn.'.jpg', $page->document_pdf->first()->filename); $resolution = 288; // Can't remember where I got 288 from - I think mostly trial and error many years ago, but seems to give best results $im = new imagick(); $im->setOption("pdf:use-cropbox","true"); $im->setColorspace(Imagick::COLORSPACE_RGB); $im->setResolution($resolution,$resolution); $im->readImage($pdf_filepath); $geometry=$im->getImageGeometry(); $width = ceil($geometry['width'] / ($resolution/72)); $height = ceil($geometry['height'] / ($resolution/72)); $im->setImageFormat("jpg"); /*if($width>150){ $width = 150; $height = 0; } $im->scaleImage($width, $height);*/ $im->writeImage($jpg_filepath); $page->of(false); $page->$image_field->add($jpg_filepath); $page->$image_field->last()->description = $page->title . ' Page ' . ($pn+1); $page->save(); } }
-
Hey diogo - thanks for your thoughts. So do you mean on save, rather than what I have which is after save? I changed it addHookAfter to just AddHook and it seems to work fine still. I already have a check to see if the document_thumb image field is populated. Anyway, I'll be sure to check for missing images from the full collection of pages images (in case something crashes, or the user kills the process), and just generate the missing ones on the next page save - good idea - thanks! Once all the page images have been generated, subsequent saves of the page for other edits should be quick since it won't regenerate the images, although I should probably build in a check to see if the PDF has been changed from the original uploaded version so that new images are generated without the user needing to delete the old ones to trigger the function again. Any ideas how to check if the PDF has been replaced during the current edit? Maybe the key thing is to add some JS loader when saving to ask them to be patient. Anyone have any better ideas?
-
I have put together a very basic module for generating images from the pages of uploaded PDFs. It requires imagemagick, ghostscript, and the imagick pecl extension. It could easily be adapted to work without the imagick extension, but I usually like having exec disabled. At the moment it also requires a couple of specific custom fields: document_pdf (file) and document_thumb (image), both with "Maximum files allowed" set to "1". Obviously I will make these more generic, or add the fields on module install once this is closer to being released. There is some commented code that facilitates image resizing before upload to PW if that is what is wanted. I should also make these configurable module options. Currently I am using this for a searchable list of publications to generate a thumbnail of the cover to place with the description, PDF download link etc. I am planning on extending this a fair bit as I want to use it to generate image previews for each page of the PDF so I can use them in a "look inside" modal lightbox. These would all be stored in a standard images field. I think when I start generating images for all the pages I am going to run up against a speed problem. It could potentially take a few minutes to generate all the images for a large PDF. I was thinking of making use of lazycron, but I think I'd rather see some progress indicator. The other issue is if I use lazycron, then it is possible that someone may visit the site and go to use the look inside functionality before the images for all the pages are ready, so maybe this idea is out. Perhaps the best approach would be to hook into the PDF upload. Once the upload is complete, the module would start generating the images before the page is ever saved by the user. Would really appreciate any suggestions on how to set this up. Off the topic a little, but one other minor consideration in all this is RGB vs CMYK colorspace. If the user uploads an RGB PDF then everything is fine, but if someone uploads CMYK PDFs the colors are often terrible, but there is a tweak that can be made to imagemagick to fix it. Here is a good description of the problem and how to fix it: http://www.lassosoft.com/CMYK-Colour-Matching-with-ImageMagick Basically you need to add the command line option ''-dUseCIEColor'' to all of the GhostScript commands in the delegates.xml file, so that they now look like this: <delegate decode="eps" encode="ps" mode="bi" command='"gs" -q -dBATCH -dSAFER -dUseCIEColor -dMaxBitmap=500000000 -dNOPAUSE -dAlignToPixels=0 -sDEVICE="pswrite" -sOutputFile="%o" -f"%i"' /> Would anyone else make use of this module? Also, does anyone have any obvious suggestions for what I have so far. It's my first module, and I don't really have a handle on best practices yet. Thanks! PS I know convention is to attach module files, but this one is so short at the moment, it didn't seem worthwhile. <?php /** * ProcessWire ProcessPDFImageCreator * * Process PDF Image Creator creates images from PDFs. * * @copyright Copyright (c) 2013, Adrian Jones * */ class ProcessPDFImageCreator extends WireData implements Module { /** * Return information about this module (required) * * @return array * */ static public function getModuleInfo() { return array( 'title' => 'PDF Image Creator', 'summary' => 'Creates images from PDFs.', 'version' => 001, 'author' => 'Adrian Jones', 'singular' => true, 'autoload' => true ); } /** * Initialize the module and setup hook */ public function init() { $this->pages->addHookAfter('save', $this, 'createPdfImage'); } /** * If document_pdf field contains a PDF, generate an image from the first page. * * */ public function createPdfImage($event) { $page = $event->arguments[0]; if(count($page->document_pdf)>0){ $src = $page->document_pdf->first()->url; if(count($page->document_thumb)==0){ $pdf_filepath = $page->document_pdf->first()->filename . '[0]'; //the appended [0] refers to the first page of the PDF $jpg_filepath = str_replace('.pdf', '.jpg', $page->document_pdf->first()->filename); $resolution = 288; $im = new imagick(); $im->setOption("pdf:use-cropbox","true"); $im->setColorspace(Imagick::COLORSPACE_RGB); $im->setResolution($resolution,$resolution); $im->readImage($pdf_filepath); $geometry=$im->getImageGeometry(); $width = ceil($geometry['width'] / ($resolution/72)); $height = ceil($geometry['height'] / ($resolution/72)); $im->setImageFormat("jpg"); /*if($width>150){ $width = 150; $height = 0; } $im->scaleImage($width, $height);*/ $im->writeImage($jpg_filepath); $page->of(false); $page->document_thumb->add($jpg_filepath); $page->document_thumb->first()->description = $page->title . ' PDF thumbnail'; $page->save(); } } } }
-
That would be an awesome addition to PW. I am tossing up the best field type for tags and I think that the multivalue option in Select2 type might actually be it
-
Sorry, that was a bit lame wasn't it Basically I got a WSOD. I am really not sure what happened. I actually had the same issue with the thumbnail module. I just reinstalled yours and it is fine now. Seems like there is something weird on my server. All the other modules I have installed (either manually or through the modules manager) have been fine, but these two have required installing, deleting the folder, and then installing again to get them to work. I'll let you know if I ever figure it out.
-
Getting fake URLs (with UrlSegments) returned in search results
adrian replied to adrian's topic in General Support
Hey Ryan, I should have explained the logic behind the viewable(). It is there to make sure that any pages that get returned have a template. Because $m contains all pages in the tree it will also contain the "People" parent and all its children. This was my way of preventing these from being displayed in the search results, without needing to make them hidden. The reason I didn't want to rely on hidden is because I will have users creating these people child pages and figured they may not always/ever remember to set them hidden, although now that I think about it, I bet it is possible to force child pages to be hidden - is it? Curious if you have any suggestions for a better way to do this - I do feel like I am hacking a little to make this work with proper search results and breadcrumbs etc. It all works, but I feel like there should be a more standard way of doing it. -
I haven't seen anything mentioned about this, but is it possible to define a format for uploads. For example I think it would be great to be able to specify an optional prefix, then the name of the associated page, then an optional suffix and finally a sequentially increasing number. For example: prefix-page-name-suffix-1.jpg prefix-page-name-suffix-2.png Maybe an option to include the page's parent name or a specific field (something category oriented) in there as well might be useful. I would use some abbreviated version of the site's name as the prefix as a way to help people who might have downloaded something to know where it came from. Personally I really don't like downloading files with meaningless and inconsistent names, especially stock camera filenames. Might be a good idea for a module. EDIT: Module for this functionality is now available at: http://processwire.com/talk/topic/4865-custom-upload-names/
-
Missing required value error to show field label instead of field name
adrian replied to adrian's topic in Wishlist & Roadmap
Sorry, yes I do at the moment. Turning that off takes care of the "Session:" -
Sorry, lots of little suggestions today Just thinking that it might be nicer for users to see the field name in these messages. In some cases the name can be quite different from the label, which could confuse them. Session: Missing required value (Field Label) vs Session: Missing required value (field_name) I also wonder whether the "Session:" is relevant, especially for non superusers.
-
All good points teppo It's one of those canned functions I found somewhere a long time ago and haven't really thought too much about it. Its formatting could certainly be improved. Mostly I just wanted to get the point across that I think filesizeStr should do some rounding and unit changes when appropriate.
-
Hey Nico, Module still doesn't seem to be in the directory. I tried a manual install, but it crashed my site completely - had to delete it to get things running again - might be something weird at my end, but might be worth checking out.