Cách lấy dữ liệu EXIF ​​từ tệp bằng C #


77

Tôi muốn viết một chương trình nhỏ bằng C # xem qua các bức ảnh jpeg của tôi và, chẳng hạn, sắp xếp chúng vào các thư mục ngày tháng (sử dụng các quy ước hẹn hò của TÔI, chết tiệt ...).

Có ai biết một cách tương đối dễ dàng để lấy dữ liệu EXIF ​​như Ngày và Giờ hoặc Phơi sáng theo chương trình không? Cảm ơn!


Hỗ trợ tích hợp của BCL cho siêu dữ liệu hình ảnh khá hạn chế. Tôi đã làm việc với siêu dữ liệu như Exif từ năm 2002 và có một thư viện đơn giản nhưng mạnh mẽ để trích xuất dữ liệu đó cho .NET .
Drew Noakes vào

1
Tại sao cái này bị đóng? Nó tập trung vào một vấn đề, thoát khỏi các tệp. Ngoài ra còn có một câu trả lời rõ ràng và tập trung.
mafu

Câu trả lời:


23

Kiểm tra trình trích xuất siêu dữ liệu này . Nó được viết bằng Java nhưng cũng đã được chuyển sang C #. Tôi đã sử dụng phiên bản Java để viết một tiện ích nhỏ để đổi tên các tệp jpeg của mình dựa trên thẻ ngày tháng và mô hình. Rất dễ sử dụng.


EDIT trình trích xuất siêu dữ liệu cũng hỗ trợ .NET. Đây là một thư viện rất nhanh và đơn giản để truy cập siêu dữ liệu từ hình ảnh và video.

Nó hỗ trợ đầy đủ Exif, cũng như IPTC, XMP và nhiều loại siêu dữ liệu khác từ các loại tệp bao gồm JPEG, PNG, GIF, PNG, ICO, WebP, PSD, ...

var directories = ImageMetadataReader.ReadMetadata(imagePath);

// print out all metadata
foreach (var directory in directories)
foreach (var tag in directory.Tags)
    Console.WriteLine($"{directory.Name} - {tag.Name} = {tag.Description}");

// access the date time
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
var dateTime = subIfdDirectory?.GetDateTime(ExifDirectoryBase.TagDateTime);

Nó có sẵn qua NuGetmã trên GitHub .


Điều này thật tuyệt nếu ứng dụng Windows của bạn luôn hiển thị hình ảnh iPhone ở một bên hoặc lộn ngược. Có một Orientationthẻ trong mỗi hình ảnh thường là một con số kỳ diệu, nhưng thư viện này cho bạn biết sự xoay vòng (tức là Rotate 180hoặc Rotate 90 CCW).
Chris Akridge

47

Như được đề xuất, bạn có thể sử dụng một số thư viện của bên thứ ba hoặc làm điều đó theo cách thủ công (không nhiều công việc), nhưng đơn giản và linh hoạt nhất có lẽ là sử dụng chức năng tích hợp sẵn trong .NET. Để biết thêm, hãy xem:

Tôi nói "nó linh hoạt nhất" bởi vì .NET không cố gắng diễn giải hoặc kết hợp dữ liệu theo bất kỳ cách nào. Đối với mỗi EXIF, về cơ bản, bạn nhận được một mảng byte. Điều này có thể tốt hoặc xấu tùy thuộc vào mức độ kiểm soát bạn thực sự muốn.

Ngoài ra, tôi nên chỉ ra rằng danh sách thuộc tính trên thực tế không tương ứng trực tiếp với các giá trị EXIF. Bản thân EXIF ​​được lưu trữ trong nhiều bảng với các ID chồng chéo, nhưng .NET đặt mọi thứ trong một danh sách và xác định lại ID của một số mục. Nhưng miễn là bạn không quan tâm đến ID EXIF ​​chính xác, bạn sẽ ổn với ánh xạ .NET.


Chỉnh sửa: Có thể làm điều đó mà không cần tải hình ảnh đầy đủ theo câu trả lời sau: https://stackoverflow.com/a/552642/2097240


9
Truy cập Bitmap.PropertyItems yêu cầu đọc toàn bộ tệp vào bộ nhớ. Nếu bạn tạo Bitmap, truy cập PropertyItems và không làm gì khác, bạn có thể sử dụng XPerf để biết rằng ứng dụng của bạn đã truy cập tệp hình ảnh và đọc tất cả vào bộ nhớ. Đối với máy tính của tôi, một tệp 3,4mb có giá trị IO> 700ms, chỉ để nhận EXIF ​​qua PropertyItems :(.
Tristan

4
Để so sánh, PhotoViewer của Picasa chỉ đọc 20 - 30k từ mỗi tệp mà nó chạm vào. Những lần đọc đó chỉ tốn ~ 25ms. Chà; Tôi rất thích trò chuyện với anh chàng / cô gái đã viết những thứ đó. (Dữ liệu được thu thập bằng cách lập hồ sơ khởi động PhotoViewer bằng XPerf).
Tristan

@Tristan: Thông tin hữu ích, tuy nhiên bạn có thường xuyên truy cập siêu dữ liệu hình ảnh mà không muốn chính hình ảnh đó không? Tôi chắc chắn có một số trường hợp, nhưng tôi nghĩ trong phần lớn trường hợp, một trường hợp sẽ hiển thị hình ảnh (hoặc làm việc với dữ liệu của nó) VÀ siêu dữ liệu đó cùng một lúc.
jrista

5
@jrista Bao lâu thì tôi muốn chỉ siêu dữ liệu? Hầu hết thời gian. Ví dụ: hãy tưởng tượng bạn muốn sắp xếp hoặc lọc một nhóm hình ảnh theo một phần siêu dữ liệu. Sắp xếp theo ngày tháng thực hiện là một việc khá phổ biến và để có được thông tin đó, bạn phải truy cập vào siêu dữ liệu.
Tristan

1
Câu trả lời này cho thấy cách để làm điều đó với PropertyItems mà không cần tải toàn bộ hình ảnh : stackoverflow.com/a/552642
Daniel Möller


8

Bạn có thể sử dụng TagLib # được các ứng dụng như F-Spot sử dụng . Bên cạnh Exif, nó sẽ đọc một lượng lớn các định dạng siêu dữ liệu cho hình ảnh, âm thanh và video.

Tôi cũng thích API ExifUtils nhưng nó bị lỗi và không được phát triển tích cực.


5

Lớp hình ảnh có các thuộc tính PropertyItems và PropertyIdList. Bạn có thể sử dụng chúng.


Có vẻ như nó chỉ đọc, vì vậy tôi không thể thêm bất kỳ trên hình ảnh mới ...
TigrouMeow

3
Sử dụng chức năng Image.SetPropertyItem (PropertyItem) trên hình ảnh mới.
Morten Christiansen

4

Lấy dữ liệu EXIF ​​từ ảnh JPEG bao gồm:

  1. Tìm kiếm các điểm đánh dấu JPEG đề cập đến phần đầu của dữ liệu EXIF,. ví dụ: thông thường oxFFE1 là điểm đánh dấu được chèn trong khi mã hóa dữ liệu EXIF, là một phân đoạn Ứng dụng, nơi dữ liệu EXIF ​​đi đến.
  2. Phân tích cú pháp tất cả dữ liệu từ 0xFFE1 đến 0xFFE2. Dữ liệu này sẽ là dòng byte, trong tệp được mã hóa JPEG.
  3. Tương đương ASCII của những byte này sẽ chứa nhiều thông tin khác nhau liên quan đến Ngày hình ảnh, Tên kiểu máy ảnh, Độ phơi sáng, v.v.

3

Công cụ dòng lệnh ExifTool của Phil Harvey hoạt động với hàng chục định dạng hình ảnh - bao gồm nhiều định dạng RAW độc quyền - và có thể thao tác nhiều định dạng siêu dữ liệu bao gồm EXIF, GPS, IPTC, XMP, JFIF.

Ứng dụng rất dễ sử dụng, nhẹ, ấn tượng.


1
ExifTool là một công cụ lib / tuyệt vời, nhưng nó được viết bằng Perl nên việc sử dụng nó từ C # bao gồm việc khởi chạy một quy trình bên ngoài.
Drew Noakes

0

Gần đây, tôi đã sử dụng API siêu dữ liệu .NET này . Tôi cũng đã viết một bài đăng trên blog về nó, cho thấy việc đọc, cập nhật và xóa dữ liệu EXIF ​​khỏi hình ảnh bằng C #.

using (Metadata metadata = new Metadata("image.jpg"))
{
    IExif root = metadata.GetRootPackage() as IExif;
    if (root != null && root.ExifPackage != null)
    {
        Console.WriteLine(root.ExifPackage.DateTime);
     }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.