Implemented

Export bounding box only

Hi,


I really would like to see the export functions to be changed. Currently the entire design area is being exported and I only want to export the items within the bounding box. All my products use the same bounding box.


See screenshot. The door is the area where the design is, the doorframe is the bounding box. When exporting the order design from WooCommerce I only want the door including all layers to be exported, not the background area.


Please include this in a next version.


Cheers,
Jaap

jpg

19 people like this idea
  • You can easily remove the layers you do not need in the order viewer and then export it.


  • Hi. 


    Of course you can delete layers, but if you have 500 orders to process... that's a lot of manual labour! And prone to make mistakes! Automation is the best way to avoid production errors. 


    And why does the plugin export the ENTIRE stage if we define a bounding box so that we can limit the users drawing area? 

    You can have a Stage with 1000 by 1000 pixels with a beautiful background, but have only a 500 by 500 pixels drawing area! Why do you have to export THE ENTIRE STAGE for production?? It makes no sense! Why? Because after the export operation the store operator has to edit the EVERY file in photoshop, crop out the 500 by 500 pixels from the image for printing production! 


    And now Imagine that with 3 initial stage layers, like your iPhone cover example, that serve only so that the user has a visual guidance while drawing inside a bounding box that will contain the final drawing for production. You will not print out those 3 initial layers! You only want the final user drawing. 


    Now imagine to process 500 orders, and having to remove 3 layers in each order!! Thats 1500 layers you have to remove, one by one!!  And manually crop 500 images, one by one after export! Try that yourself. use the iPhone cover example, try to draw a multi-layer cover for yourself, and then try to process that order, printing the final drawing in your printer WITHOUT the initial 3 layers and only the bounding box area!


    Your plugin is great for online drawing pretty Pinterest images, good for sharing in social networks by the user, but regarding to the store owner labour, and production wise, your plugin is not workflow optimized! You would get A LOT of happy plugin customers, and increase your sales, by allowing to automate some repetitive steps! You have to think that your direct clients are companies that do some kind of production!


    How can you improve your plugin?


    • create a "NO EXPORT" flag in the Product Builders Layers, and respect that flag when exporting the final image
    • Export only whats inside of the bounding box, clipping out the rest of the STAGE. For printing production we need a good hires image
    • Create a "Save as default settings" in the export options, so that you don't have to type the DPI and the scale factor FOR EVERY ORDER :(


    Are you creating a online drawing tool, or a excellent production tool?


    Best regards,


    Paulo Carrasco


  • Hi,


    I had the same problem. I didn't want to include the entire stage area in the exported image file.  I managed to solve the problem by adding the function below to the js file. You define the element that you want to use as the bounding box. It returns the dataURL of the cropped image. Then I save the file to my server using an ajax call. 


    Honestly, I don't know much about Javascript and jQuery so this might not be the best way to go about it. But it works great for me. I am using this on the jQuery version of the plugin, but it should work for WooCommerce too because I believe they use the same js file. You'd probably need to edit a template file to call the function. 


    this.getCroppedImage = function(format, backgroundColor, multiplier) {

        instance.deselectElement();

        instance.currentViewInstance.stage.setDimensions({

            width: instance.currentViewInstance.options.stageWidth,

            height: instance.currentViewInstance.options.stageHeight

        }).setZoom(1);

        var boundingObj = instance.getElementByTitle('Door'); // Title of the element that will be used as the bounding box. Everything outside of this element will be cropped out

        var myGroup = new fabric.Group();

        // ensure originX/Y 'center' is being used, as text uses left/top by default.

        myGroup.set({

            originX: 'center',

            originY: 'center'

        });

        // clone objects and put them in new group

        var i = instance.currentViewInstance.stage.getObjects().length;

        while (i--) {

            var clone = fabric.util.object.clone(instance.currentViewInstance.stage.item(i));

            clone.title = clone.title + 'clone';

            myGroup.addWithUpdate(clone).setCoords();

            clone.sendToBack;

        }

        instance.currentViewInstance.stage.add(myGroup);

        myGroup.sendToBack();

        instance.currentViewInstance.stage.renderAll();

        if (typeof boundingObj !== 'undefined') {

            var boundingRectangle = boundingObj.getBoundingRect();

        } else {

            // get bounding rect for new group

            var i = instance.currentViewInstance.stage.getObjects().length;

            while (--i) {

                var objType = instance.currentViewInstance.stage.item(i).type;

                if (objType == 'group') {

                    var boundingRectangle = instance.currentViewInstance.stage.item(i).getBoundingRect();

                }

            }

        }

        var dataURL = instance.currentViewInstance.stage.toDataURL({

            format: 'png',

            multiplier: 4,

            left: boundingRectangle.left,

            top: boundingRectangle.top,

            width: boundingRectangle.width,

            height: boundingRectangle.height,

            backgroundColor: 'transparent'

        });

        instance.currentViewInstance.stage.remove(myGroup);

        return dataURL; //returns cropped image

    };

  • I need this exact same ability. I need to export only what is within the bounding box.
    Can someone smarter than me tell me where to add this code for the wordpress plugin?

    thank you



     

  • This is a great idea! Today's industry has a very high tempo and automation is vital! At the same time one must offer the best good looking products to the customer. In this case it means that we need to offer the product in a context (for instance, a canvas in a living room) so that the customer has a "hands on" experience. To remove these extra elements that we use for sales increasing in every single order is just madness!


    I hope this function gets implemented and I look forward for it!

  • Adrienne Leverette can you please tell us where you implemented your solution?

     

  • Hi! My implementation is below. I am not an expert in jQuery or javascript, so this may not be the best way to go about it, but it works for me!

    I'm using the jQuery plugin version of FPD (in a Magento based store), but I believe it should work with the Wordpress and Opencart versions too because the FancyProductDesigner.js file appears to be the same with all of the FPD plugins.

    My modification will export only the elements that are inside of the bounding object that you specify in the this.getCroppedImage function. The cropped image is downloaded when you click the download icon in the designer. Be sure to enable the 'download' action in the plugin options so that the download icon will appear in the designer.

    Don't forget to change the name of the element you will be using as the bounding object in the this.getCroppedImage function below!

    I hope this helps you!

    ***Step 1*** Open FancyProductDesigner.js. Find the following function (starts at line 6307 in FPD 4.1):

      

    //download png, jpeg or pdf
     this.downloadFile = function(type) {
    
      if(type === 'jpeg' || type === 'png') {
    
       var a = document.createElement('a'),
        background = type === 'jpeg' ? '#fff' : 'transparent';
    
       if (typeof a.download !== 'undefined') {
    
        fpdInstance.getProductDataURL(function(dataURL) {
    
         fpdInstance.$container.find('.fpd-download-anchor').attr('href', dataURL)
         .attr('download', 'Product.'+type+'')[0].click();
    
        }, background, {format: type})
    
       }
    

     

       

    ***CHANGE it to:

    this.downloadFile = function(type) {
      //Fix for downloading large DataURI's in Chrome
      var dataURI = fpdInstance.getCroppedImage();
      var file = fpdInstance.dataURItoBlob(dataURI); 
      var url = URL.createObjectURL(file);
      
      if(type === 'jpeg' || type === 'png') {
    
       var a = document.createElement('a');
         fpdInstance.$container.find('.fpd-download-anchor').attr('href', url)
         .attr('download', 'Product.jpg')[0].click();	
    
          }
       } 


    ***Step 2*** in FancyProductDesigner.js, find "_initialize();" at the end of the file. (it's after the "this.setDimensions" function. Line 9959 in FPD 4.1 ) 

    ***ADD the following ABOVE the "_intialize();" line (after the "this.setDimensions" function)

    //Fix for downloading large DataURIs in Chrome
    this.dataURItoBlob = function(dataURI) {
        // convert base64/URLEncoded data component to raw binary data held in a string
        var byteString;
        if (dataURI.split(',')[0].indexOf('base64') >= 0)
            byteString = atob(dataURI.split(',')[1]);
        else
            byteString = unescape(dataURI.split(',')[1]);
    
        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    
        // write the bytes of the string to a typed array
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
    
        return new Blob([ia], {type:mimeString});
    };
    
    this.getCroppedImage = function(format, backgroundColor, multiplier) {
        instance.deselectElement();
        instance.currentViewInstance.stage.setDimensions({
            width: instance.currentViewInstance.options.stageWidth,
            height: instance.currentViewInstance.options.stageHeight
        }).setZoom(1);
     // Title of the element that will be used as the bounding box. Everything outside of this element will be cropped out
        var boundingObj = instance.getElementByTitle('Door'); 
        var myGroup = new fabric.Group();
        // ensure originX/Y 'center' is being used, as text uses left/top by default.
        myGroup.set({
            originX: 'center',
            originY: 'center'
        });
        // clone objects and put them in new group
        var i = instance.currentViewInstance.stage.getObjects().length;
        while (i--) {
            var clone = fabric.util.object.clone(instance.currentViewInstance.stage.item(i));
            clone.title = clone.title + 'clone';
            myGroup.addWithUpdate(clone).setCoords();
            clone.sendToBack;
        }
        instance.currentViewInstance.stage.add(myGroup);
        myGroup.sendToBack();
        instance.currentViewInstance.stage.renderAll();
        if (typeof boundingObj !== 'undefined') {
            var boundingRectangle = boundingObj.getBoundingRect();
        } else {
            // get bounding rect for new group
            var i = instance.currentViewInstance.stage.getObjects().length;
            while (--i) {
                var objType = instance.currentViewInstance.stage.item(i).type;
                if (objType == 'group') {
                    var boundingRectangle = instance.currentViewInstance.stage.item(i).getBoundingRect();
                }
            }
        }
        var dataURL = instance.currentViewInstance.stage.toDataURL({
            format: 'png',
            multiplier: 4,
            left: boundingRectangle.left,
            top: boundingRectangle.top,
            width: boundingRectangle.width,
            height: boundingRectangle.height,
            backgroundColor: 'transparent'
        });
        instance.currentViewInstance.stage.remove(myGroup);
        //returns cropped image
     return dataURL; 
    };

     



  • On a similar note and to further rationalise the work flow for certain situations I suggest adding a direct link to the original image uploaded by the customer in export options.

    When your product doesn't involve adding text or modifying the image as such, but just positioning it within a frame (bounding box) - for instance with a canvas print. The original, unprocessed image is what you will work with.

    Yes, you will need the bounding box export as a guide as you create the canvas, but you won't use that to create the canvas. Currently exporting 'single elements' only gives access to the version of the image that has been whizzed by FPD - even if the export settings are use original size and no bounding box it is the image that lives in  /wp-content/fancy_products_orders/images/ not the original which lives in /wp-content/uploads/fancy-product-uploads/ that is exported and seems to be a huge file compared to the original.

    Currently accessing /wp-content/uploads/fancy-product-uploads/ is a problem for the non-technical shop owner (like my current client). It's one of the things preventing me from using this plugin in production. 

    Surely it is not a major modification to add this to export options?

    Thank you

  • "The cropped image is downloaded when you click the download icon in the designer." - I am afraid I will not be able to implement your solution since at this moment it is not an option for us to make that option available for the user. Still, it is a great help! Thank you very much! :)

     

  • Hello Adrienne,



    I tried your javascript on my woocommerce store, but it doesn't work. I tried to export a pdf, png, jpg. Nothing works. Which kind of export file do you use?

    And I use as bounding box the item "Door" and enabled it everywhere like in your javascript, is that right? 


    Please help me, thanks in advice

  • Has there been any movement on this feature?  THIS WOULD BE HUGE for me.  Im using FPD for a large scale product, 68 inches high by 11 inches wide in some cases.  Combined with having to scale sizes up in the end to have the proper resolution, being able to just export the bounding box will make final filesizes a little smaller,and easier to produce at the end.

  • What would also be good would be for the image export of the bounding box to be e-mailed to the store owner along with the order. That way we can wait for a order to come in, send the png or pdf straight to print and apply it to the garment.

  • I agree. The least amount of work on the backend is key for my client. An global export setting or something in the settings that once you set it, every order is automatically exported at the right size, file type, and sent to your email.
  • For now, I was able to remove the actions buttons outside the stage and set the stage size to the exact size of my banners.  This has helped tremendously by keeping the file sizes down since im scaling them up so big.