Jump to content
gonzz

TIFF Support and backend jpg conversion

Recommended Posts

I'm doing an artist site and they want to be able to upload a large .tiff to their portfolio. I need to keep to a copy of the original file in the server for the art distributers, and of course serve jpg in the web front end.

I had the idea of extending the file or image upload input so that if the image is tiff, keep it, and also convert it to jpg, so I could access through something like $image->originalUrl or $image->size(100, 100)->url 

I was wondering if you thought this a good idea, or if i'm over-engineering something that could be done simply. Also, I've never extended an input, so any examples are welcome.

Thanks!

Share this post


Link to post
Share on other sites

For starters it appear that you would need ImageMagick installed on your server to make the format conversion. 

If time is an issue, I'd use two fields paired up in repeaters, or pages themselves, so the user can upload the pairing of jpeg and the tiff file. Though I understand making the user convert/upload the image is a pain point 🙂

You could add a method to the Pagefile class through a hook like this:

https://github.com/fbg13/FieldtypeFileS3/blob/master/InputfieldFileS3.module#L21

Share this post


Link to post
Share on other sites

thanks @elabx for the reply. Time is not an issue, and this is a core feature for the website. It's also key that this is easy to use, without the need to previously convert the file to png. Client is not computer savvy.

Thanks for pointing me to the s3 module. I should create the png with imagemagick, inside the ___fileAdded function (line 63) right?

..Can i create an image object on the fly? Or should I set an image field (maybe hidden) and set that in the ___fileAdded function? 

 

Please let me know if i'm not clear 🙂

thanks

Share this post


Link to post
Share on other sites

@gonzz I think the Pageimage Assistant module might help here.  At least it did for me when I wanted to convert PNG to JPG, which was helpful in my use-case for a particular site because I wanted to keep the lossless PNGs, but serve JPGs.  Not sure what the support for TIFF is.

https://modules.processwire.com/modules/pageimage-assistant/

Share this post


Link to post
Share on other sites

Converting a high-res tiff into a jpg will likely bring your server to an halt or crash it. If you did still want to go down that route - you can do this using ImageMagick, hook on the field and convert it at that point. But I would strongly encourage that you have a repeater with two fields, one for the JPG image and the other for the TIFF and do an offline conversion.

You could get your client to download a tool such as - http://www.easy2convert.com/tiff2jpg/ and let them convert it offline before upload.

Share this post


Link to post
Share on other sites

I think the Cloudinary image conversion service (they have a generous free tier) could take care of the conversion. They support TIFF. You can use their Fetch method to remotely transform your TIFFs.

  • Like 1

Share this post


Link to post
Share on other sites

I'd suggest using a file field for the tiff and on upload trigger the conversion of the image to a jpg, which is then stored in a image field. For the actual conversion I'd look outside of processwire, so you can scale independently or even more the conversion to a beefier node if needed.

Share this post


Link to post
Share on other sites

Thanks everyone for your responses, got me on track. I ended up making a module that hooks after saveReady. After some validation it does the following. Hope it helps anyone. This could be transformed into a more advanced module with options. Server needs Image Magick module installed.

// Lets generate a png image from this tiff
// imagen_tiff is a file field
$tiffImgPath = $page->imagen_tiff->first()->filename;
$tiffImgName = preg_replace('/\\.[^.\\s]{3,4}$/', '', $page->imagen_tiff->first()->name);
// Create an Imagick from the TIFF
$maxWidth = 1024;
$maxHeight = 768;
$img = new Imagick($tiffImgPath);
// Size calc
$d = $img->getImageGeometry();
$w = min($d['width'], $maxWidth);
$h = min($d['height'], $maxHeight);
// Convert image to PNG
$img->setImageFormat('png');
$img->setCompressionQuality(97);
$img->setImageResolution(72, 72);
$img->resizeImage($w,$h, Imagick::FILTER_LANCZOS, 1, true);
// Save the converted image to a cache folder
$tempDir = wire()->files->tempDir('tiffpng')->get() . $tiffImgName .'.png';
$img->writeImage($tempDir);
// I save the cached image in the image field imagen_web
$page->imagen_web->add($tempDir);

 

  • Like 1

Share this post


Link to post
Share on other sites

Obviously I don't have your complete code to check, but if you are doing on SaveReady, make sure it doesn't happen on every save - surely you only want it if the tiff has just been uploaded or replaced? Sorry if you have already taken care of this - just wanted to raise it in case.

I would probably go with hooking into InputfieldFile::fileAdded

  • Like 1

Share this post


Link to post
Share on other sites

Hi @adrian thanks for the heads up. I do have a couple of checks so it's not fired on every save, but i'm not handling the situation where the TIFF is replaced 🤔

My first attempt was using InputfieldFile::fileAdded but I wasn't sure how to get the uploaded file data and the page instance. Tried I couple of things googling around but nothing worked for me. Any working example to point me?

Share this post


Link to post
Share on other sites
3 hours ago, gonzz said:

Any working example to point me?

These are two modules that use it:

https://github.com/adrianbj/CustomUploadNames/blob/master/ProcessCustomUploadNames.module
https://github.com/matjazpotocnik/AutoSmush/blob/master/AutoSmush.module

Let me know if you can't figure out what you need from those and I can try to answer more specific questions.

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Thanks @adrian for the links. I have carefully read ProcessCustomUploadNames.module and put this together.

Here's a gist with the module I wrote: https://gist.github.com/gonzam88/2b0e8f850c469b48f4ea50fec29a4b1f

It's working for me but can't guarantee anything. Anyone is free to grab this code and continue developing into a full featured module.

Thanks for everyone's input

  • Like 2

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By carlitoselmago
      I'm building a fieldtype/inputfield to visually select a grid like Bootstrap since it's the first time coding such thing, I'm basing my code in FieldtypeColorPicker since the base structure is the same, a graphical UI helper to finally output a string as value.
      The problem is I try to save the value as something like "1,2,3" referencing the index of each column selected but it gets converted as an int value so "1,2,3" becomes "1" if input random text it gets converted as "0".
      Here is the code:
      https://github.com/carlitoselmago/FieldtypeGridSpace
      Here's an screenshot of how it looks

    • By bramwolf
      Hi Guys,

      I found that my site is producing this notice on the front end, even when $config->debug = false and also when admin is
      not even logged in. How do I keep the site from displaying this message to front end users? The notice is about a few vars
      being tested, which in this case aren't defined, how would I stop that from happing all together when testing vars? if I for instance
      wrap the $discountCode = blabla in a if($order) { ...  } statement than I'm again testing for $order which isn't a object in this case
      which throws another notice..

      This is the notice:


      Here is my current code:
      // PAD DISCOUNT CODE HOOK // First we see if we have active discount code if ($this->session->orderId) { $order = $this->pages->get($this->session->orderId); } if($product->geen_korting == 1) { $nodisc = $product->geen_korting; } else { $nodisc = $product->parent->geen_korting; } $discountCode = $this->sanitizer->selectorValue($order->pad_discount_code); $dc = $this->pages->get("template=paddiscount, title=$discountCode"); if ($dc->id) { if ($nodisc) { $discount = 0; } elseif ($dc->pad_percentage) { $discount = $newprice * ($dc->pad_percentage / 100); } } $event->return = $newprice - $discount;
      Thanks in advance 🙂
    • By EyeDentify
      Hello dear PW gurus.

      I have stumbled over a strange error that i all of sudden got when trying to upload an image to a images field on a page.
      There where images allready stored in the field that i wanted to keep, but during the upload the error apear and after that all images are gone from the field and i can´t upload any, i just get the error every time.
      I am running ProcessWire 3.0.153 dev.
      Update:
      After looking in the assets folder i find the folder for the page and the image files seems to be there including the ones i tried to upload when the error occured.
      But they don´t show up in the images field in the page editor.
       
      The error reported:
       
      SQLSTATE[01000]: Warning: 1265 Data truncated for column 'ratio' at row 1 And here is a screenshot of the event:

      The TracyDebugger Error reporting:

      I hope you fine folks could point me in a direction.
      But it seems our old pal set_time_limit() is back.

      Regards, EyeDentify
    • By shadowkyogre
      [EDIT]: After sitting down and planning out my site according to the ragged hierarchy information, I settled on the following schematics.
      /$world/$template/$content_of_template_type/... for my pretty URLs /roster/$character for my characters a generic Repeater field with depth on most content types for custom positions for child pages to connect to instead of it directly a few Repeater fields on each content that have (PageReference[1], other fields) to establish associations A few FieldsetGroups to help me manage the fields that I needed to copy across a bunch of content types. Kept the original post below for context and tagged the OP for searchability.
      ---
      Hi everyone! I'm working on a personalized worldbuilding wiki to host my art and story stuff.
      Right now my site architecture looks like...
      /$world/cosmology/$cosmology /$world/locations/$location /$world/factions/$faction /$world/history/$history /$world/species/$species /roster/$character So far the layout works, but there's one problem. I need to make sub-sections for an organization. Organizations can appear under cosmology, locations, and factions. Sounds straightforward until... I run into the problem of figuring out how to represent subfactions.
      Key factors in this are...
      Characters should be able to be part of multiple organizations Characters should have an explicit role assigned to their membership. Character pages should be able to query the organization pages to display their ranks across organizations. Editing an organization's hierarchical layout should be visible while editing the root organization page. From what I've read of the ProcessWire documentation, the best use case for each way of representing the organization's subsections are...
      Child Pages:: Works best for menu presentation and dedicated editing. PageTables:: Works if you want control over where to place the PageTable fields, but requires opening a modal for the pages you want to edit. It's also kind of like normal pages. Repeaters:: Works great for inline editing and easy control over hierarchy, but the page urls become obscure. Sections in the body field:: Works for copypasting from my note files. But it doesn't expose relationships for easy querying. It looks like my best case for this is child pages since it allows displaying suborganization in the URL easily. But also I lose out on quickly reordering and editing the child pages. Any advice for people running into similar use cases?
    • By rushy
      Hi all
      Continuing my first project where I am creating and manipulating stuff from the frontend. Till now I've always added things like images from the backend, but in this project I need to add and move images from a frontend control. This is a photo album where images are stored in albums, each album being a page containing a Pageimages array in the usual way. So what I want to know is how do I move an image from one album (page) to another in the frontend? I just need some guidance on how to approach this.  I suppose I need to do a copy and delete - but how do I copy an image or images from one page to another? What function should I use to create a new image on an existing page? I include a code snippet from the server side of my delete image request and it works fine. I'd like to implement something similar for a move and upload new image request. 
      Many thanks for any help. Paul 
      <?php namespace ProcessWire; // sanitize inputs as 1-line text $action = $sanitizer->text($input->post('action')); $instr = $sanitizer->text($input->post('input')); $sel = $input->post('selected'); // Expect JSON for image selected image list $selected = json_decode($sel); $nosel = count($selected); $response = array(); // for building JSON response switch($action) { // delete selected images case 'delete': $out = "<p>Deleted $nosel image(s)</p>"; foreach($selected as $item){ $album = $pages->get($item->album); $album->of(false); $out .= "<p>Image {$item->file} from album {$album->title}</p>"; $album->images->delete($item->file); $album->of(true); } $out .= saveUpdatedAlbums($pages, $selected); // add the response message for the delete $response['message'] = $out; break; ...... // save any album that had an image deleted function saveUpdatedAlbums($pages, $selected) { $cur = ''; $out = ''; foreach($selected as $item){ $album = $pages->get($item->album); if($album->id != $cur) { $album->of(false); $album->save('images'); $album->of(true); $cur = $album->id; $out .= "<p>Updated album {$pages->get($cur)->title}</p>"; } } return $out; }  
       
       
×
×
  • Create New...