【问题标题】:How to update the timestamp on a photo or add the time zone on Google+ Photos?如何更新照片上的时间戳或在 Google+ 照片上添加时区?
【发布时间】:2015-07-03 08:36:06
【问题描述】:

使用 Picasa Web API 从我的 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)。

我错过了一些简单的东西吗? 有没有另一种方法来完成同样的事情?我也愿意更改照片的时区。

【问题讨论】:

  • 我不是 Google Api 专家,但我玩过它,似乎虽然没有记录,但您无法更新照片的所有字段。因此,例如,您不能更改 exif 信息,或者图片大小、长度以及 时间戳。 .NET 客户端 API(也是 Java)确实支持更改 时间戳。从表面上看,但服务器会拒绝更新它。因此,这些属性只能在您创建照片时设置一次,因此一种解决方法是使用正确的时间戳以编程方式检索、删除和重新创建您的照片。
  • @nemesv 你说的一切都有道理。但是,您可以进入 Google+ 照片网站上的图片详细信息,并轻松更改时间戳、时区和许多其他内容。所以这是可能的。只是如何做的问题。
  • 是的,如果您检查浏览器控制台网络标签,Google+ 照片没有使用 Picasa Web API,而是使用不同的(可能仅限内部)API,所以这就是为什么您可以在那里更改时间戳...
  • 在 selenium 中执行并让它运行一夜......
  • 类似的问题已多次发布到Picasa API Group,但大多数都没有得到答复。尽管如此,再次询问可能还是值得一试的,有时 Google 开发人员的反应出人意料。

标签: c# google-plus photos picasa


【解决方案1】:

我自己解决了你的问题,所以让我在这里分享我对情况的评估:

Google 似乎从图像的 Exif 标签中获取了显示的元信息。 虽然在查看 .net API 时设置 Exif 标记似乎是可能的(我什至反编译了 Google 程序集,以确保一切正确),但 Google 在发布更新时根本不会将它们重新嵌入到图片中。

所以我的方法是下载所有图像,更改它们的 Exif 信息并重新上传它们(就像 nemesv 建议的那样)。不幸的是,谷歌确实剥离了所有下载的文件的 Exif 标签(thx big G!),并用人造标签(例如应用程序名称“Google”)和空值(创建时间 = null)替换它们。 生成在.net中从头开始的Exif信息充其量是hackish(必须强制构造System.Drawing.Imaging.PropertyItem的实例[具有内部构造函数,可以完成]并正确参数化它们)。但是,由于我在我的主要工作的应用程序的成像模块中做了这样的事情(从现有图片中获取 Exif 信息,重新生成图片并将 Exif 重新添加到新图片中),我认为这种方法是可行的。

这里有一些概念验证代码供您参考。它并没有一路走下去(一个完整的解决方案应该读取现有 picasa 条目的日期并将它们缓存在一个列表中,以便在下载的图像上重新应用它们),但它确实涵盖了棘手的部分。

private void button1_Click(object sender, EventArgs e)
{
    var service = new PicasaService("exampleCo-exampleApp-1");
    service.setUserCredentials("me.myself@gmail.com", "-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("hommel.peter@gmail.com", 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,但当您尝试为其他 Exif 标签查找正确的 PropertyItem 内容时,它们仍然对您有用。

由于我不再知道此代码来自哪里,请任何人写下评论,如果他/她知道,我也可以在此处添加此信息。

【讨论】:

  • 虽然这不是我所希望的,但这可能是可以实现的最好的。就我而言...我需要附加 GPSDateStamp Exif 标记 - 这可以让 Google+ 找出时区并将它们上传到新的 Google+ 相册。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多