gpt4 book ai didi

c# - 如何使用元数据创建 png 文件

转载 作者:行者123 更新时间:2023-12-05 05:18:51 38 4
gpt4 key购买 nike

我正在尝试创建一个 PNG 文件来保存我们捕获的图像数据,但在尝试设置公司、CameraManufacturer、亮度等元数据时我真的很痛苦。

Google PNGCS 库可以执行此操作,但我必须先编写文件,然后重新加载并重新保存。

我们使用的是 WPF,所以我认为我可以使用更通用的类,如 BitmapMetadataPngBitmapEncoderJpegBitmapEncoder

但是,我不断遇到 为我想使用的属性抛出类型为“System.NotSupportedException” 的异常。您可以在我放在本文底部创建的元数据中的变量 watch 中看到这一点。

Image 类实际上是一个包含宽度高度、文件类型(如 png 或 gif 等)的数据结构。

从摄像头获取图像数据,添加我们想要的标签并保存到文件应该很简单。

与负载相同 - 我们应该能够获得它们。

代码:

/// <summary>
/// Handles the load, save, and export of images
/// </summary>
public interface IImageProvider
{
string GetPath(string fileNameWithoutExtension, ImageVersion version);
string GetPath(Plate plate);
Image Load(string path);
Image Load(string path, int width);
Image Load(Plate plate);
Image LoadThumb(Plate plate);
Task<Image> LoadAsync(Plate plate);
Task<Image> LoadAsync(Plate plate, ImageVersion version);
void Save(Image image, string path, Resolution resolution);
void Save(Image image, string name, ImageCategories category, Resolution resolution);
void Save(Plate plate, Image image, Resolution resolution);
Task SaveAsync(Image image, string path, Resolution resolution);
void Export(Image image, string name, ExportFormats format, string directory, Resolution resolution);
void ExportAsync(Image image, string path, ExportFormats format, string directory, double increment, Resolution resolution);
Task<Image> Import(string fileName, Project project);
void Delete(Plate plate);
Image Load(Plate plate, IStage stage);
}

class ImageProvider
{
private void Save(Image image, string name, ExportFormats format, string directory, Resolution resolution)
{
BitmapEncoder bitmapEncoder = null;

//Determine the type of the export
switch (format)
{
case ExportFormats.bmp:
bitmapEncoder = new BmpBitmapEncoder();
break;
case ExportFormats.jpg:
bitmapEncoder = new JpegBitmapEncoder();
break;
case ExportFormats.png:
bitmapEncoder = new PngBitmapEncoder();
break;
case ExportFormats.tiff:
bitmapEncoder = new TiffBitmapEncoder();
break;
}

if (bitmapEncoder != null)
{
var source = ResizeToResolutionUniform(image, resolution);
ReadOnlyCollection<ColorContext> colorContexts = null;
BitmapMetadata metadata = new BitmapMetadata("png");
BitmapSource thumbnail = null;
BitmapFrame bitmapFrame = BitmapFrame.Create(source, thumbnail, metadata, colorContexts);

bitmapEncoder.Frames.Add(bitmapFrame);
//Get the folder and extension
var extension = Enum.GetName(typeof(ExportFormats), format);
var path = Path.Combine(directory, name + "." + extension);

//Create the directory if needed
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
Directory.CreateDirectory(directory);

if (image.ProcessingSettings != null)
{
BitmapMetadata bmp = bitmapEncoder.Frames[0].Metadata as BitmapMetadata;
BitmapMetadata bitmapMetadata = (BitmapMetadata)bitmapEncoder.Frames[0].Metadata;//bitmapEncoder.Metadata;

if (!AddMetatDataTags(bitmapMetadata, image.ProcessingSettings))
LogW($"Could not to {path}");
}

using (FileStream fileStream = new FileStream(path, FileMode.Create))
{
//Save the image
bitmapEncoder.Save(fileStream);
}
}
}


public bool AddMetatDataTags(BitmapMetadata bitmapMetadata, IImageProcessingSettings settings)
{
CultureInfo culture = CultureInfo.InvariantCulture;
var ret = false;

if (bitmapMetadata != null)
{
// 1 off invariant information
// Note: the PNG specification does not support many of these metadata properties (which are based on EXIF, which is NOT by the PNG spec)
bitmapMetadata.SetQuery("/tEXt/Author", Environment.UserName); //Environment.UserName;
object obj = bitmapMetadata.GetQuery("/tEXt/Author");
string s = obj.ToString();
AddKey(bitmapMetadata, 1, "CameraManufacturer", "Singer Instrument Company Limited");
AddKey(bitmapMetadata, 2, "CameraModel", "Phenobooth");
AddKey(bitmapMetadata, 0, "ApplicationName", "PhenoSuite");
AddKey(bitmapMetadata, 3, "Brightness", Convert.ToString(settings.Brightness, culture)); // Capture specific data
AddKey(bitmapMetadata, 4, "Exposure", Convert.ToString(settings.Exposure, culture));
AddKey(bitmapMetadata, 5, "Gain", Convert.ToString(settings.Gain, culture));
//...
ret = true;
}
return ret;
}

/*
* The tag dictionary in the bitmap properties has a strange implementation - based on a separated key value pair
* if n = 0 entry like: /iTXt/Keyword = key /iTXt/TextEntry = val
* if n > 0 entry like: /[n]iTXt/Keyword = key /[n]iTXt/TextEntry = val
*/
private void AddKey(BitmapMetadata metaData, int n, string key, string val)
{
var _key = string.Format($"iTXt/{0}{1}{2}", (n > 0) ? "[" : "", (n > 0) ? n.ToString() : "", (n > 0) ? "]" : "");

try
{
metaData.SetQuery(_key + "Keyword", key.ToCharArray()); // need to convert using ToCharArray as internal representation is based on the LPSTR C type
metaData.SetQuery(_key + "TextEntry", val.ToCharArray());
}
catch (Exception e)
{
LogE($"Could not add metadata key:{key} index: {n} {e.Message}");
throw;
}
}

public class Image
{
#region Constructors

/// <summary>
/// Creates an image optionally copying the metadata
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="_imageMetadata"></param>
public Image(int width, int height, PixelFormat format, ImageMetadata _imageMetadata) : this()
{
Width = width;
Height = height;
Format = format;
ImageMetadata = _imageMetadata;
}
...
}

当我查看创建的元数据时,有许多不受支持的属性 -事实上,我已经尝试了各种方法来解决这个问题,我确信这曾经有效,但我无法弄清楚发生了什么变化。

新元数据对象上的 watch 示例:Meta Data

最佳答案

这是我用来从 iTXt png 元数据中获取键值对的代码

public static class ImageUtils
{
/// <summary>
/// Captures all or part of the raw png metadata.
/// Can use this to capture PhonoBooth metadata by setting the filter to "iTXt"
///
/// throws: ArgumentException if not a png file
/// </summary>
/// <param name="imageFilePath"></param>
/// <param name="itemMap"></param>
/// <param name="filter"> optional filter on the key (contains)</param>
/// <returns>true if successful, false otherwise.</returns>
public static bool GetMetaDataItems(string imageFilePath, ref Dictionary<string, string> itemMap, string filter=null)
{
Assertion<ArgumentException>(imageFilePath.ToLower().EndsWith(".png"), "Expected png file");

var ret = false;
var query = string.Empty;
itemMap.Clear();

try
{
using (Stream fileStream = File.Open(imageFilePath, FileMode.Open))
{
var decoder = BitmapDecoder.Create(fileStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
GetMetaDataItems(decoder.Frames[0].Metadata as BitmapMetadata, ref itemMap, filter);
}

ret = true;
}
catch (Exception e)
{
ret = false;
LogE(e.Message);
}

return ret;
}

/// <summary>
/// Used to get the meta data from png file metadata
/// Can use this to capture PhonoBooth metadata by setting the filter to "iTXt"
/// </summary>
/// <param name="bitmapMetadata"></param>
/// <param name="itemMap"></param>
/// <param name="filter">set this to iTXt for Phenosuite image data</param>
/// <param name="query">initally null, used in recursive calls to get the child data</param>
public static void GetMetaDataItems(BitmapMetadata bitmapMetadata , ref Dictionary<string, string> itemMap, string filter= null, string query = null )
{
if (query == null)
query = string.Empty;

if (bitmapMetadata != null)
{
var key = string.Empty;

foreach (string relativeQuery in bitmapMetadata)
{
var fullQuery = query + relativeQuery;
// GetQuery returns an object: either a string or child metadata
// If a string then it is one of 4 values: ["Keyword", "Translated", "Compression", "Language Tag", "TextEntry"]
// We want the Keyword and the subsequent TextEntry items, the tags are a sequence in the order specified above
var metadata = bitmapMetadata.GetQuery(relativeQuery);
var innerBitmapMetadata = metadata as BitmapMetadata;

if (innerBitmapMetadata == null)
AddToMap(ref key, fullQuery, metadata?.ToString(), ref itemMap, filter); // Not a metadata structure so it is data - therefore check and Add to map
else
GetMetaDataItems(innerBitmapMetadata, ref itemMap, filter, fullQuery); // Recursive call
}
}
}

/// <summary>
/// Suitable for Png iTXt metadata
/// This is used to buld the item map from the metadata
/// </summary>
/// <param name="key">key like "Application" or "Lighting Mode"</param>
/// <param name="fullQuery">metadata query</param>
/// <param name="metadata">image metadata</param>
/// <param name="itemMap">map being populated from the metadata</param>
/// <param name="filter">we dont want all the meta data - so this filters on the "sub folder" of the meta data -Phenosuite uses "iTXt" </param>
private static void AddToMap(ref string key, string fullQuery, string metadata, ref Dictionary<string, string> itemMap, string filter)
{
if (metadata != null)
{
if (!fullQuery.Contains("Translated"))
{
if ((filter == null) || ((fullQuery.Contains(filter))))
{
if (fullQuery.Contains("Keyword"))
key = metadata;

if (fullQuery.Contains("TextEntry") && (key != null))
itemMap[key] = metadata?.ToString();
}
}
}
}
}

希望这对某些人有所帮助 - 因为我发现它很难理解!

关于c# - 如何使用元数据创建 png 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47163090/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com