Home>

For picture editing,The most important thing is to be able to crop the picture.The main implementation is divided into two parts,One part is that the front end uses js for crop area selection.The second part is background processing using php.Let me share with you now.

The following is an introduction to the functions of picture cropping I wrote myself:

Can be dragged with the mouse,Generate crop box

You can change the size of the crop box

Click OK.Returns cropped data

principle

There are two ways to complete the crop:

1.Add drag and drop events using html5

2. Traditional methods,Using mouse events,mousedown, mousemove, etc.

Here we use method 2.

Formation of cropped areas

To crop, you first need to form a crop area.The formation of this cropped area can be related to the distance moved by the mouse.How far the mouse moves,The cropped area is as large as possible.As shown below:

As shown in the figure above, the horizontal and vertical movement distances of the mouse form the width and height of the cropped area.

And how to calculate the distance between horizontal and vertical movement?When we click the mouse,Will be able to passevent The event object gets the mouse click position,While moving the mouse,Also viaevent Get the mouse position,By changing the mouse position twice,You can get the mouse movement distance.

Get the properties of the mouse position are clientx and clienty

Formation of shadow areas

The next step is to draw the shadow area.The part of the cropped picture other than the cropped area,All belong to the shaded area,It is also possible not to draw the area,This area is drawn to allow the user to see the cropped area more clearly.

I divided the area into four parts:See distribution below:

What about the area?At this time, the offset value of the dom element is used.The left offset value of the cropped area minus the left offset value of the image itself is the width of the left shadow.Use the cropped area's top offset value to subtract the image's top offset value,Equal to the height of the top shadow.As shown below:

After getting the values ​​of left shadow and top shadow,You can calculate the properties of other shadows through these two.

There are two ways to offset the image

1. Use offsetleft and offsettop values. Disadvantages If the dom element has a border margin and other values, these values ​​will be calculated.

2. Get the css attribute of dom.

Both methods have their own drawbacks,Use as appropriate

Clipping out of bounds

The calculation of the cropped area is calculated by moving the mouse,Therefore, the cropped area may be out of bounds.This situation is divided into two types:

1. Out of bounds during cutting

2. Out of bounds when moving crop area

Then let's talk about how to prevent cross-border.

Clipping out of bounds

What is out of bounds when cropping?It is the mouse dragging area beyond the return of the picture,Formed a transboundary,As shown below:

For this kind of out-of-bounds, you need to determine that the position of the right side of the cropped area relative to the left side of the browser cannot exceed the position on the right side of the picture that is equivalent to the left side of the browser;At the same time, the position of the bottom of the cropping area relative to the top of the browser cannot exceed the position of the bottom of the picture corresponding to the top of the browser.Still drawing to illustrate:

Whentx>= px to force the value of tx to a fixed value.

tx and px calculation methods,Assuming the cropped area isotailor , image areaopicture :

tx=otailor.offsetwidth + otailor.offsetleft;
px=opicture.offsetwidth + opicture.offsetleft;

In the same way, you can cross the left side as described above.The upper side is out of bounds,The lower side is restricted,I won't go into details.

Mobile cross-border

Moving out of bounds means that a cropped area has been formed,However, an out-of-bounds occurred when the crop area was moved by the mouse.This understanding is relatively simple,I wo n’t draw a picture.This out of bounds is consistent with the dom dragging out of bounds,Judge by judging whether the mouse moves beyond the picture area.

Principles and problems are solved,Now let's finish the actual function.

Ready to work

Before doingDo some preparations,The knife is not cut by firewood.

Web layout preparation

The key code of the page layout part is as follows:

<img src="./images/img_2.jpg">
<div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<!-Left->
<div></div>
<!-On->
<div></div>
<!-Right->
<div></div>
<!-Down->
<div></div>
<button>OK</button>

Whereimg_box represents the cropped area.outer indicates the shaded area.Whileimg_box The div inis the border of the cropped area

The style controls are as follows:

* {
  padding:0;
  margin:0;
}
body {
  background:#454545;
}
.main {
  width:500px;
  margin:50px auto;
}
.main img {
  width:500px;
  position:absolute;
  left:450px;
  top:50px;
}
.img_box {
  overflow:hidden;
  position:absolute;
  top:0px;
  left:0px;
  z-index:2;
}
.outer {
  overflow:hidden;
  background:#000;
  opacity:0.4;
  position:absolute;
  top:0px;
  left:0px;
  z-index:0;
}
.box_border1,.box_border2,.box_border3,.box_border4 {
  opacity:0.5;
}
.box_border1 {
  background:url (./images/border-anim-v.gif) repeat-y left top;
}
.box_border2 {
  background:url (./images/border-anim-h.gif) repeat-x left top;
}
.box_border3 {
  background:url (./images/border-anim-v.gif) repeat-y right top;
}
.box_border4 {
  background:url (./images/border-anim-h.gif) repeat-x right bottom;
}
.box_handle {
  background:#fff;
  border:1px solid #000;
  opacity:0.5;
}
.confrim {
  width:80px;
  height:35px;
}

The layout effect is as follows:

General function

Complete picture cropping,Through the above principles,You can know that you need to get a lot of label objects and CSS properties of labels, so you can write general functions,Get these values ​​better.as follows:

dom get function

/* Get jquerydom-like * /
function $(dom) {
   function getdom (dom) {
    var str=dom.charat (0);
    switch (str) {
      case ".":
        this.ele=document.getelementsbyclassname (dom.substring (1)) | null;
        break;
      case "#":
        this.ele=document.getelementbyid (dom.substring (1)) || null;
        break;
      default:
        if (document.getelementsbytagname (dom) .length) {
          this.ele=document.getelementsbytagname (dom);
        } else if (document.getelementsbyname (dom) .length) {
          this.ele=document.getelementsbyname (dom);
        } else {
          this.ele=null;
        }
    }
    return this;
  };
  getdom.prototype.get=function (num) {
    return this.ele [num] || this.ele;
  }
  getdom.prototype.insert=function (value, num) {
    this.ele [num] .innerhtml=value;
  }
  return new getdom (dom);
}

css property get function

There are two types of css properties,One is ie, usecurrentstyle ;the other is another major browser,Usegetcomputedstyle , the following are compatible versions:

/* css get * /
function getcss (o, key) {
  return o.currentstyle?o.currentstyle [key]:document.defaultview.getcomputedstyle (o, false) [key];
};

Assignment function

When writing, I often encounter the assignment of the dom style.For convenience, I wrote a function for assignment:

/**
 -Assignment function
 [email protected]:obj is assigned object
 [email protected]:option operation
 [email protected]:value assignment
 * /
function setassign (obj, option, value) {
  switch (option) {
    case "width":
      obj.style.width=value;
      break;
    case "height":
      obj.style.height=value;
      break;
    case "top":
      obj.style.top=value;
      break;
    case "left":
      obj.style.left=value;
      break;
    case "position":
      obj.style.position=value;
      break;
    case "cursor":
      obj.style.cursor=value;
  }
}

Well, the preparations are basically completed,Start writing now.

Drawing of cropped area with click and move events

Seton the picture mousedown andmousemove event monitoring,as follows:

//mouse click on image trigger
opicture.onmousedown=function (ev) {
  //event object
  var oevent=ev || window.event;
  //initial mouse position
  var tempx=oevent.clientx;
  var tempy=oevent.clienty;
  //adjust the crop area position
  otailor.style.left=oevent.clientx + "px";
  otailor.style.top=oevent.clienty + "px";
  //Move the mouse over the picture Draw the cropped area Shadow area
  document.onmousemove=function (ev) {
    //mouse movement event object
    var oevent=ev || window.event;
    //The current mouse position minus the mouse position before the mouse is equal to the mouse movement distance
    var sleft=oevent.clientx-tempx;
    var stop=oevent.clienty-tempy;
    //Clipping out-of-bounds limit, just limit right and bottom
    if ((otailor.offsetleft + otailor.offsetwidth)>= (opicture.offsetleft + opicture.offsetwidth)) {
      sleft=opicture.offsetleft + opicture.offsetwidth-otailor.offsetleft;
    }
    if ((otailor.offsettop + otailor.offsetheight)>= (opicture.offsettop + opicture.offsetheight)) {
      stop=opicture.offsettop + opicture.offsetheight-otailor.offsettop;
    }
    //crop area drawing
    otailor.style.width=sleft + "px";
    otailor.style.height=stop + "px";
    //crop area display
    otailor.style.display="block";
    //shaded area display
    for (var i=0;i<oshadow.length;i ++) {
      oshadow [i] .style.display="block";
    }
    //Draw the shadow area
    shadow (opicture, otailor, oshadow);
    //add a cropped border
    tailorborder (odiv, ohandle, otailor);
    //block default events
    oevent.preventdefault ();
  };
  //release the mouse to cancel the move event
  document.onmouseup=function (ev) {
    var oevent=ev || window.event;
    //Move event canceled
    document.onmousemove=null;
    //block default events
    oevent.preventdefault ();
  };
  //block default events
  oevent.preventdefault ();
}

Shaded area drawing

/**
 * @param:opicture picture dom object
 * @param:otailor crop region dom object
 * @param:oshadow shadow area dom object
 * /
function shadow (opicture, otailor, oshadow) {
  //left shaded area
  setassign (oshadow [0], "width", (parseint (getcss (otailor, "left"))-parseint (getcss (opicture, "left"))) + "px");
  setassign (oshadow [0], "height", parseint (getcss (opicture, "height")) + "px");
  setassign (oshadow [0], "left", parseint (getcss (opicture, "left")) + "px")
  setassign (oshadow [0], "top", parseint (getcss (opicture, "top")) + "px")
  //right shaded area
  setassign (oshadow [2], "width", (parseint (getcss (opicture, "width"))-parseint (getcss (otailor, "width"))-parseint (getcss (oshadow [0], "width")) ) + "px");
  setassign (oshadow [2], "height", parseint (getcss (opicture, "height")) + "px");
  setassign (oshadow [2], "left", (parseint (getcss (otailor, "left")) + parseint (getcss (otailor, "width"))) + "px");
  setassign (oshadow [2], "top", parseint (getcss (opicture, "top")) + "px");
  //upper shadow area
  setassign (oshadow [1], "width", parseint (getcss (otailor, "width")) + "px");
  setassign (oshadow [1], "height", (parseint (getcss (otailor, "top"))-parseint (getcss (opicture, "top"))) + "px");
  setassign (oshadow [1], "left", (parseint (getcss (opicture, "left")) + parseint (getcss (oshadow [0], "width"))) + "px");
  setassign (oshadow [1], "top", parseint (getcss (opicture, "top")) + "px");
  //lower shadow area
  setassign (oshadow [3], "width", parseint (getcss (otailor, "width")) + "px");
  setassign (oshadow [3], "height", (parseint (getcss (opicture, "height"))-parseint (getcss (otailor, "height"))-parseint (getcss (oshadow [1], "height")) ) + "px");
  setassign (oshadow [3], "left", (parseint (getcss (opicture, "left")) + parseint (getcss (oshadow [0], "width"))) + "px");
  setassign (oshadow [3], "top", (parseint (getcss (otailor, "top")) + parseint (getcss (otailor, "height"))) + "px");
}

Note that in the actual use of web pages,If there is no left or top attribute in the image css in the layout, the above code will generate an error.Offsetleft and offsettop should be used instead.

Add crop border

In the released layout,You can see the cropped edges,The corners and sides have a small square shape,The addition is not only to distinguish the cropped area from the non-cropped area,It also makes it easy to add stretch crop areas in the next step.Let's start writing code:

/**
 * Crop border drawing
 * @param:odiv all border objects
 * @param:ohandle point edge
 * @param:otailor crop object
 * /
function tailorborder (odiv, ohandle, otailor) {
  //initialize the border
  for (var i=0;i<odiv.length;i ++) {
    setassign (odiv [i], "position", "absolute");
    setassign (odiv [i], "top", "0px");
    setassign (odiv [i], "left", "0px");
    setassign (odiv [i], "width", parseint (getcss (otailor, "width")) + "px");
    setassign (odiv [i], "height", parseint (getcss (otailor, "height")) + "px");
  }
  /* Point edge drawing * /
  //Four corner dotted edges are drawn
  for (var i=0;i<4;i ++) {
    //point drawing
    setassign (ohandle [i], "position", "absolute");
    setassign (ohandle [i], "width", "5px");
    setassign (ohandle [i], "height", "5px");
    //0 2 means left dot
    if (i%2 == 0) {
      setassign (ohandle [i], "left", "0px");
      setassign (ohandle [i], "top", (i == 0?"0px":(parseint (getcss (otailor, "height"))-8) + "px"));
    } else {
      //right point
      setassign (ohandle [i], "left", (parseint (getcss (otailor, "width"))-6) + "px");
      setassign (ohandle [i], "top", (i == 1?"0px":parseint (getcss (otailor, "height"))-8) + "px");
    }
  }
  //four-point dotted border
  for (var i=4;i<ohandle.length;i ++) {
    setassign (ohandle [i], "position", "absolute");
    setassign (ohandle [i], "width", "5px");
    setassign (ohandle [i], "height", "5px");
    //4 6 means up and down dotted border
    if (i%2 == 0) {
      setassign (ohandle [i], "left", parseint (getcss (otailor, "width"))/2 + "px");
      setassign (ohandle [i], "top", (i == 4?"0px":(parseint (getcss (otailor, "height"))-8) + "px"));
    } else {
      //left and right
      setassign (ohandle [i], "top", parseint (getcss (otailor, "height"))/2 + "px");
      setassign (ohandle [i], "left", (i == 5?"0px":parseint (getcss (otailor, "width"))-8) + "px");
    }
  }
}

In the layout, the crop region class name isbox_handle The first four divs represent the dots of the four corners.The last four represent the dots in the middle of the edges,All are distributed clockwise.The effect is as follows:

Monitor shadow areas

The cropped area and shadow area are drawn.Now add a small feature,When the mouse is clicked over the non-cropped area (that is, the shadow area), the cropped area is canceled.

//Set the time for the shadow area. When you click into the shadow area, the crop area disappears. The shadow area disappears.
for (var i=0;i<oshadow.length;i ++) {
  oshadow [i] .index=i;
  oshadow [i] .onmousedown=function () {
    otailor.style.display="none";
    otailor.style.width="0px";
    otailor.style.hegiht="0px";
    for (var i=0;i<oshadow.length;i ++) {
      oshadow [i] .style.display="none";
      oshadow [i] .style.left="0px";
      oshadow [i] .style.top="0px";
    }
  }
}

Monitor mouse movement

Next, add the function of crop area stretching,Different effects when the mouse moves to the dotted border

Add mouse display effect

//Dot-shaped border monitoring Set the corresponding operation
otailor.onmousemove=function (ev) {
  var otarget=oevent.target;
  switch (otarget.id) {
    case "box_1"://top left
      setassign (otailor, "cursor", "nw-resize");
      break;
    case "box_2"://top right
      setassign (otailor, "cursor", "ne-resize");
      break;
    case "box_3"://bottom left
      setassign (otailor, "cursor", "sw-resize");
      break;
    case "box_4"://bottom right
      setassign (otailor, "cursor", "se-resize");
      break;
    case "box_5"://up
      setassign (otailor, "cursor", "n-resize");
      break;
    case "box_6"://left
      setassign (otailor, "cursor", "w-resize");
      break;
    case "box_7"://next
      setassign (otailor, "cursor", "s-resize");
      break;
    case "box_8"://right
      setassign (otailor, "cursor", "e-resize");
      break;
    default://crop region
      setassign (otailor, "cursor", "move");
      break;
  }
}

Since there are many monitored divs, they are added using event delegation.The effect is not convenient to demonstrate,Interested students can test on their own,

Add stretch effect

Code

//Move event of crop area
otailor.onmousedown=function (ev) {
  //event event object
  var oevent=ev || window.event;
  //Get cursor status
  var ocur=getcss (otailor, "cursor");
  //initial mouse position
  var stmpx=oevent.clientx;
  var stmpy=oevent.clienty;
  //Get the properties of the cropped area
  oattrs.left=getcss (otailor, "left");
  oattrs.top=getcss (otailor, "top");
  oattrs.width=getcss (otailor, "width");
  oattrs.height=getcss (otailor, "height");
  document.onmousemove=function (ev) {
    //move event object
    var oevent=ev || window.event;
    //The current mouse position minus the initial mouse position is equal to the mouse movement distance
    var sleftt=oevent.clientx-stmpx;
    var stopt=oevent.clienty-stmpy;
    //indicates the distance moved by the mouse
    var otmpheight="";
    var otmptop="";
    var otmpwidth="";
    var otmpleft="";
    switch (ocur) {
      case "nw-resize"://top left
        otmpwidth=parseint (oattrs.width)-sleftt;
        otmpheight=parseint (oattrs.height)-stopt;
        otmpleft=parseint (oattrs.left) + sleftt;
        otmptop=parseint (oattrs.top) + stopt;
        break;
      case "ne-resize"://top right
        //At this time, the width cannot be subtracted from the mouse movement distance, because the movement distance is positive at this time
        otmpwidth=parseint (oattrs.width) + sleftt;
        otmpheight=parseint (oattrs.height)-stopt;
        //The left value does not need to be shifted in the upper right corner because the default is right shift
        otmptop=parseint (oattrs.top) + stopt;
        break;
      case "sw-resize"://bottom left
        //Same as the top right height must be plus the mouse movement distance
        otmpwidth=parseint (oattrs.width)-sleftt;
        otmpheight=parseint (oattrs.height) + stopt;
        otmpleft=parseint (oattrs.left) + sleftt;
        break;
      case "se-resize"://bottom right
        //The combination of lower left and upper right removes left and top at the same time
        otmpwidth=parseint (oattrs.width) + sleftt;
        otmpheight=parseint (oattrs.height) + stopt;
        break;
      case "n-resize"://up
        otmpheight=parseint (oattrs.height)-stopt;
        otmptop=parseint (oattrs.top) + stopt;
        break;
      case "w-resize"://left
        otmpwidth=parseint (oattrs.width)-sleftt;
        otmpleft=parseint (oattrs.left) + sleftt;
        break;
      case "s-resize"://next
        otmpheight=parseint (oattrs.height) + stopt;
        break;
      case "e-resize"://right
        var otmpwidth=parseint (oattrs.width) + sleftt;
        break;
      default:
        //otherwise move the crop area
        tailormove (oevent, otailor, opicture, oshadow);
        break;
    }
    //pull up to the border
    if (parseint (getcss (otailor, "top"))<= opicture.offsettop) {
      otmpheight=parseint (getcss (opicture, "height"))-(opicture.offsettop + parseint (getcss (opicture, "height"))-parseint (getcss (otailor, "top"))-parseint (getcss (otailor, " height "))));
      otmptop=opicture.offsettop;
    } else if (opicture.offsettop + parseint (getcss (opicture, "height"))<= (parseint (getcss (otailor, "top")) + parseint (getcss (otailor, "height"))) {{
      //Pull down to the border
      otmpheight=opicture.offsettop + parseint (getcss (opicture, "height"))-parseint (getcss (otailor, "top"));
    }
    //pull left to the border
    if ((parseint (getcss (otailor, "left")))<= opicture.offsetleft) {
      otmpwidth=parseint (getcss (opicture, "width"))-(opicture.offsetleft + parseint (getcss (opicture), "width")-parseint (getcss (otailor, "left"))-parseint (getcss (otailor, " width ")))
      otmpleft=opicture.offsetleft;
    } else if (parseint (getcss (otailor, "width")) + parseint (getcss (otailor, "left"))>= (opicture.offsetleft + opicture.offsetwidth)) {
      //pull right to the border
      otmpwidth=opicture.offsetleft + opicture.offsetwidth-parseint (getcss (otailor, "left"));
    }
    //assignment
    if (otmpwidth) {
      setassign (otailor, "width", otmpwidth + "px");
    }
    if (otmpheight) {
      setassign (otailor, "height", otmpheight + "px");
    }
    if (otmpleft) {
      setassign (otailor, "left", otmpleft + "px");
    }
    if (otmptop) {
      setassign (otailor, "top", otmptop + "px");
    }
    //Draw the shadow area
    shadow (opicture, otailor, oshadow);
    //add a cropped border
    tailorborder (odiv, ohandle, otailor);
  };
  //Pay attention to cancel the move event when you release the mouse
  document.onmouseup=function (ev) {
    //event event object
    var oevent=ev || window.event;
    document.onmousemove=null;
    oevent.preventdefault ();
  }
  oevent.preventdefault ();
};

Pay attention to the calculation of the moving distance when stretching,Especially when moving up and to the left,Pay attention to changing the left and top values ​​of the cropped area at the same time, otherwise it will only increase downwards and to the right.Let's talk about how to calculate:

principle

Take the mouse to the upper left corner as an example,The movement distance of the mouse is the same as described above.But note that the calculated value is a negative number,So when calculating the added value of the cropped area,To subtract this value from the width or height of the original crop area,At the same time, how much width is added,How much to subtract the left offset of the crop area,Otherwise the effect of the display is that the cropped area increases to the right,As shown below:

In the figure above, the green area is the cropped area after increasing the width and height when stretched.If this is the case without offset adjustment,The yellow area is the cropped area after the offset jump,The two overlapping areas are the original crop areas.

This is the top left corner stretch,Bottom left stretch is similar to others,Can follow the upward sleeve.

And another key,Stretching out of bounds has been said above,No more narration.

Movement of the crop area

Now for the last function,The movement of the cropped area.When the mouse moves inside the cropped area,Will trigger a move event,You can move the crop area at this time,code show as below:

/* Move the crop area * /
function tailormove (ev, otailor, opicture, oshadow) {
  var oevent=ev || window.event;
  var otmpx=oevent.clientx-otailor.offsetleft;
  var otmpy=oevent.clienty-otailor.offsettop;
  document.onmousemove=function (ev) {
    var oevent=ev || window.event;
    oleft=oevent.clientx-otmpx;
    otop=oevent.clienty-otmpy;
    if (oleft<opicture.offsetleft) {
      oleft=opicture.offsetleft;
    } else if (oleft>(opicture.offsetleft + opicture.offsetwidth-otailor.offsetwidth)) {
      oleft=opicture.offsetleft + opicture.offsetwidth-otailor.offsetwidth;
    }
    if (otop<opicture.offsettop) {
      otop=opicture.offsettop;
    } else if (otop>(opicture.offsettop + opicture.offsetheight-otailor.offsetheight)) {
      otop=opicture.offsettop + opicture.offsetheight-otailor.offsetheight;
    }
    otailor.style.left=(oleft) + "px";
    otailor.style.top=(otop) + "px";
    shadow (opicture, otailor, oshadow);
  }
}

Get cropped position

The function of cropping effect is basically completed,Then we need to get the cropped position,The first thing to know is what properties you need to get.According tophp gd library operations, image cropping needs to know,The starting coordinates of the crop and the width and height of the crop.I use a function to get this data,And encapsulate it and return:

function getele () {
  var opicture=$("img"). get (0);
  var otailor=$(". img_box"). get (0);
  oattrs.leftx=(parseint (getcss (otailor, "left"))-opicture.offsetleft);
  oattrs.lefty=(parseint (getcss (otailor, "top"))-opicture.offsettop);
  oattrs.twidth=(parseint (getcss (otailor, "width")));
  oattrs.theight=(parseint (getcss (otailor, "height")));
  return oattrs;
}

still have a question,If the picture on the webpage is a picture compressed using css,Then the position and crop size obtained here will be different from what you imagine,The range of the cropped image may be larger (the original image is larger), or it may be smaller (the original image is smaller).

If you can get the size of the original image,You can crop according to the ratio of the compressed image to the original image.This will get the correct crop.

Okay, a simple picture crop function is done,You can use ajax to pass to the background for processing.

  • Previous Difference between static member functions and non-static member functions in C ++
  • Next Detailed SpringMVC interaction method with json data