2022-01-11

Google 相簿將 PNG圖片 自動轉換成 JPG圖片 問題

在下最近編寫文章時發現上載到 Google 相簿的 PNG圖片 變成 JPG圖片
由於 JPG 使用失真壓縮,因此令原本的 PNG 畫質變差,非常麻煩
這個問題不知何時發生,只是碰巧在下檢視某一篇未發佈的文章時,發現圖片的文字的邊緣非常矇糊才發現
幸好之前的文章的圖片未受影響
但在網絡亦找不到問題成因及解決方法,亦不知有甚麼使用關鍵字尋找資料
可能 Google 又有新行動?不知道,但問題發生了便要想辦法解決

測試

見下文
見下文
在下簡單地擷取熒幕的畫面,並將圖片經 Google 相簿的網頁操作上載
原圖為 PNG圖片,亦可以從 Google相簿 中看到檔案副檔名是 PNG ,在下沒有強行修改副檔名偽裝

見下文
當使用原圖解像度顯示時,PNG圖片 自動轉換成 JPG圖片

見下文
但使用 w1600 時則仍然是 PNG圖片
(可以參考 Google 相簿的媒體參數 文章)

見下文
發現當 闊或高超過1600像素,例如 1601x1601 便會自動轉換成 JPG圖片
但有時即使圖片像素不超過 1600像素 仍然自動轉換成 JPG圖片

Google Cloud Platform

既然找不到方法,即是要靠自己解決問題
由於在下是經 Google 相簿的網頁操作上載,在下懷疑是 Google 相簿網頁是問題主因
因此在下嘗試經 Google API 來上載媒體
見下文
先登入 Google Cloud Platform ,並 建立專案

見下文
填寫 專案名稱
位置 使用預設 無機置

見下文
建立專案後,如果沒有特別需要,按 選取專案 開始使用專案

見下文
見下文
在專案頁,按 瀏覽及啟用API

見下文
在API使用頁,按 啟用API和服務

見下文
在API程式庫頁,搜尋需要的 API名稱關鍵字

見下文
例如在下今次雵要使用 Google Photo API (正式名稱是 Photos Library API)

見下文
選擇 API 後,按 啟用

見下文
啟用 API 後,仍未能夠使用,還需要 建立憑證 讓授權人士使用
(即使用 擁有者 都需要授權)

見下文
選取 API 選擇需要 授權的 API
例如在下需要授權使用 Photos Library API

見下文
應用程式名稱 輸入應用程式的名稱
使用者支援電子郵件 通常選取自己的電郵地址
開發人員聯絡資訊電子郵件地址 同樣輸入自己的電郵地址

見下文
範圍可以不作任務設定

見下文
OAuth用戶端的名稱 輸入需要的名稱

見下文
完成後會顯示 OAuth 的用戶編號
亦可以下載 OAuth 用戶的資料

見下文
見下文
有需要可以將 OAuth 重新命名
如果不慎洩漏 OAuth 資料,可以刪除重新建立新的 OAuth

見下文
見下文
OAuth同意畫面 增加 測試使用者
最簡單就是新增擁有者自己的電郵地址

Google OAuth

設定範圍及獲取授權代碼
見下文
要使用 Google OAuth 憑證,要到 https://accounts.google.com/o/oauth2/v2/auth
並附上
  • redirect_uri 讓 Google OAuth 重新導向的位置,使用 urn:ietf:wg:oauth:2.0:oob 以手動形式傳回代碼
  • response_type 使用應用程式,可以 code
  • client_id Google OAuth 的 用戶編號
  • scope Google OAuth 的 使用範圍,如果範圍超過一個,要使用 加號 (+) 連接
並選取以哪個用戶認證 Google OAuth 憑證
例如:
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=<Client-ID>&scope=https://www.googleapis.com/auth/photoslibrary+https://www.googleapis.com/auth/photoslibrary.appendonly+https://www.googleapis.com/auth/photoslibrary.edit.appcreateddata+https://www.googleapis.com/auth/photoslibrary.readonly+https://www.googleapis.com/auth/photoslibrary.readonly.appcreateddata+https://www.googleapis.com/auth/photoslibrary.sharing

  • <Client-ID> 修改為 Google OAuth 的用戶編號

見下文
見下文
見下文
未發佈的應用程式都未經 Google 驗證,因此會有警告訊息
如果應用程式涉及機密資訊,還會被 Google 定義為危險狀態

見下文
選取需要的使用範圍

見下文
完成後會顯示 Google OAuth 的 授權代碼

認證及獲取存取代碼
見下文
https://oauth2.googleapis.com/token 以 POST 發送 HTTP 請求
在 標頭 指定 Content-Typeapplication/x-www-form-urlencoded
並附上
  • redirect_uri 與 Google OAuth 憑證的 redirect_uri 相同
  • grant_type 使用授權代碼 authorization_code
  • client_id 與 Google OAuth 憑證的 client_id 相同
  • client_secret Google OAuth 的 用戶密碼
  • code 提交授權代碼,授權代碼使用後便會失效
發送例子
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
Content-Length: <Data-Length>
Connection: close

redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code&client_id=<Client-ID>&client_secret=<Client-Secret>&code=<Code>

  • <Data-Length> 修改為資料長度
  • <Client-Secret> 修改為 Google OAuth 用戶密碼
  • <Code> 修改為授權代碼
CURL 是其中一種發送 HTTP 請求的工具,以 CURL 作為例子
curl \
--request "POST" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "redirect_uri=urn:ietf:wg:oauth:2.0:oob" \
--data "grant_type=authorization_code" \
--data "client_id=<Client-ID>" \
--data "client_secret=<Client-Secret>" \
--data "code=<Code>" \
"https://oauth2.googleapis.com/token"

CURL 會自動在提交 HTTP 請求時,在標頭自動加上 Host, Content-Length, Connection ,因此在 CURL 可以略卻部分標頭
請求成功後,會傳回 JSON
{
	"access_token": <Access-Token>,
	"expires_in": <Seconds>,
	"refresh_token": <Refresh-Token>,
	"scope": <Scope>,
	"token_type": <Token-Type>
}
  • <Access-Token>授權標頭存取令牌 ,過期後便無法使用
  • <Seconds> 為 過期時間,一般為 3600秒
  • <Refresh-Token>更新令牌
  • <Scope> 與 憑證的 scope 相同
  • <Token-Type> 為 令牌類型,通常為 Bearer

刷新存取代碼
見下文
https://oauth2.googleapis.com/token 以 POST 發送 HTTP 請求
在 標頭 指定
  • Content-Typeapplication/x-www-form-urlencoded
並附上
  • grant_type 使用刷新代碼 refresh_token
  • client_id 與 Google OAuth 憑證的 client_id 相同
  • client_secret 與 Google OAuth 憑證的 client_secret 相同
  • refresh_token 從 Google OAuth 憑證獲得的刷新代碼,刷新代碼可以重覆使用,直至撤銷憑證或憑證24小時內沒有使用
發送例子
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
Content-Length: <Data-Length>
Connection: close

grant_type=refresh_token&client_id=<Client-ID>&client_secret=<Client-Secret>&refresh_token=<Refresh-Token>

  • <Refresh-Token> 修改為刷新代碼
以 CURL 作為例子
curl \
--request "POST" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=refresh_token" \
--data "client_id=<Client-ID>" \
--data "client_secret=<Client-Secret>" \
--data "refresh_token=<Refresh-Token>" \
"https://oauth2.googleapis.com/token"

請求成功後,會傳回 JSON
{
	"access_token": <Access-Token>,
	"expires_in": <Seconds>,
	"scope": <Scope>,
	"token_type": <Token-Type>
}
  • <Access-Token> 為 新的存取令牌
  • <Seconds> 與之前的 expires_in 相同
  • <Scope> 與之前的 scope 相同
  • <Token-Type> 與之前的 token_type 相同

獲得 Google OAuth 憑證後,便可以使用 Photos Library API

Photos Library API

建立相簿
見下文
透過 Photos Library API 在 Google 相簿建立新相簿

見下文
https://photoslibrary.googleapis.com/v1/albums 以 POST 發送 HTTP 請求
在 標頭 指定
  • Content-Typeapplication/json
  • Authorization 為 憑證的 令牌類型 及 存取令牌
並附上
{
	"album": {
		"title": <Album-Title>
	}
}

發送例子
POST /v1/albums HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: application/json
Authorization: <Token-Type> <Access-Token>
Content-Length: <Data-Length>
Connection: close

{"album":{"title":<Album-Title>}}

  • <Token-Type> 修改為 憑證的 令牌類型,通常為 Bearer
  • <Access-Token> 修改為 憑證的 存取令牌
  • <Album-Title> 修改為相簿標題
以 CURL 作為例子
curl \
--request "POST" \
--header "Content-Type: application/json" \
--header "Authorization: <Token-Type> <Access-Token>" \
--data '{"album":{"title":<Album-Title>}}' \
"https://photoslibrary.googleapis.com/v1/albums"

請求成功後,會傳回 JSON
{
	"id": <Album-ID>,
	"title": <Album-Title>,
	"productUrl": <Album-URL>,
	"isWritable": <true-or-false>
}
  • <Album-ID> 為 相簿的 ID
  • <Album-Title> 為 相簿的 標題
  • <Album-URL> 為 相簿的 網頁連結
  • <true-or-false> 為 能否讓相簿寫入資料,true 為可以寫入,false 為不可以寫入

見下文
見下文
提交 HTTP 請求後,重新整理 Google 相簿,會顯示經 Photos Library API 建立的相簿

列出相簿
見下文
見下文
Google 相簿是以 ID 區分,因此要將多媒體加入至相簿,要先知道 相簿 對應的 ID
https://photoslibrary.googleapis.com/v1/albums 以 GET 發送 HTTP 請求
可以在 URL查詢 加入
  • pageSize 為 每次獲取資料的數量,不指定時,預設為 20
  • pageToken 由於 Photos Library API 不會一次過獲取所有資料,傳回的資料會附上下一頁的令牌讓
在 標頭 指定
  • Authorization 為 憑證的 令牌類型 及 存取令牌
發送例子
GET /v1/albums HTTP/1.1
Host: photoslibrary.googleapis.com?pageSize=<Page-Size>&pageToken=<Page-Token>
Authorization: <Token-Type> <Access-Token>
Connection: close
  • <Page-Size> 為 獲取項目的數量,最少1,最多50
  • <Page-Token> 為 獲取下頁項目的令牌,不使用只能獲取首頁的項目
以 CURL 作為例子
curl \
--request "GET" \
--header "Authorization: <Token-Type> <Access-Token>" \
"https://photoslibrary.googleapis.com?pageSize=<Page-Size>&pageToken=<Page-Token>"

請求成功後,會傳回 JSON
{
	"newMediaItemResults": [
		{
			"uploadToken": <Upload-Token>,
			"status": {
				"message": "Success"
			},
			"mediaItem": {
				"id": <Media-ID",
				"productUrl": <Media-URL",
				"mimeType": <MIME-Type-of-Media>,
				"mediaMetadata": {
					"creationTime": <Creation-Time>
					"Width": <Width-of-Media>
					"Height": <Height-of-Media>
				},
				"filename": <Name-of-Media>
			}
		}
	]
}

傳回很多資料,主要是
  • <Media-ID> 為 多媒體ID
  • <Name-of-Media> 為 上載後的名稱

上載多媒體
見下文
相簿可以上載大部分常見的多媒體檔案格式
圖片格式:GIF, JPG, PNG
影片格式:AVI, MKV, MP4
https://photoslibrary.googleapis.com/v1/uploads 以 POST 發送 HTTP 請求
在 標頭 指定
  • Content-Typeoctet-stream
  • Authorization 為 憑證的 令牌類型 及 存取令牌
  • X-Goog-Upload-Protocolraw
  • X-Goog-Upload-Content-Type 為 多媒體檔案的類型
並附上多媒體檔案的二進碼
發送例子
POST /v1/uploads HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: octet-stream
Authorization: <Token-Type> <Access-Token>
X-Goog-Upload-Protocol: raw
X-Goog-Upload-Content-Type: <MIME-Type-of-Media>
Content-Length: <Data-Length>
Connection: close

<Binary-Data-of-Media>
  • <MIME-Type-of-Media> 修改為多媒體檔案的 MIME類型
  • <Binary-Data-of-Media> 修改為 多媒體檔案 的 二進碼
以 CURL 作為例子
curl \
--request "POST" \
--header "Content-Type: octet-stream" \
--header "Authorization: <Token-Type> <Access-Token>" \
--header "X-Goog-Upload-Protocol: raw" \
--header "X-Goog-Upload-Content-Type: <MIME-Type-of-Media>" \
--data-binary @"Path-of-Media-File" \
"https://photoslibrary.googleapis.com/v1/uploads"

使用 CURL 加入檔案的二進碼的資料時,必須使用 --data-binary 不是 --data
請求成功後,傳回一個長字串 為 多媒體上載後的 上載令牌 ,上載令牌時限為24小時

備註:
在下發現當 Content-Type 不使用 octet-stream 改為使用 多媒體檔案的類型
便不需要使用 X-Goog-Upload-Protocol 及 X-Goog-Upload-Content-Type
curl \
--request "POST" \
--header "Content-Type: <MIME-Type-of-Media>" \
--header "Authorization: <Token-Type> <Access-Token>" \
--data-binary @"Path-of-Media-File" \
"https://photoslibrary.googleapis.com/v1/uploads"

便能將操作稍為簡化
多媒體加入至相簿
見下文
上載多媒體後,還需要透過 上載令牌 將多媒體加入到相簿
若不加入相簿,多媒體只會存放到主頁的相片中
https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate 以 POST 發送 HTTP 請求
在 標頭 指定
  • Content-Typeapplication/json
  • Authorization 為 憑證的 令牌類型 及 存取令牌
並附上
{
	"albumId": <Album-ID>,
	"albumPosition": {
		"position": "LAST_IN_ALBUM"
	},
	"newMediaItems": [
		{
			"simpleMediaItem": {
				"fileName": <File-Name>,
				"uploadToken": <Upload-Token>
			}
		}
	]
}

發送例子
POST /v1/mediaItems:batchCreate HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: application/json
Authorization: <Token-Type> <Access-Token>
Content-Length: <Data-Length>
Connection: close

{"albumId":<albumId>,"albumPosition":{"position":"LAST_IN_ALBUM"},"newMediaItems":[{"simpleMediaItem":{"fileName":<File-Name>,"uploadToken":<Upload-Token>}}]}

以 CURL 作為例子
curl \
--request "POST" \
--header "Content-Type: application/json" \
--header "Authorization: <Token-Type> <Access-Token>" \
--data '{"albumId":<albumId>,"albumPosition":{"position":"LAST_IN_ALBUM"},"newMediaItems":[{"simpleMediaItem":{"fileName":<File-Name>,"uploadToken":<Upload-Token>}}]}' \
"https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate"

  • <Album-ID> 為 相簿ID,若不加入相簿需要將整個 albumId 及 albumPosition 移除
  • <File-Name> 為 上載後的名稱
  • <Upload-Token> 為 上載令牌
請求成功後,會傳回 JSON
{
	"newMediaItemResults": [
		{
			"uploadToken": <Upload-Token>,
			"status": {
				"message": "Success"
			},
			"mediaItem": {
				"id": <Media-ID",
				"productUrl": <Media-URL",
				"mimeType": <MIME-Type-of-Media>,
				"mediaMetadata": {
					"creationTime": <Creation-Time>
					"Width": <Width-of-Media>
					"Height": <Height-of-Media>
				},
				"filename": <Name-of-Media>
			}
		}
	]
}

傳回很多資料,主要是
  • <Media-ID> 為 多媒體ID
  • <Name-of-Media> 為 上載後的名稱

見下文
見下文
經 Photos Library API 上載的 PNG圖片 使用原圖尺寸時,不再自動轉換成 JPG圖片

總結

多年前在下都曾經編寫透過 Google API 上載多媒體到 Picasa Web Album
但現在 Google 將 Picasa Web Album 撤消,需要使用 Google Photos
然而取而代之的 Photos Library API 的功能卻非常少
過往 Picasa Web API 功能非常全面,上載、下載、更新、刪除都能夠執行
但現在的 Photos Library API 卻只有上載及很少更新功能,沒有刪除能力
失去大部分批次操作及自動化處理功能
而且還非常奇怪,在 Google Photos 網頁版建立的相簿是不能夠使用 Photos Library API 將多媒體加入
需要先上載到 Google Photos 的相片主頁,再在網頁版手動加入
要完全只使用 Photos Library API 將多媒體加入至相簿,必須連同相簿都是使用 Photos Library API 才能加入

唯一好處是每個相簿容量比之前多
Picasa Web Album 只可以存放 1000個多媒體資料
Google Photo 可以存放 20000個多媒體資料,對不斷拍攝的使用者的確是好消息
但如果沒有將資料整理妥當,20000個多媒體資料只是一堆混亂資料
不過 1000個多媒體資料都已經很多
在下編寫第一篇文章至今大約拍攝及擷取 50000個多媒體資料,700個相簿,平均每個相簿有 70個多媒體資料
一日有 86400秒,即是平均 每86秒 拍攝一個多媒體,才會用盡 Picasa Web Album 一個相簿

參考資料

沒有留言 :

張貼留言