Introduction
Apple’s HEIC image format, known for its efficiency, isn’t always compatible with all platforms or devices. This guide walks you through a Python script that automatically converts HEIC images to PNG, uploads them back to Google Drive, and cleans up the original files. We’ll cover everything from setting up Google credentials to running the script.
Setting Up Your Environment
1. Install Python Libraries You’ll need Python installed on your machine along with a few libraries. Open your terminal or command prompt and run:
pip install pillow pyheif google-api-python-client google-auth-httplib2 google-auth-oauthlib
Pillow
for image processing.pyheif
for handling HEIC files.- Google Client libraries to interact with the Drive API.
2. Google Drive API and Credentials To interact with Google Drive:
To enable our Python script to interact with Google Drive for converting and managing images, we first need to set up access to the Google Drive API. This involves a few steps within the Google Cloud Platform and handling credentials correctly.
Create a Project in Google Cloud Platform (GCP)
Go to the Google Cloud Console. Sign in with your Google account. Click on the “Select a project” dropdown near the top of the page, then click “NEW PROJECT” to create a new project. Enter a project name and select a billing account as required. Click “CREATE”.
Enable the Google Drive API
With your new project selected, navigate to the “Dashboard” pane on the GCP console. Click on “Go to APIs overview” → “+ ENABLE APIS AND SERVICES”. In the API Library, search for “Google Drive API” and select it. Click the “ENABLE” button to enable the Google Drive API for your project.
Configure Consent Screen
In the sidebar under “APIs & Services”, select “OAuth consent screen”. Choose the User Type (usually “External”) and click “CREATE”. Fill in the required fields under the “App registration” section. This information will be shown to users when they first authenticate with your script.
Create Credentials
In the sidebar under “APIs & Services”, select “Credentials”. Click “+ CREATE CREDENTIALS” at the top and choose “OAuth client ID”. If prompted to set up the OAuth consent screen, fill in the required details and save. For “Application type”, select “Desktop app”, give it a name, and click “Create”. Your credentials (client ID and client secret) will now be displayed. Click “OK” to dismiss the dialog.
Download Credentials
Under “OAuth 2.0 Client IDs”, find your newly created credentials and click on the download button on the right side to download the credentials.json
file. Save this file to your project directory where your Python script resides.
Initialize in Your Script Now that you have downloaded credentials.json
, the script will use this file to authenticate users. Ensure the file is in the same directory as your Python script or provide the correct path in your script to locate this file.
The Script Explained
Below is the Python script broken down into sections:
Import Libraries
We start by importing necessary libraries for handling files, images, and Google Drive API interactions.
import io
import os
import pyheif
from PIL import Image
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload, MediaFileUpload
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
Google Authentication Flow
The SCOPES
variable defines the permissions for accessing Google Drive. The get_credentials()
function manages the authentication flow. This function checks for existing credentials or initiates an authorization flow if none are found.
SCOPES = ['https://www.googleapis.com/auth/drive']
def get_credentials():
creds = None
# The file token.json stores the user's access and refresh tokens.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES, redirect_uri='https://localhost')
auth_url, _ = flow.authorization_url(
prompt='consent',
access_type='offline',
include_granted_scopes='true'
)
print("Please go to this URL and authorize access:")
print(auth_url)
code = input("Enter the authorization code: ")
flow.fetch_token(code=code)
# Save the credentials for the next run
with open('token.json', 'w') as token_file:
token_file.write(flow.credentials.to_json())
creds = flow.credentials
return creds
creds = get_credentials()
service = build('drive', 'v3', credentials=creds)
Downloading and Converting Images
Each HEIC file from Drive is downloaded, converted to PNG using pyheif
and Pillow
, then saved locally. The new PNG files are uploaded back to Google Drive, and the original HEIC files are deleted.
# Replace FOLDER_ID with your Google Drive folder ID
FOLDER_ID = 'FOLDER_ID'
# Folder to save images
image_folder = 'images'
if not os.path.exists(image_folder):
os.makedirs(image_folder)
# Query to get all HEIC files from the folder
query = f"parents = '{FOLDER_ID}' and mimeType = 'image/heif'"
results = service.files().list(q=query, pageSize=1000, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
print(f'{len(items)} images found.')
if not items:
print("No HEIC files found.")
else:
for item in items:
request = service.files().get_media(fileId=item['id'])
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print(f"Download {item['name']} {int(status.progress() * 100)}%.")
fh.seek(0)
heif_file = pyheif.read(fh)
image = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
heif_file.mode,
heif_file.stride,
)
# Convert to PNG and save in the 'images' folder
png_filename = item['name'].rsplit('.', 1)[0] + '.png'
png_filepath = os.path.join(image_folder, png_filename)
image.save(png_filepath, format="PNG")
# Upload PNG back to Google Drive
file_metadata = {'name': png_filename, 'parents': [FOLDER_ID]}
media = MediaFileUpload(png_filepath, mimetype='image/png')
file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
print(f"Uploaded {png_filename} with file ID {file.get('id')}")
# Delete the original HEIC file from Google Drive
try:
service.files().delete(fileId=item['id']).execute()
print(f"Deleted original file: {item['name']}")
except Exception as error:
print(f"An error occurred: {error}")
Running the Script
- Place the
credentials.json
file in your project directory. - Adjust
FOLDER_ID
in the script to point to your specific Google Drive folder. - Run the script. You’ll be prompted to authorize access on the first run. Copy the token in the redirected URL into your console to generate the token file.
Conclusion
This script simplifies image format management and can be modified to suit various needs. Understanding and customizing the script can provide a deeper insight into Python scripting and API interactions.