У меня есть приложение, которое извлекает изображение из веб-службы. Веб-служба будет внедрять некоторые метаданные в изображение перед отправкой на клиент С#.
Это часть метода. Он извлекает поток из объекта Response и создает изображение из потока. Обратите внимание, что я использую System.Drawing.Image
, а не System.Windows.Controls.Image
- это означает, что я не могу использовать какой-либо ImageSource или BitmapSource.
System.Drawing.Image img = null;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
Stream stream = response.GetResponseStream();
img = System.Drawing.Image.FromStream(stream);
.......
}
return img;
Изображение выглядит отлично, но внутри встроены метаданные. Изображение находится в формате PNG, и есть другой способ, который извлекает информацию из Image
. В общей сложности шесть встроенных метаданных. Формат PNG (фрагменты PNG) описывается здесь здесь. Данные сохраняются в разделе "tEXt".
public static Hashtable GetData(Image image)
{
Hashtable metadata = null;
data = new Hashtable();
byte[] imageBytes;
using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, image.RawFormat);
imageBytes = new byte[stream.Length];
imageBytes = stream.ToArray();
}
if (imageBytes.Length <= 8)
{
return null;
}
// Skipping 8 bytes of PNG header
int pointer = 8;
while (pointer < imageBytes.Length)
{
// read the next chunk
uint chunkSize = GetChunkSize(imageBytes, pointer);
pointer += 4;
string chunkName = GetChunkName(imageBytes, pointer);
pointer += 4;
// chunk data -----
if (chunkName.Equals("tEXt"))
{
byte[] data = new byte[chunkSize];
Array.Copy(imageBytes, pointer, data, 0, chunkSize);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte t in data)
{
stringBuilder.Append((char)t);
}
string[] pair = stringBuilder.ToString().Split(new char[] { '\0' });
metadata[pair[0]] = pair[1];
}
pointer += (int)chunkSize + 4;
if (pointer > imageBytes.Length)
break;
}
return data;
}
private static uint GetChunkSize(byte[] bytes, int pos)
{
byte[] quad = new byte[4];
for (int i = 0; i < 4; i++)
{
quad[3 - i] = bytes[pos + i];
}
return BitConverter.ToUInt32(quad);
}
private static string GetChunkName(byte[] bytes, int pos)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 4; i++)
{
builder.Append((char)bytes[pos + i]);
}
return builder.ToString();
}
В Windows 7 все шесть частей метаданных обнаружены и извлечены. Короче говоря, в среде Windows 7 мне удалось получить все, что мне нужно.
Когда я переношу это на терминал Windows 10 (также пробовал Windows 8), все становится по-другому. Я могу извлечь только 2 части метаданных из Image
.
Поскольку мой метод GetData()
преобразует Image
в byte[]
, поэтому я попытался извлечь данные прямо из потока веб-службы. Я преобразовал поток в byte[]
и использовал ту же технику для извлечения метаданных из byte[]
. Мне удалось вернуть все 6 метаданных с помощью этого метода.
Итак, вопрос: Что изменилось? В Windows 7 он работает отлично, но не так в Windows 8 и 10. Я все еще могу вернуть данные, если не буду поток в Image
. Где-то в этом процессе метаданные теряются. Он либо теряется, когда я конвертирую поток в Image
, или когда я преобразовываю Image
обратно в byte[]
. В качестве примечания я попытался преобразовать строку byte[]
в строку. Строковое представление byte[]
из потока отличается от byte[]
от Image
. Используя правильный кодировщик, я мог видеть 4 метаданных, отсутствующих в более позднем byte[]
.