-
Posts
11,241 -
Joined
-
Last visited
-
Days Won
374
Everything posted by adrian
-
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.
-
Hey Nico, I was just testing this out and get several PHP warnings and the template files show up blank. Warning: fread() expects parameter 1 to be resource, boolean given in /xxx/site/modules/TemplateEditor/TemplateEditor.module on line 77 Warning: fclose() expects parameter 1 to be resource, boolean given in /xxx/site/modules/TemplateEditor/TemplateEditor.module on line 78 Notice: Trying to get property of non-object in /xxx/site/modules/InputfieldAceEditor/InputfieldAceEditor.module on line 126 Let me know if I can provide any other debug info.
-
Just wondering about the output from $file->filesizeStr I have only used it once so far, but was surprised to see it return 10,375kB. I would rather have seen 10.4mB Not sure what others think, but I have always used this function and been happy with the output. Thanks for any feedback. function human_file_size($size) { if($size == 0) { return("0 Bytes"); } $filesizename = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"); return round($size/pow(1024, ($i = floor(log($size, 1024)))), 1) . $filesizename[$i]; }
-
No problem - glad it turned out to be an easy fix !
-
I believe it was the Autocomplete field type. I expect you might have trouble changing it back to that, so you might have to create a new field from scratch with this type. I think you might also have to install the Autocomplete module to be able to create this field type. Hope that is of some help until you get a definitive answer from someone who knows for sure!
-
Sorry, I did what I always accuse other people of doing - not reading Thanks for the great explanation!
-
Hey Joss, Can you explain the page_select from this line that appears in the wiki article you posted. I can't see this selector mentioned anywhere else. $posts = $pages->find("page_select=$category");
-
You rock Soma - that's just what I wanted
-
Here's another one - show the name of a field in parentheses after the field label when editing a page in the admin. Maybe I am missing something, but I often have to go back to the fields view to find the actual name in those cases when the label is quite different from the name.
-
Getting fake URLs (with UrlSegments) returned in search results
adrian replied to adrian's topic in General Support
Ok, I have something that works. I am not sure how portable it is yet (I haven't really done any testing), but it seems to work well for my scenario. This is my entire search.php template file. Basically what it does is: Find all pages with the search term (as the standard search.php does) Iterate through all the fields within those returned pages to see if any pages within the $pages array have a name which matches any of the field names If there is a match, build the link using the name of the matching page in the path Add viewable() check to the standard pages found to prevent display of the People > links The key thing (if it's not obvious), is that you must name the field (in my case a checkbox for each of staff, affiliates, contractors to match the name of the page that displays them (the fake url).I know this won't work at all in many scenarios, and I have some ideas for making it more portable and be able to handle situations where you want to use an ASM to choose the categories, but in a rush, so this will do for now <?php $content = ''; $resultText = ''; $count = 0; if($q = $sanitizer->selectorValue($input->get->q)) { // Send our sanitized query 'q' variable to the whitelist where it will be // picked up and $content .=ed in the search box by the head.inc file. $input->whitelist('q', $q); // Search the title, body and sidebar fields for our query text. // Limit the results to 50 pages. // Exclude results that use the 'admin' template. $matches = $pages->find("title|body|summary%=$q, limit=50"); if(count($matches)) { foreach($matches as $m) { $pm = ''; foreach($m->fields as $field) { $corrected_fieldname = str_replace('_','-',$field->name); //To match page name $pagematches = $pages->find("name={$corrected_fieldname}"); $pagescount = count($pagematches); if($pagescount>0){ foreach($pagematches as $pm){ if($m->$field!=0){ $count++; $content .= "<li><p><a href='{$pm->url}{$m->name}/'>". (($pm->title!='') ? $pm->title . " > " : "") . $m->title . "</a><br />{$m->summary}</p></li>"; } } } } if($m->viewable()){ $content .= "<li><p><a href='{$m->url}'>". (($pm && $pm->title!='') ? $pm->title . " > " : "") . $m->title . "</a><br />{$m->summary}</p></li>"; $count++; } } $content .= "</ul>"; $resultText .= "<h2>Found $count pages matching your query:</h2>" . "<ul class='nav'>"; } else { $content .= "<h2>Sorry, no results were found.</h2>"; } } else { $content .= "<h2>Please enter a search term in the search box (upper right corner)</h2>"; } $content = $resultText . $content; include("./main.inc"); -
Getting fake URLs (with UrlSegments) returned in search results
adrian replied to adrian's topic in General Support
Thanks Macrura - very interested to see what you come up with. Conceptually I can't figure out the best way to go from the returned results, which actually 404 in my case because there is no template file for the actual page in the tree, to the working fake URL. I could set up custom replacements for these before returning the search results. This really should be trivial, but I guess I am looking for a more generic and portable solution. Part of the issue is that it would need to return more than one result - eg it would need to return links to: About > Staff > Partners > Affiliates > Partners > Contractors > even though the actual result returned from the $pages->find would simply be People > person. This could also be achieved for this case, but I have a couple of other completely separate taxonomy issues like this as well. Just starting to seem ugly. Without going the module route, I am wondering about maybe a field for the relevant templates that allows specifying the actual working (fake) URLs and building the search page to check these fields before returning results and return all the possible paths as results. Not sure how well I described that, but I think I have a working idea at least. I'll tackle this tomorrow and post when I have a working solution. -
Just thinking out loud here. The idea for this comes from the inevitable page title changes that clients want as site development comes together. For this situation, I'd love to see the page name automatically change to match any changes to the page title while the site is still in dev mode. Here's another potential option that could be overridden: http://processwire.com/talk/topic/2694-cant-change-field-to-certain-types/ I am sure there are several other things that could also be tied into a dev mode setting. Anyone have any other ideas for different behavior that would be appropriate for this setting?