2010-10-07 35 views
9

Tôi có ảnh chụp màn hình tôi chụp trong ứng dụng dành cho thiết bị di động của mình. Ảnh chụp màn hình mất khoảng 32 KB khi được lưu dưới dạng png trên đĩa.Làm cách nào để giảm kích cỡ của ảnh trong C# và .NET 3.5?

Tôi gửi chúng đến một máy chủ SQL trung tâm và 32 KB là quá lớn đối với số lần đó tôi sẽ cần phải lưu trữ ảnh chụp màn hình đó (khoảng 2500 lần một ngày).

Có loại thủ thuật nào mà tôi có thể thực hiện để làm cho nó tiết kiệm nhỏ hơn không?

Đây là mã tôi đang sử dụng hiện nay để mang nó từ Bitmap để byte (để gửi đến máy chủ để lưu trữ):

MemoryStream stream = new MemoryStream(); 
_signatureImage.Save(stream, ImageFormat.Png); 
return stream.ToArray(); 

_signatureImage là một Bitmap và là ảnh chụp màn hình trong câu hỏi.

Dưới đây là một ví dụ màn hình bắn tôi tiết kiệm của:

Screen Shot Image

Mọi thứ mà bật để tâm (nhưng tôi không biết làm thế nào để làm cho họ):

  1. Giảm Chiều cao và Chiều rộng thực tế của hình ảnh (nhưng hy vọng theo cách sẽ không bóp méo nó).
  2. Thay đổi hình ảnh thành hình ảnh đen trắng (không chắc chắn liệu tôi có thấy bất kỳ khoản tiết kiệm không gian thực nào) không? .

Lưu ý, tất cả điều này phải được thực hiện theo chương trình và không thể thực hiện thao tác hình ảnh phức tạp, quá lâu.

Cảm ơn bạn đã được trợ giúp.

+0

Tôi không thể xem hình ảnh bạn đã đăng (lọc http tại nơi làm việc). kích thước là gì? – Kendrick

+0

@Kendrick Nó là 480 x 640. – jdmichal

Trả lời

10
private static Image ResizeImage(int newSize, Image originalImage) 
    { 
     if (originalImage.Width <= newSize) 
      newSize = originalImage.Width; 

     var newHeight = originalImage.Height * newSize/originalImage.Width; 

     if (newHeight > newSize) 
     { 
      // Resize with height instead 
      newSize = originalImage.Width * newSize/originalImage.Height; 
      newHeight = newSize; 
     } 

     return originalImage.GetThumbnailImage(newSize, newHeight, null, IntPtr.Zero); 
    } 

Điều này sẽ làm việc với đối tượng Bitmap của bạn Nhập và thay đổi kích thước Chiều cao hoặc Chiều rộng, tùy thuộc vào kích thước hình ảnh của bạn. Nó cũng sẽ duy trì quy mô.

EDIT:

Bạn có thể tạo đối tượng Bitmap mới và định lại kích thước hình ảnh gốc của bạn thành đối tượng Bitmap đó.

Bitmap b = new Bitmap(newWidth, newHeight); 
Graphics g = Graphics.FromImage((Image)b); 
g.InterpolationMode = InterpolationMode.HighQualityBicubic; 

g.DrawImage(imgToResize, 0, 0, newWidth, newHeight); 
g.Dispose(); 

return (Image)b; 

Tôi chưa cài đặt Compact Framework, nhưng có vẻ như điều này sẽ phù hợp với bạn.

+0

Điều đó có vẻ tốt. Nhưng tôi không thể dễ dàng sử dụng nó. Tôi nên đã chỉ ra điều này, nhưng ứng dụng này là trên Compact Framework và GetThumbnailImage không phải là trong khuôn khổ nhỏ gọn. Nếu nó xuống đến nó, tôi có thể tái kích thước hình ảnh ở phía máy chủ, nhưng tôi thà gửi một hình ảnh nhỏ hơn trên không nếu có thể. – Vaccano

+0

Bạn nên tránh GetThumbnailImage dù sao đi nữa - nó chỉ thích hợp cho hình ảnh 40x40 hoặc nhỏ hơn. –

3

Nếu độ sâu màu không phải là vấn đề, bạn có thể thay đổi màu đen và trắng hoặc 16 chế độ màu. Cần có một khoản tiết kiệm đáng kể so với yêu cầu lưu trữ 24 bpp (hoặc 32 bpp với alpha) của png. Một thứ khác cần lưu ý là lưu nó dưới dạng tệp .gif ở chế độ 256 màu.

Khi bạn đang lưu dữ liệu chữ ký, tôi nghĩ rằng việc thay đổi kích thước của hình ảnh sẽ là một ý tưởng tồi. Bạn cũng có thể xem xét áp dụng nén không mất dữ liệu như zip, nhưng có khả năng là tính toán chuyên sâu hơn bạn yêu cầu.

+0

Bất kỳ gợi ý nào về cách thực hiện điều này trong C#? – Vaccano

+0

Không phải cá nhân, nhưng tìm kiếm nhanh đã bật liên kết này: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=554acd82-d87d-43c6-a984-8c625387b198&displaylang=vi Trích dẫn đã chọn: "Trong .NET Compact Framework, không có phương pháp đơn giản để lưu các đối tượng Bitmap hoặc nhận được một xử lý bitmap từ một đối tượng Bitmap do đó cần sử dụng một chút thủ thuật để truy cập dữ liệu pixel của bitmap. " – arootbeer

+0

Sản phẩm của công ty tôi, DotImage Photo, có thể làm điều này và là một SDK miễn phí. Chỉ cần gọi GetChangedPixelFormat() trên một AtalaImage - chuyển sang định dạng được lập chỉ mục, sau đó lưu với AtalaImage.Save(). https://www.atalasoft.com/photofree –

0

Thử chuyển sang bitmap đơn sắc thuần túy. Chúng cực kỳ nhỏ, vì chúng chỉ sử dụng một bit cho mỗi pixel.

EDIT: Tôi là kẻ nói dối. Chỉ cần cố gắng này trong Paint và nó khoảng 40k so với 20k ban đầu. Tôi có thể thề rằng những người đã tiết kiệm không gian lớn khi tôi sử dụng chúng trước đây ...

EDIT EDIT: OK, dường như chúng có tiết kiệm lớn. Nó chỉ là cho những hình ảnh này, PNG thậm chí còn tiết kiệm lớn hơn. Chỉ cần thử một bitmap 16-màu thay vào đó và nó thổi nó lên đến 150k.

CHỈNH SỬA CHỈNH SỬA CHỈNH SỬA: NHƯNG, bitmap đơn sắc nén đến 9k byte, trong khi PNG vẫn ở 20k thậm chí nén.


Vì vậy, có vẻ như nếu bạn muốn đi tuyến đường nén, trước tiên bạn có thể chuyển sang bitmap đơn sắc, sau đó nén cho hình ảnh khoảng một nửa kích thước của PNG.

Bạn cũng có thể loại bỏ một số thông tin ra khỏi hình ảnh. Ví dụ, trên màn hình đó, điều duy nhất thực sự cần để giữ lại một hình ảnh là chữ ký. Các thanh trên và dưới có thể bị tách ra và thông tin số có thể được gửi như vậy và được lưu trữ riêng biệt.

+0

Tôi không chắc chắn chính xác cách các cửa sổ lưu trữ các tệp bitmap của nó, nhưng tôi biết rằng chúng hoàn toàn không nén. .png ít nhất có một số nén. – arootbeer

0

đánh lửa pháo hoa với một bức ảnh, mà sẽ không giống nhau nhưng nên đưa ra một ý tưởng

66% quality JPG with no smoothing is 17.5k 
PNG8 with 256 colours is 58K (down to 42 using websnap palette) 
PNG8 with black and white palette is 14k 

Lưu ý rằng nhiều tập tin hình ảnh sẽ nhỏ hơn với một ảnh chụp màn hình kể từ khi có nhóm tiếp giáp lớn của cùng màu, và điều đó có thể đặc biệt đúng với màu đen và trắng. Nó có lẽ cũng sẽ phụ thuộc vào thuật toán được sử dụng để chuyển đổi hình ảnh, nhưng bạn có thể muốn chỉ cần đi với bất cứ điều gì bạn có thể tìm ...

2

Thay đổi bảng màu thành độ sâu màu thấp hơn. Hãy xem this question (cũng nhìn vào câu trả lời thực sự) cho thấy chuyển đổi thành 1bpp. Bạn có thể đi đến 8bpp thay vì 1bpp và tiết kiệm đáng kể kích thước. Cơ chế chuyển đổi sẽ giống như cơ chế được hiển thị.

EDIT

Suy nghĩ ra khỏi hộp, bạn cũng có thể xem xét chỉ gửi các điểm dữ liệu từ phần trên của màn hình và vector chữ ký, và có máy chủ tái tạo màn hình cho bạn. Nếu kích thước thực sự là một vấn đề lớn, tôi có thể điều tra điều đó.

EDIT 2

Nếu chỉ đơn giản là thay đổi kích thước hình ảnh là một giải pháp hợp lý (bạn rõ ràng sẽ bị mất dữ liệu khi làm như vậy) sau đó bạn có thể sử dụng không gian tên Imaging trong SDF để tạo ra một hình ảnh thu nhỏ như Alex explains here.

1

Nếu hình ảnh đơn sắc được chấp nhận, bạn có thể thử TIFF G4 (nén không mất dữ liệu). TIFF G4 được biết đến là rất hiệu quả trong kích thước tập tin để lưu trữ hình ảnh màu đen và trắng. Thật không may tôi không có bất kỳ thông tin có sẵn về cách nó so sánh với PNG, nhưng giá trị điều tra vào nó.

Here là các thông tin và ví dụ về cách để làm điều đó trong C#

0

FWIW lưu trữ các hình ảnh vật lý bên trong SQL server không phải là một giải pháp tối ưu. Nếu bạn đang sử dụng Sql Server 2008, bạn nên xem xét hỗ trợ luồng tệp sẽ cho phép bạn lưu trữ các hình ảnh vật lý trên đĩa và truy cập chúng như thể chúng nằm trong SQL Server.Điều này rất có thể sẽ làm giảm bớt nhu cầu của bạn phải lo lắng về việc kích cỡ.

Các vấn đề liên quan