我使用 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 似乎从图像的 Exif 标签中获取显示的元信息。 虽然在查看 .net API 时似乎可以设置 Exif 标签(我什至反编译了 Google 程序集,以确保一切正确),但 Google 在发布更新时根本没有将它们重新嵌入到图片中。
所以我的方法是下载所有图像,更改它们的 Exif 信息并重新上传它们(像 nemesv 建议的那样)。不幸的是,谷歌确实删除了所有下载的文件的 Exif 标签(thx big G!)并用人工标签(例如应用程序名称“Google”)和空值(创建时间 = null)替换它们。 在 .net 中从头开始生成 Exif 信息充其量是骇人听闻的(必须强行构建 System.Drawing.Imaging.PropertyItem [具有内部构造函数,可以完成] 的实例并正确地参数化它们)。但是,由于我在我的主要工作的应用程序的成像模块中做了类似的事情(从现有图片中获取 Exif 信息,重新生成图片并将 Exif 重新添加到新图片),我认为这种方法是可行的。
这是为您提供的一些概念验证代码。它不会一路走下去(完整的解决方案应该读取现有 picasa 条目的日期并将它们缓存在列表中以将它们重新应用到下载的图像上),但它确实涵盖了棘手的部分。 请容忍我发布了一些脏代码,但我很快就把它拼凑在一起了。 你会在上面的代码中找到两行注释掉的代码,它们使用了我前段时间在网上找到的一些 Exif 类。由于他们直接在这里公开了太多代码,我已经将它们上传到 Pastebin: 虽然它们只允许读取 Exif,但在您尝试为其他 Exif 标签找到合适的 PropertyItem 内容时,它们仍然对您有用。 因为我不知道这段代码是从哪里来的,如果有人知道,请写评论,这样我也可以在这里添加这些信息。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();
}
}
关于c# - 如何更新照片上的时间戳或在 Google+ 照片上添加时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29852580/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
我有一大串格式化数据(例如JSON),我想使用Psychinruby同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解