[WebApi] 搗鼓一個資源管理器--服務器端分割壓縮圖片

《打造一個網站或者其他網絡應用的文件管理接口(WebApi)第五章“服務器端分割壓縮圖片”》

========================================================
作者:
qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/41826865
========================================================

History

[WebApi] 搗鼓一個資源管理器--數據庫輔助服務器文件訪問

In This

在做網站開發時,我常常會做一些這樣的工作:一張大圖中包含了許多的小圖,而網站中爲了使用其中一張小圖我不得不把大圖切成一張張的小圖。雖然這樣的工作不多;但對於我來說在服務器端莫名的存儲了一大堆小文件是很反感的事情;或許你會說使用css來完成大圖中的小圖顯示;當然這是可以的。但是我假如需要下載該小圖呢?這時無能爲力了吧!

所以有了今天的服務器端剪切壓縮圖片的一章。

CodeTime

更改


本次版本相對上一張主要兩個地方更改:新增 ImageUtils.cs,修改 ResourceApiController.cs

ImageUtils.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

namespace WebResource.Models
{
    public class ImageUtils
    {
        /// <summary>
        /// 圖片類型對應的ImageFormat
        /// </summary>
        /// <param name="type">類型</param>
        /// <returns>ImageFormat</returns>
        public static ImageFormat GetFormat(string type)
        {
            Dictionary<string, ImageFormat> types = new Dictionary<string, ImageFormat>();
            types.Add("bmp", ImageFormat.Bmp);
            types.Add("gif", ImageFormat.Gif);
            types.Add("ief", ImageFormat.Jpeg);
            types.Add("jpeg", ImageFormat.Jpeg);
            types.Add("jpg", ImageFormat.Jpeg);
            types.Add("jpe", ImageFormat.Jpeg);
            types.Add("png", ImageFormat.Png);
            types.Add("tiff", ImageFormat.Tiff);
            types.Add("tif", ImageFormat.Tiff);
            types.Add("djvu", ImageFormat.Bmp);
            types.Add("djv", ImageFormat.Bmp);
            types.Add("wbmp", ImageFormat.Bmp);
            types.Add("ras", ImageFormat.Bmp);
            types.Add("pnm", ImageFormat.Bmp);
            types.Add("pbm", ImageFormat.Bmp);
            types.Add("pgm", ImageFormat.Bmp);
            types.Add("ppm", ImageFormat.Bmp);
            types.Add("rgb", ImageFormat.Bmp);
            types.Add("xbm", ImageFormat.Bmp);
            types.Add("xpm", ImageFormat.Bmp);
            types.Add("xwd", ImageFormat.Bmp);
            types.Add("ico", ImageFormat.Icon);
            types.Add("wmf", ImageFormat.Emf);
            types.Add("exif", ImageFormat.Exif);
            types.Add("emf", ImageFormat.Emf);

            try
            {
                ImageFormat format = types[type];
                if (format != null)
                    return format;
            }
            catch { }
            return ImageFormat.Bmp;
        }


        /// <summary>
        /// 圖片轉換爲字節
        /// </summary>
        /// <param name="bitmap">圖片</param>
        /// <param name="type">類型</param>
        /// <returns>字節碼</returns>
        public static byte[] ToBytes(Bitmap bitmap, string type)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, GetFormat(type));
                byte[] data = new byte[stream.Length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(data, 0, Convert.ToInt32(stream.Length));
                return data;
            }
        }

        /// <summary>  
        ///  調整圖片寬度高度   
        /// </summary>  
        /// <param name="bmp">原始Bitmap </param>  
        /// <param name="newW">新的寬度</param>  
        /// <param name="newH">新的高度</param>  
        /// <returns>處理Bitmap</returns>  

        public static Bitmap Resize(Bitmap bmp, int newW, int newH)
        {
            try
            {
                Bitmap b = new Bitmap(newW, newH);
                Graphics g = Graphics.FromImage(b);
                // 插值算法的質量   
                g.InterpolationMode = InterpolationMode.Default;
                g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
                g.Dispose();
                return b;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 切片Bitmap:指定圖片分割爲 Row 行,Col 列,取第 N 個圖片
        /// </summary>
        /// <param name="b">等待分割的圖片</param>
        /// <param name="row">行</param>
        /// <param name="col">列</param>
        /// <param name="n">取第N個圖片</param>
        /// <returns>切片後的Bitmap</returns>
        public static Bitmap Cut(Bitmap b, int row, int col, int n)
        {
            int w = b.Width / col;
            int h = b.Height / row;

            n = n > (col * row) ? col * row : n;

            int x = (n - 1) % col;
            int y = (n - 1) / col;

            x = w * x;
            y = h * y;

            try
            {
                Bitmap bmpOut = new Bitmap(w, h, PixelFormat.Format24bppRgb);
                Graphics g = Graphics.FromImage(bmpOut);
                g.DrawImage(b, new Rectangle(0, 0, w, h), new Rectangle(x, y, w, h), GraphicsUnit.Pixel);
                g.Dispose();
                return bmpOut;
            }
            catch
            {
                return null;
            }
        }
    }
}
該類的作用就是壓縮和剪切圖片,其具體實現也都註釋清楚了;如果不明白的地方,還望在評論中提出。

然後來看看這次的API更改。

ResourceApiController.cs

        /// <summary>
        /// Get Image
        /// </summary>
        /// <param name="name">MD5 Name</param>
        /// <returns>File</returns>
        [HttpGet]
        [Route("{Id}/Img")]
        public async Task<HttpResponseMessage> GetImage(string Id, int w = 0, int h = 0, int r = 1, int c = 1, int n = 1)
        {
            // Return 304
            var tag = Request.Headers.IfNoneMatch.FirstOrDefault();
            if (Request.Headers.IfModifiedSince.HasValue && tag != null && tag.Tag.Length > 0)
                return new HttpResponseMessage(HttpStatusCode.NotModified);

            // 判斷參數是否正確
            if (w < 0 || h < 0 || r < 1 || c < 1 || n < 1)
                return new HttpResponseMessage(HttpStatusCode.BadRequest);

            // 默認參數情況直接返回
            if (w == 0 && h == 0 && r == 1 && c == 1 && n == 1)
                return await Get(Id);

            // 查找數據庫
            Resource model = await db.Resources.FindAsync(Id);

            // 判斷
            if (model == null || !GetContentType(model.Type).StartsWith("image"))
                return new HttpResponseMessage(HttpStatusCode.BadRequest);

            // 加載文件信息
            FileInfo info = new FileInfo(Path.Combine(ROOT_PATH, model.Folder, model.Id));
            if (!info.Exists)
                return new HttpResponseMessage(HttpStatusCode.BadRequest);

            // 打開圖片
            Bitmap bitmap = new Bitmap(info.FullName);

            // 剪切
            if (r > 1 || c > 1)
            {
                bitmap = ImageUtils.Cut(bitmap, r, c, n);
            }

            // 放大縮小
            if (w > 0 || h > 0)
            {
                w = w == 0 ? bitmap.Width : w;
                h = h == 0 ? bitmap.Height : h;

                bitmap = ImageUtils.Resize(bitmap, w, h);
            }

            try
            {
                // Copy To Memory And Close.
                byte[] bytes = ImageUtils.ToBytes(bitmap, model.Type);
                // Get Tag
                string eTag = string.Format("\"{0}\"", HashUtils.GetMD5Hash(bytes));

                // 構造返回
                HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);

                ContentDispositionHeaderValue disposition = new ContentDispositionHeaderValue(GetDisposition(model.Type));
                disposition.FileName = string.Format("{0}.{1}", model.Name, model.Type);
                disposition.Name = model.Name;
                // 這裏寫入大小爲計算後的大小
                disposition.Size = bytes.Length;

                result.Content = new ByteArrayContent(bytes);
                result.Content.Headers.ContentType = new MediaTypeHeaderValue(GetContentType(model.Type));
                result.Content.Headers.ContentDisposition = disposition;
                // Set Cache 這個同Get方法
                result.Content.Headers.Expires = new DateTimeOffset(DateTime.Now).AddHours(1);
                result.Content.Headers.LastModified = new DateTimeOffset(DateTime.Now);
                result.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromHours(1) };
                result.Headers.ETag = new EntityTagHeaderValue(eTag);
                return result;
            }
            catch { }
            finally
            {
                if (bitmap != null)
                    bitmap.Dispose();
            }

            return new HttpResponseMessage(HttpStatusCode.BadRequest);
        }
由於代碼量較多,我就不全部貼出來了;就把更改的地方寫出來了;其中主要就是新增了一個 GetImage 方法。

在方法中,根據傳入的參數我們進行一定的判斷然後剪切壓縮圖片;最後打包爲 Http 返回

代碼修改的地方就這麼多。

RunTime

API


可以看見多API中多了一個接口;進入看看。


可以看見除了 Id 是必須,其他參數都是有默認值,可以不用傳入。

  • Id:文件的MD5值,用於接口尋找對應文件
  • w:返回的圖片寬度
  • h:返回的圖片高度
  • r:row 行,代表橫向分割爲多少行;默認爲1
  • c:column 列,代表縱向分割爲多少列;默認爲1
  • n:代表分割後取第N個圖片

上傳


慣例,首先上傳一個圖片。

訪問


訪問地址,可以使用原來的也可以使用新的地址,新的地址無非就是在後面加上“/img”

壓縮


上面是改變寬度和高度後的結果;你可以右鍵保存圖片看看圖片是否是被改變了。

剪切

再來看看剪切的效果:


說說原理:


再來一張:


這樣也就實現了,服務器端一張圖片;客戶端無數張圖片;可以根據需求進行分割壓縮;當然複雜一點你還可以加上一些特效;比如模糊;水印等等;這些服務端都可以做。

END

資源

[WebApi] 搗鼓一個資源管理器--服務器端分割壓縮圖片

下一章

下章準備把這些現有的功能進行組合,做一個管理界面;那樣就可以在客戶端管理服務端數據了;賊爽!

========================================================
作者:
qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/41826865
========================================================

發佈了82 篇原創文章 · 獲贊 709 · 訪問量 66萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章