转自:http://www.cnblogs.com/cloudgamer/archive/2008/10/05/1303993.html
上一阵子做过一个 JavaScript 图片切割效果,得到很多人关注。其中有很多人向我询问如何做一个真正的图片切割,这里需要声明一下:
首先js是不能操作客户端文件的(除非特殊情况),所以图片的切割必须在后台处理,对于客户端的图片可以先上传再切割或者把图片和切割参数一起传递到服务器再处理(上传文件不在本次讨论范围,请自行修改);
还有是通过客户端传递的参数来处理图片,确实能得到展示图或预览图的效果(这是针对有些提出在后台处理的图片得不到预览图的效果来说的),下面会举例说明如何生成展示图那样的图片。
程序说明:
【客户端部分】
客户端部分详细请参考 JavaScript 图片切割效果(建议没有看过的先看那里的例子),这里说说要传递到后台的参数,这些参数包括:
图片地址:ic.Url;
水平切割点:ic.Drag.offsetLeft;
垂直切割点:ic.Drag.offsetTop;
切割宽度:ic.Drag.offsetWidth;
切割高度:ic.Drag.offsetHeight;
图片宽度:ic.Width;
图片高度:ic.Height。
在前台传递这些参数:
var p = ic.Url,
x = ic.Drag.offsetLeft,
y = ic.Drag.offsetTop,
w = ic.Drag.offsetWidth,
h = ic.Drag.offsetHeight,
pw = ic.Width,
ph = ic.Height;
$("imgCreat").src = "ImgCropper.ashx?p=" + p + "&x=" + x + "&y=" + y + "&w=" + w + "&h=" + h + "&pw=" + pw + "&ph=" + ph + "&" + Math.random;
其中图片地址、图片宽度、图片高度如果是预先设定好的话就可以不传递了。
【后台部分】
后台主要是进行图片的处理。
在后台获取前台传递的参数:
string Pic = Convert.ToString(context.Request["p"]);
int PointX = Convert.ToInt32(context.Request["x"]);
int PointY = Convert.ToInt32(context.Request["y"]);
int CutWidth = Convert.ToInt32(context.Request["w"]);
int CutHeight = Convert.ToInt32(context.Request["h"]);
int PicWidth = Convert.ToInt32(context.Request["pw"]);
int PicHeight = Convert.ToInt32(context.Request["ph"]);
public MemoryStream ResetImg(string ImgFile, int PicWidth, int PicHeight, int PointX, int PointY, int CutWidth, int CutHeight)
{
Image imgPhoto = Image.FromFile(ImgFile);
Bitmap bmPhoto = new Bitmap(CutWidth, CutHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gbmPhoto = Graphics.FromImage(bmPhoto);
gbmPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, CutWidth, CutHeight), PointX * imgPhoto.Width / PicWidth, PointY * imgPhoto.Height / PicHeight, CutWidth * imgPhoto.Width / PicWidth, CutHeight * imgPhoto.Height / PicHeight, GraphicsUnit.Pixel);
MemoryStream ms2 = new MemoryStream();
bmPhoto.Save(ms2, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
gbmPhoto.Dispose();
bmPhoto.Dispose();
return ms2;
}
<%@ WebHandler Language="c#" Class="ImgCropper_WebHandler" Debug="true" %>
using System;
using System.Web;
using System.Drawing;
using System.IO;
public class ImgCropper_WebHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string Pic = Convert.ToString(context.Request["p"]);
int PointX = Convert.ToInt32(context.Request["x"]);
int PointY = Convert.ToInt32(context.Request["y"]);
int CutWidth = Convert.ToInt32(context.Request["w"]);
int CutHeight = Convert.ToInt32(context.Request["h"]);
int PicWidth = Convert.ToInt32(context.Request["pw"]);
int PicHeight = Convert.ToInt32(context.Request["ph"]);
context.Response.ContentType = "image/jpeg";
ResetImg(System.Web.HttpContext.Current.Server.MapPath(Pic), PicWidth, PicHeight, PointX, PointY, CutWidth, CutHeight).WriteTo(context.Response.OutputStream);
}
public MemoryStream ResetImg(string ImgFile, int PicWidth, int PicHeight, int PointX, int PointY, int CutWidth, int CutHeight)
{
Image imgPhoto = Image.FromFile(ImgFile);
Bitmap bmPhoto = new Bitmap(CutWidth, CutHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gbmPhoto = Graphics.FromImage(bmPhoto);
gbmPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, CutWidth, CutHeight), PointX * imgPhoto.Width / PicWidth, PointY * imgPhoto.Height / PicHeight, CutWidth * imgPhoto.Width / PicWidth, CutHeight * imgPhoto.Height / PicHeight, GraphicsUnit.Pixel);
MemoryStream ms2 = new MemoryStream();
bmPhoto.Save(ms2, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
gbmPhoto.Dispose();
bmPhoto.Dispose();
return ms2;
}
public bool IsReusable
{
get
{
return false;
}
}
}
在.net中我只是菜鸟,各位有什么建议或意见欢迎留言讨论,由于涉及后台操作,请下载完整实例测试。
下载完整测试实例
上一阵子做过一个 JavaScript 图片切割效果,得到很多人关注。其中有很多人向我询问如何做一个真正的图片切割,这里需要声明一下:
首先js是不能操作客户端文件的(除非特殊情况),所以图片的切割必须在后台处理,对于客户端的图片可以先上传再切割或者把图片和切割参数一起传递到服务器再处理(上传文件不在本次讨论范围,请自行修改);
还有是通过客户端传递的参数来处理图片,确实能得到展示图或预览图的效果(这是针对有些提出在后台处理的图片得不到预览图的效果来说的),下面会举例说明如何生成展示图那样的图片。
程序说明:
【客户端部分】
客户端部分详细请参考 JavaScript 图片切割效果(建议没有看过的先看那里的例子),这里说说要传递到后台的参数,这些参数包括:
图片地址:ic.Url;
水平切割点:ic.Drag.offsetLeft;
垂直切割点:ic.Drag.offsetTop;
切割宽度:ic.Drag.offsetWidth;
切割高度:ic.Drag.offsetHeight;
图片宽度:ic.Width;
图片高度:ic.Height。
在前台传递这些参数:
var p = ic.Url,
x = ic.Drag.offsetLeft,
y = ic.Drag.offsetTop,
w = ic.Drag.offsetWidth,
h = ic.Drag.offsetHeight,
pw = ic.Width,
ph = ic.Height;
$("imgCreat").src = "ImgCropper.ashx?p=" + p + "&x=" + x + "&y=" + y + "&w=" + w + "&h=" + h + "&pw=" + pw + "&ph=" + ph + "&" + Math.random;
其中图片地址、图片宽度、图片高度如果是预先设定好的话就可以不传递了。
【后台部分】
后台主要是进行图片的处理。
在后台获取前台传递的参数:
string Pic = Convert.ToString(context.Request["p"]);
int PointX = Convert.ToInt32(context.Request["x"]);
int PointY = Convert.ToInt32(context.Request["y"]);
int CutWidth = Convert.ToInt32(context.Request["w"]);
int CutHeight = Convert.ToInt32(context.Request["h"]);
int PicWidth = Convert.ToInt32(context.Request["pw"]);
int PicHeight = Convert.ToInt32(context.Request["ph"]);
然后就用这些参数对图片进行切割了,先说说切割的原理,主要分两部:切割和缩放。
首先是在原图切割出需要的部分。切割需要 的参数是PointX、PointY、CutWidth、CutHeight,因为在客户端的程序中是可以缩放原图来进行切割的,所以要在在切割原图时需 要先按比例缩放这些参数,还要注意PointX和CutWidth需要水平方向的比例,PointY和CutHeight需要垂直方向的比例。例如(其中 imgPhoto是原图):
水平切割点:PointX * imgPhoto.Width / PicWidth;
切割宽度:CutWidth * imgPhoto.Width / PicWidth;
垂直切割点:PointY * imgPhoto.Height / PicHeight;
切割高度:CutHeight * imgPhoto.Height / PicHeight。
用这些参数就可以对原图进行切割了。
然后是缩放原图。可以想象,当切割好原图后,只要把图宽高缩放到CutWidth和CutHeight就可以得到跟展示图一样的图片了。
下面是处理图片的程序:
public MemoryStream ResetImg(string ImgFile, int PicWidth, int PicHeight, int PointX, int PointY, int CutWidth, int CutHeight)
{
Image imgPhoto = Image.FromFile(ImgFile);
Bitmap bmPhoto = new Bitmap(CutWidth, CutHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gbmPhoto = Graphics.FromImage(bmPhoto);
gbmPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, CutWidth, CutHeight), PointX * imgPhoto.Width / PicWidth, PointY * imgPhoto.Height / PicHeight, CutWidth * imgPhoto.Width / PicWidth, CutHeight * imgPhoto.Height / PicHeight, GraphicsUnit.Pixel);
MemoryStream ms2 = new MemoryStream();
bmPhoto.Save(ms2, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
gbmPhoto.Dispose();
bmPhoto.Dispose();
return ms2;
}
当然对于不同的需求可能要生成的效果也不一样,但只要能灵活运用对于一般的需求基本都能实现了。
程序中还有一个特点是利用IHttpHandler来输出生成的图片,这个估计已经有更好的文章这里就不说明了,下面是完整服务器端代码:
<%@ WebHandler Language="c#" Class="ImgCropper_WebHandler" Debug="true" %>
using System;
using System.Web;
using System.Drawing;
using System.IO;
public class ImgCropper_WebHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string Pic = Convert.ToString(context.Request["p"]);
int PointX = Convert.ToInt32(context.Request["x"]);
int PointY = Convert.ToInt32(context.Request["y"]);
int CutWidth = Convert.ToInt32(context.Request["w"]);
int CutHeight = Convert.ToInt32(context.Request["h"]);
int PicWidth = Convert.ToInt32(context.Request["pw"]);
int PicHeight = Convert.ToInt32(context.Request["ph"]);
context.Response.ContentType = "image/jpeg";
ResetImg(System.Web.HttpContext.Current.Server.MapPath(Pic), PicWidth, PicHeight, PointX, PointY, CutWidth, CutHeight).WriteTo(context.Response.OutputStream);
}
public MemoryStream ResetImg(string ImgFile, int PicWidth, int PicHeight, int PointX, int PointY, int CutWidth, int CutHeight)
{
Image imgPhoto = Image.FromFile(ImgFile);
Bitmap bmPhoto = new Bitmap(CutWidth, CutHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gbmPhoto = Graphics.FromImage(bmPhoto);
gbmPhoto.DrawImage(imgPhoto, new Rectangle(0, 0, CutWidth, CutHeight), PointX * imgPhoto.Width / PicWidth, PointY * imgPhoto.Height / PicHeight, CutWidth * imgPhoto.Width / PicWidth, CutHeight * imgPhoto.Height / PicHeight, GraphicsUnit.Pixel);
MemoryStream ms2 = new MemoryStream();
bmPhoto.Save(ms2, System.Drawing.Imaging.ImageFormat.Jpeg);
imgPhoto.Dispose();
gbmPhoto.Dispose();
bmPhoto.Dispose();
return ms2;
}
public bool IsReusable
{
get
{
return false;
}
}
}
在.net中我只是菜鸟,各位有什么建议或意见欢迎留言讨论,由于涉及后台操作,请下载完整实例测试。
下载完整测试实例