drupal hit counter
Jerry Huang | apps and developing apps

Jerry Huang apps and developing apps

Replace TinyMCE with CKEditor and CKFinder in BlogEngine 2.0

24. April 2011 22:23 by Jerry in BlogEngine

From the first day of using BlogEngine, I'm suffering the built-in editor which is the stupid TinyMCE. I finally make up my mind to replace it after upgraded the website to the latest BlogEngine 2.0 version, because it's really slow when typing.

 

  1. download the latest ckeditor and ckfinder for ASP.NET, put CKEditor.NET.dll and CKFinder.dll to the BIN folder of your blogengine website;
    and copy the rest stuff to editors folder, like: editors/ckeditor; editors/ckfinder;
  2. disable any form of http compression, including but not limit to IIS settings (if you had enabled) and blogengine compression, otherwise ckfinder will not working
  3. edit blogengine web.config file, to disable the default http compression, search for "CompressionModule", remove or comment the whole line, i.e.
    <!--add name="CompressionModule" type="BlogEngine.Core.Web.HttpModules.CompressionModule, BlogEngine.Core"/-->
    *BTW, I spent hours to troubleshoot ckfinder, before I disable this setting, I always got an "system error" 1072896748 with ckfinder.

    By now, you should proper config ckeditor and ckfinder, make sure you are able to run those samples. You will need to set folder permission, change config files etc, for details, please refer to ckeditor and ckfinder's documentations.

    From the next step, will start to integrate blogengine with ckeditor and ckfinder.
     
  4. modify admin/HtmlEditor.ascx

[code language=ASPX]

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="htmlEditor.ascx.cs" Inherits="Admin.HtmlEditor" %>
<%@ Register Src="tinyMCE.ascx" TagName="tinyMCE" TagPrefix="uc1" %>
<%--<uc1:tinyMCE ID="TinyMCE1" runat="server" />--%>

<textarea class="ckeditor" ID="TinyMCE1" style="width:100%" rows="40" runat="server"></textarea>

<script src='/editors/ckeditor/ckeditor.js' type='text/javascript'></script>
<script src='/editors/ckfinder/ckfinder.js' type='text/javascript'></script>
<script type= "text/javascript" defer="defer">
/*
var oFCKeditor = new CKeditor( '<%=TinyMCE1.ClientID %>',null,null,"Default" ) ;
oFCKeditor.BasePath = "/editors/ckeditor/" ;
oFCKeditor.filebrowserBrowseUrl = '/editors/ckfinder/ckfinder.html';
oFCKeditor.filebrowserImageBrowseUrl = '/editors/ckfinder/ckfinder.html?type=Images';
oFCKeditor.filebrowserFlashBrowseUrl = '/editors/ckfinder/ckfinder.html?type=Flash';
oFCKeditor.ReplaceTextarea() ;
*/
CKEDITOR.replace( '<%=TinyMCE1.ClientID %>',
{
filebrowserBrowseUrl : '/editors/ckfinder/ckfinder.html',
filebrowserImageBrowseUrl : '/editors/ckfinder/ckfinder.html?type=Images',
filebrowserFlashBrowseUrl : '/editors/ckfinder/ckfinder.html?type=Flash',
filebrowserUploadUrl : '/editors/ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Files',
filebrowserImageUploadUrl : '/editors/ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Images',
filebrowserFlashUploadUrl : '/editors/ckfinder/core/connector/aspx/connector.aspx?command=QuickUpload&type=Flash',
filebrowserWindowWidth : '1000',
filebrowserWindowHeight : '700'
});
</script>

[/code]

 

  1. modify admin/HtmlEditor.ascx.cs

[code language=C#]

// --------------------------------------------------------------------------------------------------------------------
// <summary>
//   The admin_html editor.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Admin
{
    using System.Web.UI;

    /// <summary>
    /// The admin_html editor.
    /// </summary>
    public partial class HtmlEditor : UserControl
    {
        #region Properties

        /// <summary>
        /// Gets or sets TabIndex.
        /// </summary>
       
        public short TabIndex
        {
         /*
            get
            {
                return this.TinyMCE1.TabIndex;
            }

            set
            {
                this.TinyMCE1.TabIndex = value;
            }*/
            get { return 0; }
      set { }

        }

        /// <summary>
        /// Gets or sets Text.
        /// </summary>
        public string Text
        {
            get
            {
                return this.TinyMCE1.Value;
            }

            set
            {
                this.TinyMCE1.Value = value;
            }
        }
       
        public string EditorID
        { get{return TinyMCE1.ClientID;}}

        #endregion
    }
}

[/code]

  1. modify admin/Posts/Add_entry.aspx, should be 2 places in AutoSave and SavePost javascript functions
    replace "tinyMCE.activeEditor.getContent();" with "CKEDITOR.instances['<%=txtContent.EditorID %>'].getData()"
  2. modify admin/Posts/EditPage.aspx, similar with above, but only 1 place in SavePage function
    change  var content = tinyMCE.activeEditor.getContent(); to
    var content = CKEDITOR.instances['<%=txtContent.EditorID %>'].getData();
  3. modify CheckAuthentication function in editors/ckfinder/config.ascx
    to integrate the blogengine authentication, otherwise everyone will be able to upload file to your user file folder if you simply return true:
    return Page.User.Identity.IsAuthenticated;
  4. It's not realted to integration, but it's a security issue that most people forgot,
    * to remove all samples in the _samples folder, as well as the _source folder
    * it's a good practice to follow the ckfinder's suggestion: in IIS, set Execute Permissions to "none" in the properties of the user files folder (ie. upload folder)

A WinForm Image Selector Control

24. April 2011 12:35 by Jerry in UI

First of all, I have to point out that the control is far from perfect. So far it's just workable for my Smart Dial Agent. If you want to make use of it, you will need to do your own customization or make it flexible by using control property. You are welcome to send me back an enhanced version if you have done some works on itLaughing

Before going into technical details, let's have a look how it works

The rectangle with black border in the photo is the selector, while the image on the left is the target cropped photo. The selector could move or resize, but it couldn't smaller than 96*96.

The original source code is from a Chinese website (I forgot which one now, sorry) and base on .Net Framework 1.1. It doesn't work probably at the beginning, I'm not sure if relates to the framework. I just fix some problems and make some changes to fit my needs.

Usage:

New a Form in Visual Studio, drap a PictureBox and then place a Selector control on top of the PictureBox. drap another PictureBox as target image. Trigger the Mouse-Up event to retrieve target image. Below is a sample:

[code language=C#]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SmartDialAgent.Utils;
using SmartDialAgent.Controls;

namespace SmartDialAgent
{
    public partial class CropImage : Form
    {
        public CropImage()
        {
            InitializeComponent();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                dlg.Filter = "Images|*.jpg;*.jpeg;*.png;*.bmp";
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    LoadImage(dlg.FileName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void LoadImage(string path)
        {
            Image img = Image.FromFile(path);
            if (img.Width > 640 || img.Height > 480)
            {
                //source img too big, adjust size
                int x1, y1;//base on width
                if (img.Width > 640)
                {
                    x1 = 640;
                    y1 = 640 * img.Height / img.Width;
                }
                else
                {
                    x1 = img.Width;
                    y1 = img.Height;
                }
                int x2, y2;//base on height
                if (img.Height > 480)
                {
                    y2 = 480;
                    x2 = 480 * img.Width / img.Height;
                }
                else
                {
                    x2 = img.Width;
                    y2 = img.Height;
                }
                //choose the smaller pairs
                if (x1 > x2)
                {
                    img = img.GetThumbnailImage(x2, y2, null, new IntPtr());
                }
                else
                {
                    img = img.GetThumbnailImage(x1, y1, null, new IntPtr());
                }
            }
            pbImage.Image = img;
            pbImage.Width = img.Width;
            pbImage.Height = img.Height;
            int len;
            if (img.Width > img.Height)
                len = img.Height;
            else
                len = img.Width;
            if ((len / 2) > 96)
            {
                pictureBoxSelection1.Width = len / 2;
                pictureBoxSelection1.Height = pictureBoxSelection1.Width;
            }
            else
            {
                pictureBoxSelection1.Width = 96;
                pictureBoxSelection1.Height = 96;
            }
            pictureBoxSelection1.PictureBox = pbImage;
            groupBox1.Width = pbImage.Width;
            groupBox1.Height = pbImage.Height;
            pictureBoxSelection1.Left = pbImage.Left;
            pictureBoxSelection1.Top = pbImage.Top;
            this.GetTargetImage();

        }


        private void GetTargetImage()
        {
            Image img;
            if (pictureBoxSelection1.SelectedImage == null)
            {
                img = PictureBoxSelector.Crop(pbImage.Image, pictureBoxSelection1.Size, pictureBoxSelection1.Left - pbImage.Left, pictureBoxSelection1.Top - pbImage.Top);
            }
            else
            {
                img = pictureBoxSelection1.SelectedImage;
            }
             if (img != null && img.Width > 96)
                    img = img.GetThumbnailImage(96, 96, null, new IntPtr());
                pbTarget.Image = img;
        }

        private void pictureBoxSelection1_MouseUp(object sender, MouseEventArgs e)
        {
            GetTargetImage();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }
        private Image Image
        {
            get
            {
                return pbTarget.Image;
            }
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }

        public static Image GetCropImage(string path)
        {
            using (CropImage frm = new CropImage())
            {
                frm.LoadImage(path);
                if (frm.ShowDialog() == DialogResult.OK)
                {
                    return frm.Image;
                }
                else
                    return null;
            }
        }

 

    }
}

[/code]

 

Control source code:

[code language=C#]

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using SmartDialAgent.Utils;
using System.Drawing.Drawing2D;

namespace SmartDialAgent.Controls
{

    public class PictureBoxSelector : System.Windows.Forms.Control
    {

        private Color _BorderColor = new Color();
        //private Color _BackColor = new Color();
        private bool _ReSizeble;
        private Point _SelfLocation = new Point();
        private Point _MouseLocation = new Point();
        private int _SelfWidth;
        private int _SelfHeight;
        private int _SelectSelctedIndex;//0-8,0:SizeAll
        private Rectangle _rectLeftSelector = new Rectangle();
        private Rectangle _rectTopSelector = new Rectangle();
        private Rectangle _rectRightSelector = new Rectangle();
        private Rectangle _rectBottomSelector = new Rectangle();
        private Rectangle _rectLeftTopSelector = new Rectangle();
        private Rectangle _rectRightTopSelector = new Rectangle();
        private Rectangle _rectRightBottomSelector = new Rectangle();
        private Rectangle _rectLeftBottomSelector = new Rectangle();
        private System.ComponentModel.Container components = null;
        public PictureBoxSelector()
        {
            InitializeComponent();
        }
        [DefaultValue("Black"), Description("color of the border"), Category("Appearance")]
        public Color BorderColor
        {
            get
            {
                // Insert code here.
                return _BorderColor;
            }
            set
            {
                _BorderColor = value;
                this.Invalidate();
            }
        }
        //[DefaultValue("Control"), Description("Background color"), Category("Appearance")]
        //public override Color BackColor
        //{
        //    get
        //    {
        //        // Insert code here.
        //        return _BackColor;
        //    }
        //    set
        //    {
        //        _BackColor = value;
        //        this.Invalidate();
        //    }
        //}
        [DefaultValue(false), Description("Indicates the control coud be moved and resized"), Category("Behavior")]
        public bool ReSizeble
        {
            get
            {
                // Insert code here.
                return _ReSizeble;
            }
            set
            {
                _ReSizeble = value;
                this.Invalidate();
            }
        }

        [Description("Selected area"), Category("Behavior")]
        public Rectangle SelectedRectangle
        {
            get
            {
                Rectangle selectRectangler = new Rectangle();
                selectRectangler.X = this.Location.X ;
                selectRectangler.Y = this.Location.Y ;
                selectRectangler.Height = this.Height ;
                selectRectangler.Width = this.Width ;
                return selectRectangler;
            }

        }
        /// <summary>
        /// the selected image
        /// </summary>
        public Image SelectedImage { get; private set; }

        public static Bitmap Crop(Image image, Size targetSize, int x, int y)
        {
            try
            {
                Bitmap bmp = new Bitmap(targetSize.Width, targetSize.Height);//, PixelFormat.Format24bppRgb);
                bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);

                Graphics gfx = Graphics.FromImage(bmp);
                gfx.SmoothingMode = SmoothingMode.AntiAlias;
                gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
                gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
                gfx.DrawImage(image, new Rectangle(0, 0, targetSize.Width, targetSize.Height),
                    x, y, targetSize.Width, targetSize.Height, GraphicsUnit.Pixel);

                gfx.Dispose();

                return bmp;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// repaint the background by copying crop image from parent picturebox
        /// </summary>
        /// <param name="e"></param>
        private void RepaintBackground(PaintEventArgs e)
        {
            if (PictureBox != null && PictureBox.Image!=null)
            {
                Image img = Crop(PictureBox.Image, Size, Left - PictureBox.Left, Top - PictureBox.Top);
                if (img != null)
                    e.Graphics.DrawImage(img, 0, 0, Width, Height);
                SelectedImage = img;
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            RepaintBackground(e);
            ReDrawControl(e.Graphics);
        }
        private void DrawSelector(Graphics graphics)
        {
            SolidBrush SelectorPen = new SolidBrush(Color.White);
            Pen borderPen = new Pen(this._BorderColor, 1);
            try
            {
                //solid
                PointF[] LeftPoints = getPointF(0, this.Height / 2 - 3, 6, 6);
                graphics.FillClosedCurve(SelectorPen, LeftPoints);

                PointF[] TopPoints = getPointF(this.Width / 2 - 3, 0, 6, 6);
                graphics.FillClosedCurve(SelectorPen, TopPoints);

                PointF[] RightPoints = getPointF(this.Width - 7, this.Height / 2 - 3, 6, 6);
                graphics.FillClosedCurve(SelectorPen, RightPoints);

                PointF[] BottomPoints = getPointF(this.Width / 2 - 3, this.Height - 7, 6, 6);
                graphics.FillClosedCurve(SelectorPen, BottomPoints);
               
                //remove the 4 solid resize selectors, I don't need it, if you need to, add them back
                //PointF[] LeftTopPoints = getPointF(0, 0, 6, 6);
                //graphics.FillClosedCurve(SelectorPen, LeftTopPoints);

                //PointF[] RightTopPoints = getPointF(this.Width - 7, 0, 6, 6);
                //graphics.FillClosedCurve(SelectorPen, RightTopPoints);

                //PointF[] RightBottomPoints = getPointF(this.Width - 7, this.Height - 7, 6, 6);
                //graphics.FillClosedCurve(SelectorPen, RightBottomPoints);

                //PointF[] LeftBottomPoints = getPointF(0, this.Height - 7, 6, 6);
                //graphics.FillClosedCurve(SelectorPen, LeftBottomPoints);
                //borders
                int border = 6;
                _rectLeftSelector.X = 0;
                _rectLeftSelector.Y = this.Height / 2 - 3;
                _rectLeftSelector.Height = border;
                _rectLeftSelector.Width = border;
                graphics.DrawRectangle(borderPen, _rectLeftSelector);

                _rectTopSelector.X = this.Width / 2 - 3;
                _rectTopSelector.Y = 0;
                _rectTopSelector.Height = border;
                _rectTopSelector.Width = border;
                graphics.DrawRectangle(borderPen, _rectTopSelector);

                _rectRightSelector.X = this.Width - 7;
                _rectRightSelector.Y = this.Height / 2 - 3;
                _rectRightSelector.Height = border;
                _rectRightSelector.Width = border;
                graphics.DrawRectangle(borderPen, _rectRightSelector);

                _rectBottomSelector.X = this.Width / 2 - 3;
                _rectBottomSelector.Y = this.Height - 7;
                _rectBottomSelector.Height = border;
                _rectBottomSelector.Width = border;
                graphics.DrawRectangle(borderPen, _rectBottomSelector);
               
                //remove the 4 solid resize selectors, I don't need it, if you need to, add them back
                //_rectLeftTopSelector.X = 0;
                //_rectLeftTopSelector.Y = 0;
                //_rectLeftTopSelector.Width = border;
                //_rectLeftTopSelector.Height = border;
                //graphics.DrawRectangle(borderPen, _rectLeftTopSelector);

                //_rectRightTopSelector.X = this.Width - 7;
                //_rectRightTopSelector.Y = 0;
                //_rectRightTopSelector.Width = border;
                //_rectRightTopSelector.Height = border;
                //graphics.DrawRectangle(borderPen, _rectRightTopSelector);

                //_rectRightBottomSelector.X = this.Width - 7;
                //_rectRightBottomSelector.Y = this.Height - 7;
                //_rectRightBottomSelector.Width = border;
                //_rectRightBottomSelector.Height = border;
                //graphics.DrawRectangle(borderPen, _rectRightBottomSelector);

                //_rectLeftBottomSelector.X = 0;
                //_rectLeftBottomSelector.Y = this.Height - 7;
                //_rectLeftBottomSelector.Width = border;
                //_rectLeftBottomSelector.Height = border;
                //graphics.DrawRectangle(borderPen, _rectLeftBottomSelector);
            }
            catch (Exception E)
            {
                throw E;
            }
            finally
            {
                SelectorPen.Dispose();
                borderPen.Dispose();
            }

        }
        private void ReDrawControl(Graphics graphics)
        {

            try
            {

                //draw background
               
                //graphics.Clear(this._BackColor);
                //SolidBrush backPen=new SolidBrush(this._BackColor);
                //PointF point1 = new PointF(1,1);
                //PointF point2 = new PointF(this.Width-2,1);
                //PointF point3 = new PointF(this.Width-2,this.Height-2);
                //PointF point4 = new PointF(1,this.Height-2);
                //PointF[] points = {point1, point2, point3, point4};
                //graphics.DrawImage(ImageUtils.CropImage(this.PictureBox, new Rectangle(Left, Top, Width, Height)),);
                //graphics.FillClosedCurve(backPen, points);
               
                //border
                Rectangle rectBorder = new Rectangle();
                Pen borderPen = new Pen(this._BorderColor, 1);
                rectBorder.X = 0;
                rectBorder.Y = 0;
                rectBorder.Height = this.Height - 1;
                rectBorder.Width = this.Width - 1;
                graphics.DrawRectangle(borderPen, rectBorder);
                //selector
                if (_ReSizeble)
                {
                    DrawSelector(graphics);
                }
            }
            catch (Exception E)
            {
                throw E;
            }
            finally
            {
                graphics.Dispose();
            }
        }
        public PictureBox PictureBox { get; set; }
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            this.RepaintBackground(e);
        }


        private PointF[] getPointF(int x, int y, int Width, int Height)
        {
            PointF point1 = new PointF(x, y);
            PointF point2 = new PointF(x + Width, y);
            PointF point3 = new PointF(x + Width, y + Height);
            PointF point4 = new PointF(x, y + Height);
            PointF[] points = { point1, point2, point3, point4 };
            return points;
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region generated by Visual Studio

        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
            this.Resize += new EventHandler(ShapeEx_Resize);
            this.MouseDown += new MouseEventHandler(ShapeEx_MouseDown);
            this.MouseMove += new MouseEventHandler(ShapeEx_MouseMove);
            this.MouseLeave += new EventHandler(ShapeEx_MouseLeave);
            this.MouseUp += new MouseEventHandler(ShapeEx_MouseUp);
            this.Move += new EventHandler(Selection_Move);
            this._BorderColor = Color.Black;
            //this._BackColor = Color.Transparent;//.FromName("Control");
            this._ReSizeble = false;
            this._SelectSelctedIndex = -1;
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);  
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);  

        }
        #endregion

        private void ShapeEx_Resize(object sender, EventArgs e)
        {
            //hard code 96, the smallest size could be,
            //will be better if use a Size property
            if (this.Width < 96 || this.Height < 96)
            {
                this.Width = 96;
                this.Height = 96;
            }
            this.Invalidate();
        }

 

        private void ShapeEx_MouseDown(object sender, MouseEventArgs e)
        {
            if (_ReSizeble)
            {
                if (_rectLeftSelector.Contains(e.X, e.Y) || _rectRightSelector.Contains(e.X, e.Y) || _rectTopSelector.Contains(e.X, e.Y) || _rectBottomSelector.Contains(e.X, e.Y) || _rectLeftTopSelector.Contains(e.X, e.Y) || _rectRightTopSelector.Contains(e.X, e.Y) || _rectRightBottomSelector.Contains(e.X, e.Y) || _rectLeftBottomSelector.Contains(e.X, e.Y))
                {
                    if (_rectLeftTopSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNWSE;
                        this._SelectSelctedIndex = 1;
                    }

                    if (_rectTopSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNS;
                        this._SelectSelctedIndex = 2;
                    }
                    if (_rectRightTopSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNESW;
                        this._SelectSelctedIndex = 3;
                    }
                    if (_rectRightSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeWE;
                        this._SelectSelctedIndex = 4;
                    }
                    if (_rectRightBottomSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNWSE;
                        this._SelectSelctedIndex = 5;
                    }
                    if (_rectBottomSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNS;
                        this._SelectSelctedIndex = 6;
                    }
                    if (_rectLeftBottomSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeNESW;
                        this._SelectSelctedIndex = 7;
                    }
                    if (_rectLeftSelector.Contains(e.X, e.Y))
                    {
                        this.Cursor = Cursors.SizeWE;
                        this._SelectSelctedIndex = 8;
                    }

                }
                else
                {
                    this.Cursor = Cursors.SizeAll;
                    this._SelectSelctedIndex = 0;
                }
                this._SelfLocation.X = this.Location.X;
                this._SelfLocation.Y = this.Location.Y;
                this._MouseLocation.X = Cursor.Position.X;
                this._MouseLocation.Y = Cursor.Position.Y;
                this._SelfWidth = this.Width;
                this._SelfHeight = this.Height;
            }
        }

        private void ShapeEx_MouseMove(object sender, MouseEventArgs e)
        {
           
            //move and resize
            //since I removed 4 resize selector, it will only fall into cases like 2,4,6,8,etc
            switch (this._SelectSelctedIndex)
            {
                case 0:
                    this.Location = new Point(Cursor.Position.X - (_MouseLocation.X - _SelfLocation.X), Cursor.Position.Y - (_MouseLocation.Y - _SelfLocation.Y));
                    break;
                case 1:
                    this.Height = this._SelfHeight - (Cursor.Position.Y - _MouseLocation.Y);
                    this.Width = this._SelfWidth - (Cursor.Position.X - _MouseLocation.X);
                    this.Location = new Point(Cursor.Position.X - _MouseLocation.X + _SelfLocation.X, Cursor.Position.Y - _MouseLocation.Y + _SelfLocation.Y);
                    break;
                case 2:
                    this.Height = this._SelfHeight - (Cursor.Position.Y - _MouseLocation.Y);
                    this.Width = Height;//remove if Width<> Height
                    this.Location = new Point(_SelfLocation.X, Cursor.Position.Y - _MouseLocation.Y + _SelfLocation.Y);
                    break;
                case 3:
                    this.Height = this._SelfHeight - (Cursor.Position.Y - _MouseLocation.Y);
                    this.Width = this._SelfWidth + (Cursor.Position.X - _MouseLocation.X);
                    this.Location = new Point(_SelfLocation.X, Cursor.Position.Y - (_MouseLocation.Y - _SelfLocation.Y));
                    break;
                case 4:
                    this.Width = this._SelfWidth + (Cursor.Position.X - _MouseLocation.X);
                    Height = Width;//remove if Width<> Height
                    break;
                case 5:
                    this.Height = this._SelfHeight + (Cursor.Position.Y - _MouseLocation.Y);
                    this.Width = this._SelfWidth + (Cursor.Position.X - _MouseLocation.X);
                    break;
                case 6:
                    this.Height = this._SelfHeight + (Cursor.Position.Y - _MouseLocation.Y);
                    Width = Height;//remove if Width<> Height
                    break;
                case 7:
                    this.Height = this._SelfHeight + (Cursor.Position.Y - _MouseLocation.Y);
                    this.Width = this._SelfWidth - (Cursor.Position.X - _MouseLocation.X);
                    this.Location = new Point(Cursor.Position.X - _MouseLocation.X + _SelfLocation.X, _SelfLocation.Y);
                    break;
                case 8:
                    this.Width = this._SelfWidth - (Cursor.Position.X - _MouseLocation.X);
                    Height = Width;//remove if Width<> Height
                    this.Location = new Point(Cursor.Position.X - _MouseLocation.X + _SelfLocation.X, _SelfLocation.Y);
                    break;
            }
 
           
        }

        private void Selection_Move(object sender, EventArgs e)
        {
            Invalidate();
        }

        private void ShapeEx_MouseLeave(object sender, EventArgs e)
        {
            this.Cursor = Cursors.Default;
            this._SelectSelctedIndex = -1;
            Invalidate();
        }

        private void ShapeEx_MouseUp(object sender, MouseEventArgs e)
        {
            this.Cursor = Cursors.Default;
            this._SelectSelctedIndex = -1;
            Invalidate();
        }

    }
}

[/code]

As I stated at the beginning, this is a naive version, below is a list of known issues

  1. when the selector is out of the parent PictureBox, the area of out of PictureBox can't be blank, but some remaining pixes with lagacy color (I don't know how to say, you will see if you run it). Currently I use a groupBox as a container for the PictureBox so that it doesn't look so ugly. Ideally the selector is not allowed to move out size of parent PictureBox
  2. should proper control the PictureBox property, should throw error if the property is null, or force the control parent is PictureBox
  3. current version seems not very efficient, the image is flicking when moving the selector

 

source code also available here:

PictureBoxSelection.cs (19.17 kb)

Smart Dial Agent

20. April 2011 01:40 by Jerry in Smart Dial

finally, Smart Dial Agent now support directly import contacts from Live and Google.Cool

select "Import" from menu

 

Simply input user name and password, then import...

IP CAM Controller is ranking top 54

19. April 2011 11:12 by Jerry in IP CAM

In the Music & Video category. Not bad as a new app just published one monthCool

Live contacts import coming soon

19. April 2011 01:18 by Jerry in Smart Dial

A big progress in directly importing (not via CSV) Live contacts, including both Messenger contacts and Live Address Book contacts!

New Smart Dial Agent is coming very soonCool

Hmmm... maybe provide the same functionality in WP7 as well..

 

Smart Dial Agent update

18. April 2011 01:51 by Jerry in Smart Dial

For today's update, the Import function supports directly download all contacts from Gmail, no longer need to export to CSV file.Laughing

Working on direct export Live's contacts...looks like much harderInnocent

Smart Dial published

16. April 2011 10:31 by Jerry in Smart Dial

- search contacts by numbers, names and even Pinyin for Chinese characters;
- define the candidate keyword of each contact by yourself
- numbers in each result contact are sorted by best match
- edit before call/SMS and pre-stored prefix
- sync your contacts between your phone and computers

go here for details: http://www.jerryhuang.net/page/Smart-Dial.aspx

How to export contacts from Gmail

16. April 2011 00:08 by Jerry in Smart Dial

1) logon with your gmail ID on www.gmail.com, and click "Contacts"

2)click "More actions" and select "Export"

3) Choose "All contacts" and "Outlook CSV" format. It's not a must, but if you choose Outlook format you will able to use the default "Windows Live" srouce type for data conversion later on. Then click "Export"

 

4) click "Save", done.

How to export your Live contacts

15. April 2011 23:52 by Jerry in Smart Dial

1) login www.hotmail.com with your Live ID, and then click "Contacts"

 

2) click "Manage" and choose "Export"

3) input the urgly stupid 8 digit characters as it shown, then click "Export"

 

4) wait for a while (sometimes it needs a few minutes if you have many contacts and your network connection happed to be slow), you will see a download dialog, click "Save" to store the folder to your computer, "My documents" would be a nice choice. Sorry for the screenshot has to be Chinese. I don't have an english Windows on hand. Probably a good start for learning Chinese, lol

Serializing image in WP7

15. April 2011 03:23 by Jerry in Windows Phone Development

This post is to celebrate my 2nd app - Smart Dial has been approved in marketplace.

None of the build in imaging classes in Windows Phone or Silverlight is serializable, that's why I have to build my own class.Cool

To serialize a custom object, the class need to implement IXmlSerializable interface. So my class inherits BitmapSource and then implement IXmlSerializable.

The idea of the whole thing is actually pretty simple. Just covert the image into byte array, and then transform to Base64 string, and backward for deserialization. With such approach, we are able to ship the image within XML(i.e. pure text). This is how my app (Smart Dial) to transfer contact photos between WP7 and server.

 Since my Smart Dial solution consists 2 client programs in handset device and desktop computer, I made the class compatible with both silverlight (WP7) and Winform (base on .Net 3.5). However, somehow I can't load the image source to itself in winform version. The BitmapSource in winform doesn't contain the SetSource method, I have use a stupid property (Source).

Simply copy and paste and compile and enjoyLaughing

[code language=C#]   

using System;
using System.Windows;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Media.Imaging;
using System.Xml.Schema;
using System.Xml;
 #if !SILVERLIGHT
using System.Drawing;
#endif
namespace SmartDial.Data
{

    public class SerializableImage : BitmapSource, IXmlSerializable
    {
 #if SILVERLIGHT
        private string ImageToString(BitmapSource image)
#else
        private string ImageToString(Bitmap image)
#endif
        {
           
            byte[] byteArray;

            using (MemoryStream stream = new MemoryStream())
            {
 #if SILVERLIGHT
                WriteableBitmap bmp = new WriteableBitmap((BitmapSource)image);
                bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
                byteArray = stream.ToArray();
#else
                image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                stream.Flush();
                byteArray = stream.ToArray();
#endif
              
            }

            return Convert.ToBase64String(byteArray);
        }
        public SerializableImage() { }
 #if SILVERLIGHT
       
        public SerializableImage(Uri uri)
        {

            using (Stream stream = Application.GetResourceStream(uri).Stream)
            {
                this.SetSource(stream);
            }
        }

#else
        public SerializableImage(Image image)
        {
            this.Source = (Bitmap)image;
        }
        protected override Freezable CreateInstanceCore() { return new SerializableImage(); }
        public Bitmap Source { get;  set; }
#endif

        private void StringToImage(string imageString)
        {
            if (imageString == null)
                throw new ArgumentNullException("imageString");

            byte[] array = Convert.FromBase64String(imageString);
 #if SILVERLIGHT
            this.SetSource (new MemoryStream(array));
#else
            Source = (Bitmap)Image.FromStream(new MemoryStream(array));
#endif
          

        }


        #region IXmlSerializable Members

        public XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(XmlReader reader)
        {


            if (reader.IsEmptyElement || !reader.Read())
            {
                return;
            }
            XmlSerializer imgSerializer = new XmlSerializer(typeof(string));
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement("SerializedImage");

                string img = (string)imgSerializer.Deserialize(reader);
                reader.ReadEndElement();

                reader.MoveToContent();

                StringToImage(img);
            }
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            XmlSerializer imgSerializer = new XmlSerializer(typeof(string));

            writer.WriteStartElement("SerializedImage");
 #if SILVERLIGHT
            string img = ImageToString( this);
#else
            string img = ImageToString(this.Source);
#endif
            imgSerializer.Serialize(writer, img);
            writer.WriteEndElement();

        }

        #endregion
    }
}

[/code]