我自己解决了你的问题,所以让我在这里分享我对情况的评估:
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 内容时,它们仍然对您有用。
由于我不再知道此代码来自哪里,请任何人写下评论,如果他/她知道,我也可以在此处添加此信息。