Friday, April 29, 2016

How to automate your Facebook posts

Why would you want to automate your Facebook posts?

Well the answer is simple, you want to spend less time and do more, and this is when automation tools come in.
But there are several ways of automating your work with Facebook and keeping your feed alive.
First and the most common way is creating your work upfront and schedule your posts to be published based on your schedule.

But what if you want to do more? What if you run a business where you have products you would like your followers to get notified about when something new is added to your website?
Well there are some tools, like Wordpress that let you publish your content to Facebook. But what if you have your own website, your online web shop and it does not have such functionality?

How to generate Facebook posts automatically based on your content?

This was one of the reasons why Bludged.com was created. With Bludged.com you can also do a standard posts scheduling, you can link multiple Facebook feeds, you can post to your wall, or to one of the pages you manage.

Bludged.com can delivery your content to your Facebook feed


Bludged.com logo
But beside all the standard functionality with Bludged.com you can also teach the system about your web site content, tell it how your product page looks like, where is the title, price, description and product image. Then you simply tell where you want those posts to be published and which schedule to use.









Tell Bludged.com what is what on your product page

You can prepend and append title, description, price, and link to make generated posts really user friendly.

You can also preview posts to get the idea how they would look like when published to your Facebook feed

You can check your scheduled posts in the calendar
In the background Bludged.com will crawl your website, find all matching pages representing your products, generate Facebook posts for you. But it will not post anything until you approve it.
So once your web site is crawled you can log into the system and review automatically generated posts, if you like them you can simply approve all or one by one.
If you need to touch them up, you can convert them into manual posts and apply all the changes you want.
With Bludged.com you can save lots of time so you can focus on your primary business or spend time with your family and friends enjoying your life.

Is automatically generated content good?

Yes and no. If this is the only content you have - that would not be our recommendation. But if this is something you would enhance you feed with and something that would keep you social channels alive it is definitely better than no content at all.

Thursday, September 26, 2013

How to create your own image gallery plugin with JQuery

Hey guys,
Today I want to try to create an image gallery plugin with you. We have already covered how to create a lightbox plugin, so you get a nice pop-up dialog with your image adjusted in size to your screen resolution.
My next question was how to position multiple thumbnails images on my screen so they would take all space available width-wise and images in each row would have the same height. So when I have images on page with different sizes like this:

I want them to be displayed like this:

So where to begin? I don’t want to just give you my final solution, but would rather walk you through the thinking process I had.
First thing I decided to define is the minimum height and width of the image. Let’s say by default I would try to resize all images so they have height of 200px. Then I need to know the width of the container so I can do the math to see how many images I can fit into one row. And then I also want to have a little gap between my images, within the row and between rows.
So here are our plugin options:
Margin – defines the gap between images, I would put default value of 8px,
MinHeight – minimum height of the image
MinWidth – minimum width of the image (in future I would also like to prevent images to get resized to anything what would cause their width to be less than minimum width).
Okay, so we have those parameters, now what? Let’s say we have a container with width of 1000 pixels and we have 10 images in our gallery, all the same size 300x200. So how many of them can I fit in one row? Three! That’s right, but we still have extra 100 pixels left in the row. At this point we have to resize our images so they would take all the space in the row. So total allocated width would be 300pixels times 3 = 900 pixels. These 900 pixels should be converted into 1000 pixels. Our height is 200 pixels (since every image is 200 pixels high). These 200 pixels will be converted into our new height value. So new height will be equal to 200 * 1000 / 900. And the result is 222.22 pixels. So that would be our new height. And in theory since we might have different width for the images in the row (but we would always bring them to the same height) we have to re-calculate new width for every image. Same way new image width equals to original width * new image height / original height. In our case new width for each image in a row would be 300 * 222.22 / 200 = 333.33.
So the idea is clear, right? We loop through all the images in our collection, resize each to minimum height, stack up until their total width would reach our container width, adjust sizes of images in the row, and continue with the next row.
Let’s begin. Create a new project, add a folder for images (I created 8 colorful blocks of different sizes). Create new page, put your images onto the page into a div, enclose each image with a hyperlink (remember we still want to use it with our lightbox plugin eventually). This is what I have so far:
    <div id="gallery"class="gallery">
        <a href="img/1.jpg">
        <imgsrc="img/1.jpg" border="0" /></a><a href="img/2.jpg">
        <imgsrc="img/2.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/7.jpg">
        <imgsrc="img/7.jpg" border="0" /></a><a href="img/8.jpg">
        <imgsrc="img/8.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/1.jpg">
        <imgsrc="img/1.jpg" border="0" /></a><a href="img/2.jpg">
        <imgsrc="img/2.jpg" border="0" /></a><a href="img/3.jpg">
        <imgsrc="img/3.jpg" border="0" /></a><a href="img/4.jpg">
        <imgsrc="img/4.jpg" border="0" /></a><a href="img/5.jpg">
        <imgsrc="img/5.jpg" border="0" /></a><a href="img/6.jpg">
        <imgsrc="img/6.jpg" border="0" /></a><a href="img/7.jpg">
        <imgsrc="img/7.jpg" border="0" /></a><a href="img/8.jpg">
        <imgsrc="img/8.jpg" border="0" /></a>
    </div>
As you can see I have copied some images multiple times so the gallery looks more full.
Now add link to jquery library:
<script language="javascript" type="text/javascript" src="/Scripts/jquery-1.9.0.js"></script>

Now create two new files: gallery.js (I also add prefix to all my plugins so I don’t get confused if this is my plugin I’m using or someone’s from the web, so I called my file pass.gallery.gs) and gallery.css (pass.gallery.css in my case).
This is the body of our jquery plugin:
/// <reference path="jquery-1.9.0.js" />

(function ($) {
    $.fn.gallery = function (options) {
        options = $.extend({}, $.fn.gallery.defaultOptions, options);

        // our code here
    };

    $.fn.gallery.defaultOptions = {
        minwidth: 100,
        minheight: 200,
        margin: 8
    };
})(jQuery);

As you can see I already added our options there and gave them their default values. Now let’s replace our comment with actual code to make whole thing work. Let’s declare variables we will need:
        var images = []; // array of images on the page
        varimgSizes = []; // array of images' sizes which we have to calculate and then apply to our images
        varwindowWidth = $(this).width(); // container width
        var margin = options['margin']; // gap between out images
        varminwidth = options['minwidth']; // minimum width
        varminheight = options['minheight']; // minimum height
        varimagesCount = 0; // image counter

Now we need to loop through all the images in the container and get their sizes:
        $(this).children().each(function () {
            images.push($(this).children()[0]); // add image to the images array
            varimageSize = []; // define an array to hold image width and height
            imageSize.push($($(this).children()[0]).width()); // add image width
            imageSize.push($($(this).children()[0]).height()); // add image height
            imgSizes.push(imageSize); // add image size to the imgSizes array
            imagesCount++; // increment image counter
        });

Now we would also need to declare another array where we would store indexes of images we added  to each row, remaining width of the row, and index of the image in the row (to see how many images we have in the row):
        var rowArray = []; // will contain images indexes which were added to the row
        varremainingWidth = windowWidth; // remaining width of the row, be default equals to container width
        varrowIndex = 0; // number of images added to the row

Now let’s loop through all images, resize them, place into one row until we maxed out the width:
        for (var i = 0; i < imagesCount; i++) {
            var image = images[i]; // gt current image
            varimageHeight = $(image).height(); // get image height
            varimageWidth = $(image).width(); // get image width
            varnw = minheight * imageWidth / imageHeight; // new image width scaled according to minimum height
            if (nw<= remainingWidth - margin) { // check if there is enough room in the row to place the image
                remainingWidth = remainingWidth - (nw + margin); // deduct from remaining width current image width and margin
                rowArray.push(i); // add image index to array of indexes added to the row
                imgSizes[i][0] = nw; // update image size with new width
                imgSizes[i][1] = minheight; // update image size with new height
                rowIndex++; // increment image index in the row
            }
            else { // if not enough room for the image
                if (rowIndex > 0) { // check if it was the first image added, if not
                    i--; // decrement image counter so we don't skip any images
                    AdjustRowSize(rowArray); // call a function where we need to re-calculate images sizes in current row
                }
                else { // if it was first image and its' size is already greater than container width
                    nw = windowWidth - margin; // calculate new width based on container width minus margin
                    imgSizes[i][0] = nw; // update image size with new width
                    imgSizes[i][1] = nw * imageHeight / imageWidth; // calculate new height based on scaled width and update image height
                }
                rowIndex = 0; // reset rowindex
                remainingWidth = windowWidth; // reset remaining width
                rowArray = null; // reset array
                rowArray = [];
            }
        }

Alright, almost there. So now we have to implement our function AdjustRowSize to scale images up to fill the row:
        function AdjustRowSize(imgIndexes) {
            varnum = imgIndexes.length; // get number of images in the row
            vartotalWidth = 0; // declare total width variable
            for (var i = 0; i < num; i++) { // loop through all images to calculate total width
                totalWidth += imgSizes[imgIndexes[i]][0];
            }
            // calculate new row height
            varnh = (windowWidth - num * margin) * minheight / totalWidth;
            // loop through images adjusting their widths according to our new height
            for (var i = 0; i < num; i++) {
                varnw = nh * imgSizes[imgIndexes[i]][0] / imgSizes[imgIndexes[i]][1];
                imgSizes[imgIndexes[i]][0] = nw;
                imgSizes[imgIndexes[i]][1] = nh;
            }
        }

Now we still need to go back, loop through all the images in our collection and change their sizes and add margin:
        var counter = 0; // image counter
        $(this).children().each(function () {
            $($(this).children()[0]).width(imgSizes[counter][0]); // set image width
            $($(this).children()[0]).height(imgSizes[counter][1]); // set image height
            $($(this).children()[0]).css('margin', margin / 2 + 'px'); // add margin
            counter++;
        });
And our plugin is ready. Let’s add some styles to gallery.css:
.gallery
{
    display: table;
    width: 100%;
    padding: 0;
    margin: 0;
}
.gallery a
{
    margin: 0;
    padding: 0;
}
.gallery aimg
{
    margin: 0;
    padding: 0;
    float: left;
}

and now it is time to call our plugin from the page:
$(document).ready(function () {
    $('#gallery').gallery(); // call plugin

    // when window is resized we want to reposition our images as well
    $(window).resize(function () {
        $('#gallery').gallery();
    });
});

And open your page in the browser now:

Resize browser’s window:
Works as expected J
I hope you enjoyed this tutorial and if you have any questions, comments, suggestions please feel free to write a comment, we would really appreciate your input.
Cheers,
Your GPTeam

Monday, September 23, 2013

How to crop uploaded image with JQuery and ASP.NET

Hey guys,
Last week we tried to add new feature to our website, http://www.bestbars.in/, to let users upload and crop their profile pictures. Well we already had the functionality to upload pictures using uplodify plugin. But the problem we had was the images were all different size, some portrait, some landscape, some square etc. So then when we try to make our design pretty it was quite difficult. So the decision was to add cropping functionality to make users crop images into square size profile picture.
Since our website is developed using ASP.NET we started googling how to implement image cropping using JQuery and ASP.NET and came across this great tutorial “Upload and Crop Images with jQuery, JCrop and ASP.NET” from Mikesdotnetting (which is actually a cool domain name J). So thank you very much for a great tutorial Mike.
But here are a few problems we faced:
1.       We wanted to avoid postbacks when uploading and cropping images.
2.       We wanted to let people re-upload and crop image in case after cropping they did not like the results, and again, without postbacks.
With current implementation it did not work, since JCrop plugin did not recognize new loaded image and was still showing the old one. Plus we did not want to display uploaded image with 100% size, it just broke our layout, and therefore we had to touch up our math a little bit.
So avoiding any further discussions let’s dig into the code. Create new web project “AsyncImageCropping”. By default VS would create some extra stuff which is not necessary for this project, so you have a chance of either cleaning up your solution or leave it as it is. We did the cleaning, removing Account folder, About.aspx page and slightly changing Site.Master. Here is what we have so far:


Now, we need to add all required components, they are:
1.       JQuery file (jquery-1.9.0.js)
2.       Uploadify plugin (jquery.uploadify-3.1.js, uploadify.swf, uploadify.css)
3.       JCrop plugin (jquery.Jcrop.js, jquery.Jcrop.css, Jcrop.gif)
Okay, quick step aside, to make our uploadify plugin work we also need to add extra code that would take care of our files uploading and saving on the server. Don’t worry, we will get back to it later.
Now let’s prepare our form to take care of image uploading and cropping. We would need to blocks, one with profile image and a button to change it, when user clicks that button we would perform new image selection and upload and then hide this block and display a new one, where we would display new uploaded image and let our user to crop it. So second block would have an image control and a button to crop the image. Once this button is clicked we would crop the image, save it and hide this block, then display our first block with new profile image.
Here is our html code of Default.aspx:
    <div id="dvUplod">
        <div class="profileimage">
            <img id="profilePicture"alt=""src="/img/default.jpg"/></div>
        <div id="profileUpload">
            Upload</div>
    </div>
    <div id="dvCrop">
        <div class="cropimage"id="cropcontainer">
            <img src="/img/default.jpg"id="imgCrop"width="200px"/></div>
        <input type="hidden"id="X"/>
        <input type="hidden"id="Y"/>
        <input type="hidden"id="W"/>
        <input type="hidden"id="H"/>
        <div class="button"id="cropImage">
            Crop Image</div>
    </div>
And this is how it looks so far:




Add following styles to you Site.css:
.profileimage
{
    display: table;
    width: 200px;
    height: 200px;
    border: 1px solid #CCCCCC;
    padding: 8px;
    background-color: #FFFFFF;
    margin-bottom: 10px;
}
.profileimage img
{
    width: 100%;
}
.cropimage
{
    display: table;
    width: 400px;
}
.cropimageimg
{
    width: 400px;
}
.button
{
    font-size: 1em;
    padding: 8px;
    background-color: #d8188d;
    border: 1px solid #F838Ad;
    text-align: center;
    color: #FFFFFF;
    cursor: pointer;
    width: 160px;
    display: table;
    border-radius: 6px;
}

Here is the code of our Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using SD = System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace AsyncImageCropping
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
            Response.Cache.SetNoStore();
            if (Request.QueryString["action"] != null)
            {
                switch (Request.QueryString["action"])
                {
                    case "crop":
                        string profileImage = string.Empty;
                        try
                        {
                            string tempPath = "/img";
                            string path = Server.MapPath(tempPath);
                            string[] src = Request.QueryString["src"].Split('/');
                            string ImageName = src[src.Length - 1];
                            if (ImageName.IndexOf('?') >= 0)
                            {
                                ImageName = ImageName.Split('?')[0];
                            }
                            int w = Convert.ToInt32(Request.QueryString["w"]);
                            int h = Convert.ToInt32(Request.QueryString["h"]);
                            int x = Convert.ToInt32(Request.QueryString["x"]);
                            int y = Convert.ToInt32(Request.QueryString["y"]);
                            int iw = Convert.ToInt32(Request.QueryString["iw"]);
                            int ih = Convert.ToInt32(Request.QueryString["ih"]);
                            System.Drawing.Image objImage = System.Drawing.Image.FromFile(path + "/" + ImageName);
                            decimal scale = (decimal)objImage.Width / (decimal)iw;
                            x = (int)(x * scale);
                            y = (int)(y * scale);
                            w = (int)(w * scale);
                            h = (int)(h * scale);
                            byte[] CropImage = Crop(path + "/" + ImageName, w, h, x, y);
                            profileImage = ImageName.Replace("_uncropped", "");
                            using (MemoryStream ms = new MemoryStream(CropImage, 0, CropImage.Length))
                            {
                                ms.Write(CropImage, 0, CropImage.Length);
                                using (SD.Image CroppedImage = SD.Image.FromStream(ms, true))
                                {
                                    string SaveTo = path + "/" + profileImage;
                                    CroppedImage.Save(SaveTo, CroppedImage.RawFormat);
                                }
                            }
                            objImage.Dispose();
                            if (File.Exists(path + "/" + ImageName))
                            {
                                File.Delete(path + "/" + ImageName);
                            }
                        }
                        catch (Exception ex)
                        {
                        }
                        if (profileImage == string.Empty)
                            Response.Write("/img/default.jpg");
                        else
                            Response.Write("/img/" + profileImage);
                        Response.End();
                        break;
                    case "upload":
                        if (Request.Form["userToken"] != null)
                        {
                            string userId = Request.Form["userToken"];
                            string savepath = "";

                            HttpPostedFile postedFile = Request.Files["Filedata"];

                            string tempPath = "/img";
                            savepath = Server.MapPath(tempPath);
                            string filename = userId + "_uncropped.jpg";
                            if (!Directory.Exists(savepath))
                                Directory.CreateDirectory(savepath);

                            if (File.Exists(savepath + @"\" + filename))
                                File.Delete(savepath + @"\" + filename);

                            postedFile.SaveAs(savepath + @"\" + filename);
                            Response.Write(tempPath + "/" + filename);
                            Response.StatusCode = 200;
                            Response.End();
                        }
                        else
                        {
                            throw new Exception("You have to specify user ID");
                        }
                        break;
                }
            }
        }
        static byte[] Crop(string Img, int Width, int Height, int X, int Y)
        {
            try
            {
                MemoryStream ms = newMemoryStream();
                using (SD.Image OriginalImage = SD.Image.FromFile(Img))
                {
                    using (SD.Bitmap bmp = new SD.Bitmap(Width, Height))
                    {
                        bmp.SetResolution(OriginalImage.HorizontalResolution, OriginalImage.VerticalResolution);
                        using (SD.Graphics Graphic = SD.Graphics.FromImage(bmp))
                        {
                            Graphic.SmoothingMode = SmoothingMode.AntiAlias;
                            Graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            Graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                            Graphic.DrawImage(OriginalImage, new SD.Rectangle(0, 0, Width, Height), X, Y, Width, Height, SD.GraphicsUnit.Pixel);
                            bmp.Save(ms, OriginalImage.RawFormat);
                        }
                    }
                }
                return ms.GetBuffer();
            }
            catch (Exception Ex)
            {
                throw (Ex);
            }
        }
    }
}



Now add following code to the header of your Default.aspx page:
<link href="/Styles/uploadify.css"rel="stylesheet"type="text/css"/>
    <link href="/Styles/jquery.Jcrop.css"rel="stylesheet"type="text/css"/>
    <script type="text/javascript"src="Scripts/jquery-1.9.0.js"></script>
    <script type="text/javascript"src="/Scripts/jquery.uploadify-3.1.js"></script>
    <script type="text/javascript"src="Scripts/jquery.Jcrop.js"></script>
    <script language="javascript"type="text/javascript">
        $(document).ready(function () {
            $('#dvCrop').hide();           
            var userId = 'ouruserid'; // replace this one with your generic user ID
            $("#profileUpload").uploadify({
                'formData': { 'userToken': userId }, // form parameters
                'fileTypeDesc': 'Image Files',
                'fileTypeExts': '*.gif; *.jpg; *.png',
                'swf': '/scripts/uploadify.swf', // path to your swf file
                'uploader': 'Default.aspx?action=upload', // path to generic handler
                'buttonClass': 'uploadify-button',
                'buttonText': 'Change Photo',
                'width': 176,
                'multi': false,
                'auto': true,
                'onUploadComplete': function (file) {
                    $('#cropcontainer').empty(); // clear the control
                    var path = "/img/" + userId + "_uncropped.jpg" + "?timestamp=" + Date(); // get the path of the image, adding tiestamp so it is not cached
                    $('#cropcontainer').append("<img src='" + path + "' width='200px' />"); // add image control to the container
                    $('#imgCrop').attr('src', path); // set source property of the image
                    $('#dvUplod').hide();
                    $('#dvCrop').show();
                    // call JCrop function
                    $('#cropcontainer img').Jcrop({
                        onSelect: storeCoords,
                        bgColor: 'black',
                        bgOpacity: 0.3,
                        aspectRatio: 1,
                        setSelect: [10, 10, 50, 50]
                    }, function () {
                        jcrop_api = this;
                    });
                }
            });
            $("#cropImage").click(function () {
                crop($('#cropcontainer img').attr('src'), $('#X').val(), $('#Y').val(), $('#H').val(), $('#W').val());
            });
            function storeCoords(c) {
                $('#X').val(c.x);
                $('#Y').val(c.y);
                $('#W').val(c.w);
                $('#H').val(c.h);
            };
            function crop(imgSrc, x, y, h, w) {
                $.ajax({ url: '/Default.aspx?action=crop&src=' + imgSrc + '&x=' + x + '&y=' + y + '&h=' + h + '&w=' + w + '&iw=' + $('#cropcontainer img').width() + '&ih=' + $('#cropcontainer img').height(),
                    async: false,
                    success: function (data) {
                        $("#profilePicture").attr('src', data + "?timestamp=" + Date());
                        $("#dvCrop").hide();
                        $("#dvUplod").show();
                    }
                });
            }
        });
    </script>
And time to give it a go:






Let’s say you are unhappy, so let’s upload another image and crop it:



Works perfect, doesn’t it?
Okay a few tricks we did here: async calls to the server side. You might want to touch up our C# code, we did not have a goal to show you the most efficient code here, just to show a working solution you can start with J
Then on JQuery side the trick with avoiding JCrop showing cached images is to actually empty the container, add another image to it and then call JCrop function, this way it will be applied to a new DOM object and you won’t have any problems.
Why so many calculations on the server side? Well in case you don’t display your image (the one you are about to crop) in its’ original size, you will end up with wrong cropped image because your coordinates (x.y.w.h) are passed based on the image size from the screen, and your cropping is done with the original image size.
So this is it guys, play with it, optimize the code, there is a huge field for improvement!
Cheers,
Your GPTeam