.Net平台移动端实现图像上传、压缩及预览功能详解
最近再给公司做移动端开发图像上传裁剪压缩以及预览的功能,给大家分享一点心得,首先给大家看一下最终实现效果:
首先是前端把图片转化成base64格式然后通过ajax异步发送到服务器
html部分
<div style="background-color:#fff;margin-top:-5px;padding:0px 8px;">
<img onclick="DeleteImage(this)" id="ImgShow0" class="ImgPreHidden" src="" alt="" />
<img onclick="DeleteImage(this)" id="ImgShow1" class="ImgPreHidden" src="" alt="" />
<img onclick="DeleteImage(this)" id="ImgShow2" class="ImgPreHidden" src="" alt="" />
<img onclick="DeleteImage(this)" id="ImgShow3" class="ImgPreHidden" src="" alt="" />
<img onclick="DeleteImage(this)" id="ImgShow4" class="ImgPreHidden" src="" alt="" />
<image id="ImgUploadButtom" onclick="$('#ImgUpload').click()" style="width:80px;height:80px;margin-bottom:2px;" src="../../../../Content/image/camera.png" />
<input type="file" id="ImgUpload" style="display:none;" />
</div>
javascript部分
使用canvas对象对图片进行压缩,使用exif.js解决部分手机拍照之后图片旋转问题
$("#ImgUpload").on("change", headPortraitListener);
/*头像上传监听*/
function headPortraitListener(e) {
var ImgShowI = 0;
for (var i = 1; i <= 4; i++) {
if ($("#ImgShow" + i).attr("src") == "") {
ImgShowI = i;
break;
}
}
if (ImgShowI == 0) {
_layer.msg("最多只能上传4张图片");
return;
}
var img = document.getElementById("ImgShow" + i);
var img0 = document.getElementById("ImgShow0");
if (window.FileReader) {
var file = e.target.files[0];
EXIF.getData(file, function () {
Orientation = EXIF.getTag(this, 'Orientation');
});
var reader = new FileReader();
if (file && file.type.match('image.*')) {
reader.readAsDataURL(file);
} else {
img.setAttribute('class', 'ImgShow ImgPreHidden');
img.setAttribute('src', '');
}
reader.onloadend = function (e) {
img0.setAttribute('src', reader.result);
}
img0.onload = function () {
var imgWidth = this.width,
imgHeight = this.height;
console.log(this);
if (imgWidth > imgHeight && imgWidth > 1000) {
imgWidth = 1000;
imgHeight = Math.ceil(1000 * this.height / this.width);
} else if (imgWidth < imgHeight && imgHeight > 1334) {
imgWidth = Math.ceil(1334 * this.width / this.height);
imgHeight = 1334;
}
var canvas = document.createElement("canvas"),
ctx = canvas.getContext('2d');
canvas.width = imgWidth;
canvas.height = imgHeight;
if (Orientation && Orientation != 1) {
switch (Orientation) {
case 6:
canvas.width = imgHeight;
canvas.height = imgWidth;
ctx.rotate(Math.PI / 2);
ctx.drawImage(this, 0, -imgHeight, imgWidth, imgHeight);
break;
case 3:
ctx.rotate(Math.PI);
ctx.drawImage(this, -imgWidth, -imgHeight, imgWidth, imgHeight);
break;
case 8:
canvas.width = imgHeight;
canvas.height = imgWidth;
ctx.rotate(3 * Math.PI / 2);
ctx.drawImage(this, -imgWidth, 0, imgWidth, imgHeight);
break;
}
} else {
ctx.drawImage(this, 0, 0, imgWidth, imgHeight);
}
UploadImage(img, canvas.toDataURL("image/jpeg", 0.8));
}
}
}
function DeleteImage(e) {
$(e).attr('class', 'ImgPreHidden');
$(e).attr('src', '');
$("#ImgUploadButtom").show();
}
function UploadImage(img, base64Image) {
var postData = {};
postData["Bill_Id"] = $("#ID").val();
postData["Base64Image"] = base64Image;
AjaxJson("/ExtensionApp/ComplaintMailbox/UploadImage", "json=" + JSON.stringify(postData), function (result) {
if (result.status == "1") {
img.setAttribute('src', base64Image);
img.setAttribute('class', 'ImgShow ImgPreShow');
IsImage();
} else {
_layer.msg(result.message);
}
})
}
function IsImage() {
var ImgShowI = 0;
for (var i = 1; i <= 4; i++) {
if ($("#ImgShow" + i).attr("src") == "") {
ImgShowI = i;
break;
}
}
if (ImgShowI == 0) {
$("#ImgUploadButtom").hide();
return;
}
}
C#后端部分
public ActionResult UploadImage(string json)
{
SH.Entity.CommonModule.CommonResult<Hashtable> result = new SH.Entity.CommonModule.CommonResult<Hashtable>();
try
{
Base_Image entity = json.JsonToEntity<Base_Image>();
var Image = SH.Utilities.Base.Media.ImageExt.Compression(entity.Base64Image, 1000);
entity.Id = Guid.NewGuid().ToString();
using (MiniPoco.Database db = new MiniPoco.Database())
{
var data_type = entity.Base64Image.Split(',');
string Ext = data_type[0].Split('/')[1].Split(';')[0];
string _Url = "\\WeChat\\" + DateTime.Now.ToString("yyyy-MM");
entity.CreateDate = DateTime.Now;
string fileName = entity.Id + "." + Ext;
entity.Status = 0;
entity.Url = _Url + "\\" + fileName;
string ImageFilePath = "\\\\网盘地址" + _Url;
if (System.IO.Directory.Exists(ImageFilePath) == false)//如果不存在就创建文件夹
{
System.IO.Directory.CreateDirectory(ImageFilePath);
}
string ImagePath = ImageFilePath + "\\" + fileName;//定义图片名称
Image.Save(ImagePath); //保存图片到服务器,然后获取路径
db.Insert<Base_Image>(entity);
db.Save();
result.status = "1";
result.message = entity.Id;
return Content(result.ToJson());
}
}
catch (Exception ex)
{
result.status = "0";
result.message = ex.Message;
return Content(result.ToJson());
}
}
使用PhotoSwipe实现图片的预览功能
引入必要的css和js
<!-- Core CSS file -->
<link href="../../../../Content/js/plugins/PhotoSwipe/photoswipe.css" rel="stylesheet" type="text/css" />
<!-- Skin CSS file (styling of UI - buttons, caption, etc.)
In the folder of skin CSS file there are also:
- .png and .svg icons sprite,
- preloader.gif (for browsers that do not support CSS animations) -->
<link href="../../../../Content/js/plugins/PhotoSwipe/default-skin/default-skin.css" rel="stylesheet" type="text/css" />
<!-- Core JS file -->
<script src="../../../../Content/js/plugins/PhotoSwipe/photoswipe.min.js" type="text/javascript"></script>
<!-- UI JS file -->
<script src="../../../../Content/js/plugins/PhotoSwipe/photoswipe-ui-default.min.js" type="text/javascript"></script>
html部分
<div id="layer-photos-demo" class="line-div" style="margin-top:5px;">
<img onclick="openPhotoSwipe(1)" id="ImgShow1" class="ImgPreHidden" layer-src="" src="" alt="" />
<img onclick="openPhotoSwipe(2)" id="ImgShow2" class="ImgPreHidden" layer-src="" src="" alt="" />
<img onclick="openPhotoSwipe(3)" id="ImgShow3" class="ImgPreHidden" layer-src="" src="" alt="" />
<img onclick="openPhotoSwipe(4)" id="ImgShow4" class="ImgPreHidden" layer-src="" src="" alt="" />
</div>
<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element, as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides. PhotoSwipe keeps only 3 slides in DOM to save memory. -->
<div class="pswp__container">
<!-- don't modify these 3 pswp__item elements, data is added later on -->
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--active pswp__ui--fit">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close(Esc)"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
javascript部分
var PhotoSwipe_items = [
{
src: '/GetImage?Id=95b5e811-3796-4841-9960-d6d03815baea.jpeg',
w: 1000,
h: 750
},
{
src: '/GetImage?Id=bb128132-0e9d-4bf7-b68b-aedb89d8d8b2.jpeg',
w: 1000,
h: 750
}];
var openPhotoSwipe = function (i) {
var pswpElement = document.querySelectorAll('.pswp')[0];
// define options (if needed)
var options = {
// history & focus options are disabled on CodePen
history: false,
focus: false,
index:i-1,
showAnimationDuration: 0,
hideAnimationDuration: 0
};
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, PhotoSwipe_items, options);
gallery.init();
};
给大家看一下图像压缩前和压缩后的对比
压缩前
压缩后
最后补充一下图片压缩功能的代码
public static Image Compression(string Base64String, int width)
{
long quality = 90;//壓縮質量0-100之間 數值越大質量越高
string ImageType = Base64String.Split(',')[0];
string temp = Base64String.Split(',')[1];
temp = temp.Replace(" ", "+");
int mod4 = temp.Length % 4;
if (mod4 > 0)
{
temp += new string('=', 4 - mod4);
}
byte[] btsdata = Convert.FromBase64String(temp);
MemoryStream ms = new MemoryStream(btsdata);
Image img = Image.FromStream(ms);
int height = (int)img.Height * width / img.Width;
Bitmap _bitmap = new Bitmap(width, height);
Graphics _graphics = Graphics.FromImage(_bitmap);
//设置图片质量
_graphics.InterpolationMode = InterpolationMode.Low;
_graphics.SmoothingMode = SmoothingMode.None;
//绘制图片
_graphics.Clear(Color.Transparent);
_graphics.DrawImage(img, 0, 0, _bitmap.Width, _bitmap.Height);
//压缩
ImageCodecInfo CodecInfo = GetEncoder(img.RawFormat);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, quality);
myEncoderParameters.Param[0] = myEncoderParameter;
//保存
using (MemoryStream memorystream = new MemoryStream())
{
_bitmap.Save(memorystream, CodecInfo, myEncoderParameters);
myEncoderParameters.Dispose();
myEncoderParameter.Dispose();
_graphics.Dispose();
img.Dispose();
_bitmap.Dispose();
return BytesToImage(memorystream.ToArray());
}
}
private static Image BytesToImage(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer);
Image image = System.Drawing.Image.FromStream(ms);
return image;
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{ return codec; }
}
return null;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通