2015-04-24 16 views
12

Korzystanie z Picasa Web API odzyskać zdjęcia z mojego albumu fotograficznego Google+ i próbować zmienić znacznik czasu (czas było złe w moim telefonie, więc próbuje go naprawić):Jak zaktualizować znacznik czasu na zdjęciu lub dodać strefę czasową w Zdjęciach 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(); 

Niestety, podczas gdy .Update metoda się powiedzie, znacznik czasu się nie zmienia. Próbowałem również zmienić strefę czasową zdjęcia (np. Ten sam użytkownik robi ręcznie, jak ten http://i.imgur.com/pxYSi9S.png).

Czy brakuje mi czegoś prostego? Czy istnieje inny sposób osiągnięcia tego samego? Postanowiłbym także zmienić strefę czasową zdjęcia.

+2

Nie jestem ekspertem od Google Api, ale grałem z nim trochę i wygląda na to, że nie jest to udokumentowane, ale nie można zaktualizować wszystkich pól zdjęcia. Na przykład nie można zmienić informacji o exif, ani rozmiaru zdjęcia, długości ani ** znacznika czasu **. Interfejs API klienta .NET (także Java) obsługuje zmianę ** znacznika czasu **. na powierzchni, ale serwer odmówi jej aktualizacji.Dlatego te właściwości można ustawić tylko raz podczas tworzenia zdjęcia, dlatego obejściem byłoby programowe pobieranie, usuwanie i ponowne tworzenie zdjęć z poprawnym znacznikiem czasu. – nemesv

+0

@nemesv Wszystko co mówisz ma sens. Możesz jednak przejść do szczegółów zdjęcia w witrynie Zdjęcia Google+ i łatwo zmienić sygnaturę czasową, strefę czasową i całą masę innych rzeczy. Jest to możliwe. Tylko pytanie, jak. – AngryHacker

+2

Tak, jeśli zaznaczysz kartę sieci w konsoli przeglądarki, ** Google + zdjęcia nie używają interfejsu Picasa Web API **, ale innego (prawdopodobnie wewnętrznego) interfejsu API, dlatego właśnie możesz zmienić sygnaturę czasową ... – nemesv

Odpowiedz

2

miałem iść w swoim problemem sam, więc pozwól mi podzielić się moją ocenę sytuacji tutaj:

Google wydaje się mieć wyświetloną meta informacje z tagów EXIF ​​obrazu. Mimo że ustawienie tagów Exif wydaje się możliwe, patrząc na API .net (nawet dekompilowałem zespoły Google, aby upewnić się, że wszystko jest w porządku), Google po prostu nie umieszcza ich ponownie w obrazie podczas wydawania aktualizacji.

Moje podejście polega więc na pobieraniu wszystkich zdjęć, zmianie ich danych Exif i ponownym ich przesłaniu (jak sugeruje nemesv). Niestety Google usuwa wszystkie pobrane pliki ich tagów Exif (thx big G!) I zastępuje je sztucznymi (np. Nazwa aplikacji "Google") i wartościami pustymi (czas utworzenia = null). Generowanie Exif info od zera w .net jest w najlepszym wypadku hackowate (trzeba przymusowo konstruować wystąpienia System.Drawing.Imaging.PropertyItem [ma wewnętrzny konstruktor, można to zrobić] i poprawnie je sparametryzować). Ale, jak już zrobiłem coś takiego (wziąłem Exif info z istniejącego obrazu, zregenerowanego obrazu i ponownie dodałem Exif do nowego zdjęcia) w module obrazowania aplikacji w mojej głównej pracy, uważam, że to podejście jest wykonalne.

Oto kilka dowodów kodu idei dla ciebie. Nie idzie do końca (kompletne rozwiązanie powinno odczytywać daty istniejących wpisów Picasa i umieszczać je w pamięci podręcznej na liście, aby ponownie je stosować na pobranych obrazach), ale obejmuje ono trudne części.

private void button1_Click(object sender, EventArgs e) 
{ 
    var service = new PicasaService("exampleCo-exampleApp-1"); 
    service.setUserCredentials("me.mys[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(); 
    } 
} 

Proszę o cierpliwość za opublikowanie nieco zabrudzonego kodu, ale bardzo szybko to wymyśliłem.

Znajdziesz dwa skomentowane linie w powyższym kodzie, które używają niektórych klas Exif, które znalazłem gdzieś w sieci jakiś czas temu. Gdy gdzie zbyt dużo kodu ujawniają tu bezpośrednio, mam przesłanych im Pastebin:

http://pastebin.com/pkZMVZ9i

Choć pozwalają one tylko do odczytu Exif, ale mimo to może być przydatne dla Ciebie, gdy próbuje znaleźć właściwą PropertyItem koncentruje się na innych znacznikach Exif.

Ponieważ nie wiem, skąd wziął się ten kod, proszę, proszę, jeśli ktoś napisze komentarz, to ja też mogę dodać tę informację.

+0

Chociaż nie jest to tym, na co liczyłem, to prawdopodobnie najlepsze, co można osiągnąć. W moim przypadku ... muszę dołączyć znacznik GPSDateStamp Exif - dzięki temu Google+ może określić strefę czasową i przesłać je do nowego albumu Google+. – AngryHacker

Powiązane problemy