Как обновить временную метку на фотографии или добавить часовой пояс в Google+ Фото?

Используя веб-API Picasa, я извлекаю фотографию из своего фотоальбома Google+ и пытаюсь изменить временную метку (время на телефоне было неправильным, поэтому, пытаясь исправить это):

var service = new PicasaService("exampleCo-exampleApp-1");
service.setUserCredentials("uid", "pwd");
AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri("default"));

PicasaFeed feed = service.Query(query);
var entry = (PicasaEntry)feed.Entries.SingleOrDefault(f => f.Title.Text == "Trip to Italy - ALL");

var ac = new AlbumAccessor(entry);

var photoQuery = new PhotoQuery(PicasaQuery.CreatePicasaUri("default", ac.Id));
PicasaFeed photoFeed = service.Query(photoQuery);

PicasaEntry picasaEntry = photoFeed.Entries[0];

ulong timestamp = Convert.ToUInt64(picasaEntry.GetPhotoExtensionValue("timestamp"));

// deduct 9 hours
DateTime dt = FromUnixTime(pa.Timestamp).AddHours(-9);
picasaEntry.SetPhotoExtensionValue("timestamp", Convert.ToString(ToUnixTime(dt)));

var updatedEntry = (PicasaEntry) picasaEntry.Update();

К сожалению, пока метод .Update завершается успешно, метка времени не изменяется. Я также попытался изменить часовой пояс фотографии (например, тот же самый пользователь делает это вручную http://i.imgur.com/pxYSi9S.png).

Я пропустил что-то простое? Есть ли другой способ сделать то же самое? Я также согласился бы изменить часовой пояс фотографии.

Ответ 1

У меня тоже была проблема, поэтому позвольте мне поделиться моей оценкой ситуации здесь:

Google, похоже, отображает отображаемую метаинформацию из тегов Exif изображения. Хотя установка тегов Exif представляется возможной при просмотре API.net(я даже декомпилировал сборки Google, чтобы убедиться, что все правильно), Google просто не добавляет их в изображение при выпуске обновления.

Итак, мой подход заключается в загрузке всех изображений, изменении их информации Exif и их повторной загрузке (например, предложенный nemesv). К сожалению, Google блокирует все загруженные файлы своих тегов Exif (спасибо large G!) И заменяет их искусственными (например, имя приложения "Google" ) и нулевые значения (время создания = нуль). Генерация. Exif-информация с нуля в .net в лучшем случае хакерская (нужно принудительно построить экземпляры System.Drawing.Imaging.PropertyItem [имеет встроенный конструктор, можно сделать] и правильно их параметризовать). Но, поскольку я сделал что-то вроде этого (вывел Exif-информацию из существующего pic, обновил pic и повторно добавил Exif к новому рис.) В модуль обработки изображений приложения на моей основной работе, я считаю этот подход выполнимым.

Вот несколько примеров кода концепции для вас. Он не проходит полностью (полное решение должно читать даты существующих записей picasa и кэшировать их в списке, чтобы повторно использовать их на загруженных изображениях), но он охватывает сложные элементы.

private void button1_Click(object sender, EventArgs e)
{
    var service = new PicasaService("exampleCo-exampleApp-1");
    service.setUserCredentials("[email protected]", "-secret-");
    AlbumQuery query = new AlbumQuery(PicasaQuery.CreatePicasaUri("default"));


    PicasaFeed feed = service.Query(query);
    var entry = (PicasaEntry)feed.Entries.SingleOrDefault(f => f.Title.Text == "Testalbum");

    var ac = new AlbumAccessor(entry);

    var photoQuery = new PhotoQuery(PicasaQuery.CreatePicasaUri("default", ac.Id));
    PicasaFeed photoFeed = service.Query(photoQuery);

    DirectoryInfo srcdir = Directory.CreateDirectory("C:\\Temp\\Testalbum");
    DownloadAllPhotos("C:\\Temp\\Testalbum", photoFeed.Entries);

    foreach (PicasaEntry oldentry in photoFeed.Entries)
    {
        oldentry.Delete();
    }

    DirectoryInfo tgtdir = Directory.CreateDirectory("C:\\Temp\\Converted");
    foreach (FileInfo imagefile in srcdir.EnumerateFiles())
    {
        Image img = Image.FromFile(imagefile.FullName);

        PropertyItem PiDtOrig = null;
        try
        {
            PiDtOrig = img.GetPropertyItem(0x9003); // id 0x9003 is "DateTimeOriginal"
        }
        catch (System.ArgumentException ex) // this exception is thrown when PropertyItem does not exist 
        {
            PiDtOrig = NewPropertyItem();
            PiDtOrig.Id = 0x9003;
            PiDtOrig.Type = 7;
            PiDtOrig.Len = 4;
        }

        PiDtOrig.Value = BitConverter.GetBytes(DateTimeToInt(DateTime.Now));
        img.SetPropertyItem(PiDtOrig);
        string ConvImgName = tgtdir.FullName + "\\" + imagefile.Name;
        img.Save(ConvImgName);

        //ExifTagCollection exif = new ExifTagCollection(img);
        //Debug.WriteLine(exif);

        Uri postUri = new Uri(PicasaQuery.CreatePicasaUri("[email protected]", ac.Id));
        FileStream fileStream = imagefile.OpenRead();

        PicasaEntry newentry = (PicasaEntry)service.Insert(postUri, fileStream, "image/jpeg", ConvImgName);

        fileStream.Close();
        fileStream.Dispose();
    }
}

private PropertyItem NewPropertyItem()
{
    Type t = typeof (PropertyItem);
    ConstructorInfo ctor = t.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
    Object o = ctor.Invoke(new Object[] { });
    return (PropertyItem) o;
}

private int DateTimeToInt(DateTime theDate)
{
    return (int)(theDate.Date - new DateTime(1900, 1, 1)).TotalDays + 2;
}

// taken from https://codethis.wordpress.com/2008/11/ and modified for this example
static void DownloadAllPhotos(string DirectoryName, AtomEntryCollection photoList)
{
    DirectoryInfo dirInfo = Directory.CreateDirectory(DirectoryName);

    int photoNum = 1;
    foreach (AtomEntry photo in photoList)
    {
        HttpWebRequest photoRequest = WebRequest.Create(photo.Content.AbsoluteUri) as HttpWebRequest;
        HttpWebResponse photoResponse = photoRequest.GetResponse() as
           HttpWebResponse;

        BufferedStream bufferedStream = new BufferedStream(
           photoResponse.GetResponseStream(), 1024);
        BinaryReader reader = new BinaryReader(bufferedStream);

        FileStream imgOut = File.Create(dirInfo.FullName + "\\image" +
           photoNum++ + ".jpg");
        BinaryWriter writer = new BinaryWriter(imgOut);

        int bytesRead = 1;
        byte[] buffer = new byte[1024];
        while (bytesRead > 0)
        {
            bytesRead = reader.Read(buffer, 0, buffer.Length);
            writer.Write(buffer, 0, bytesRead);
        }
        reader.Close();
        reader.Dispose();
        writer.Flush();
        writer.Close();
        writer.Dispose();
    }
}

Пожалуйста, несите меня для публикации грязного кода, но я быстро взбивал это вместе.

Вы найдете две прокомментированные строки в коде выше, которые используют некоторые классы Exif, которые я нашел где-то в сети некоторое время назад. Поскольку они здесь, где слишком много кода раскрывают здесь, я загрузил их в Pastebin:

http://pastebin.com/pkZMVZ9i

Хотя они только позволяют читать Exif, они, тем не менее, могут быть вам полезны, когда вы пытаетесь найти подходящие контенты PropertyItem для других тегов Exif.

Поскольку я не знаю, откуда этот код пришел, пожалуйста, напишите комментарий, если он/она сделает, поэтому я также могу добавить эту информацию здесь.