2@brief Utilities to extract materials from the GPUOpen material database. This is not a complete set of calls to extract out all material information but instead enough to find materials
3and extract out specific packages from the list of available materials.
5See: https://api.matlib.gpuopen.com/api/swagger/ for information on available API calls.
8import requests, json, os, io, re, zipfile, logging
9from http
import HTTPStatus
16from PIL
import Image
as PILImage
21 This class is used to load materials from the GPUOpen material database.
22 See: https://api.matlib.gpuopen.com/api/swagger/ for API information.
26 Initialize the GPUOpen material loader.
29 self.
root_url =
'https://api.matlib.gpuopen.com/api'
40 self.
logger = logging.getLogger(
'GPUO')
41 logging.basicConfig(level=logging.INFO)
45 Write a package data to a file.
46 @param data: The data to write.
47 @param outputFolder: The output folder to write the file to.
48 @param title: The title of the file.
49 @param unzipFile: If true, the file is unzipped to a folder with the same name
51 @return: True if the package was written.
56 if not os.path.exists(outputFolder):
57 os.makedirs(outputFolder)
61 unzipFolder = os.path.join(outputFolder, title)
64 with io.BytesIO(data)
as data_io:
65 with zipfile.ZipFile(data_io,
'r')
as zip_ref:
66 zip_ref.extractall(unzipFolder)
68 self.
logger.info(f
'Unzipped to folder: "{unzipFolder}"')
71 outputFile = os.path.join(outputFolder, f
"{title}.zip")
72 with open(outputFile,
"wb")
as f:
73 self.
logger.info(f
'Write package to file: "{outputFile}"')
80 Convert a PIL image to a Base64 string.
81 @param image: An instance of PIL.Image
82 @return: Base64-encoded string of the image
86 self.
logger.debug(
'Pillow (PIL) image module not provided. Image data will not be converted to Base64.')
89 self.
logger.debug(
'No image data. Image data will not be converted to Base64.')
97 image.save(buffer, format=
"PNG")
98 binary_data = buffer.getvalue()
99 base64_encoded_data = base64.b64encode(binary_data).decode(
'utf-8')
102 return base64_encoded_data
106 Extract the package data from a zip file.
107 @param data: The data to extract.
108 @param pilImage: The PIL image module.
109 @return: A list of extracted data of the form:
110 [ { 'file_name': file_name, 'data': data, 'type': type } ]
115 self.
logger.debug(
'Pillow (PIL) image module provided. Image data will not be extracted.')
117 zip_object = io.BytesIO(data)
119 extracted_data_list = []
120 with zipfile.ZipFile(zip_object,
'r')
as zip_file:
122 for file_name
in zip_file.namelist():
124 extracted_data = zip_file.read(file_name)
125 if file_name.endswith(
'.mtlx'):
126 mtlx_string = extracted_data.decode(
'utf-8')
127 extracted_data_list.append( {
'file_name': file_name,
'data': mtlx_string,
'type':
'mtlx'} )
130 elif file_name.endswith(
'.png'):
132 image = pilImage.open(io.BytesIO(extracted_data))
135 extracted_data_list.append( {
'file_name': file_name,
'data': image,
'type':
'image'} )
137 return extracted_data_list
141 Download a package for a given material from the GPUOpen material database.
142 @param listNumber: The list number of the material to download.
143 @param materialNumber: The material number to download.
144 @param packageId: The package ID to download.
145 Packages are numbered starting at 0. Default is 0.
146 with index 0 containing the smallest package (smallest resolution referenced textures).
157 if "results" in json_data:
158 jsonResults = json_data[
"results"]
159 if len(jsonResults) <= materialNumber:
162 jsonResult = jsonResults[materialNumber]
169 if "packages" in jsonResult:
170 jsonPackages = jsonResult[
"packages"]
174 if len(jsonPackages) <= packageId:
176 package_id = jsonPackages[packageId]
181 url = f
"{self.package_url}/{package_id}/download"
182 data = requests.get(url).content
184 title = jsonResult[
"title"]
189 Download a package for a given material from the GPUOpen material database.
190 @param searchExpr: The regular expression to match the material name.
191 @param packageId: The package ID to download.
192 @return: A list of downloaded packages of the form:
197 if len(foundList) > 0:
198 for found
in foundList:
199 listNumber = found[
'listNumber']
200 materialNumber = found[
'materialNumber']
201 matName = found[
'title']
202 self.
logger.info(f
'> Download material: {matName} List: {listNumber}. Index: {materialNumber}')
203 result = [data, title] = self.
downloadPackage(listNumber, materialNumber, packageId)
204 downloadList.append(result)
209 Find materials by name.
210 @param materialName: Regular expression to match the material name.
211 @return: A list of materials that match the regular expression of the form:
212 [ { 'listNumber': listNumber, 'materialNumber': materialNumber, 'title': title } ]
221 for material
in materialList[
'results']:
222 if re.match(materialName, material[
'title'], re.IGNORECASE):
223 materialsList.append({
'listNumber': listNumber,
'materialNumber': materialNumber,
'title': material[
'title'] })
231 Update the material names from the material lists.
232 @return: List of material names. If no materials are loaded, then an empty list is returned.
239 for material
in materialList[
'results']:
246 Get the materials returned from the GPUOpen material database.
247 Will loop based on the linked-list of materials stored in the database.
248 Currently the batch size requested is 100 materials per batch.
249 @return: List of material lists
257 'accept':
'application/json'
267 haveMoreMaterials =
True
268 while (haveMoreMaterials):
270 response = requests.get(url, headers=headers, params=params)
272 if response.status_code == HTTPStatus.OK:
274 raw_response = response.text
277 json_strings = raw_response.split(
'}{')
279 json_result_string = json_strings[0]
280 jsonObject = json.loads(json_result_string)
284 nextQuery = jsonObject[
'next']
288 queryParts = nextQuery.split(
'?')
290 queryParts = queryParts[1].split(
'&')
292 limitParts = queryParts[0].split(
'=')
293 offsetParts = queryParts[1].split(
'=')
294 params[
'limit'] = int(limitParts[1])
295 params[
'offset'] = int(offsetParts[1])
296 self.
logger.info(f
'Fetch set of materials: limit: {params["limit"]} offset: {params["offset"]}')
298 haveMoreMaterials =
False
302 self.
logger.info(f
'Error: {response.status_code}, {response.text}')
308 Get the JSON strings for the materials
309 @return: List of JSON strings for the materials. One string per material batch.
316 results.append(json.dumps(material, indent=4, sort_keys=
True))
321 Load the materials from a set of JSON files downloaded from
322 the GPUOpen material database.
325 for fileName
in fileNames:
326 with open(fileName)
as f:
333 Write the materials to a set of MaterialX files.
334 @param folder: The folder to write the files to.
335 @param rootFileName: The root file name to use for the files.
336 @return: The number of files written.
343 os.makedirs(folder, exist_ok=
True)
346 fileName = rootFileName +
'_' + str(i) +
'.json'
347 materialFileName = os.path.join(folder, fileName)
348 self.
logger.info(f
'> Write material to file: "{materialFileName}"')
349 with open(materialFileName,
'w')
as f:
350 json.dump(material, f, indent=4, sort_keys=
True)
357 Write sorted list of the material names to a file in JSON format
358 @param fileName: The file name to write the material names to.
359 @param sort: If true, sort the material names.
364 with open(fileName,
'w')
as f:
This class is used to load materials from the GPUOpen material database.
writeMaterialNamesToFile(self, fileName, sort=True)
Write sorted list of the material names to a file in JSON format.
list getMaterials(self)
Get the materials returned from the GPUOpen material database.
int writeMaterialFiles(self, folder, rootFileName)
Write the materials to a set of MaterialX files.
list materialNames
List of material names.
str package_url
URL for the packages.
convertPilImageToBase64(self, image)
Convert a PIL image to a Base64 string.
bool writePackageDataToFile(self, data, outputFolder, title, unzipFile=True)
Write a package data to a file.
downloadPackageByExpression(self, searchExpr, packageId=0)
Download a package for a given material from the GPUOpen material database.
str root_url
Root URL for the GPUOpen material database.
list findMaterialsByName(self, materialName)
Find materials by name.
downloadPackage(self, listNumber, materialNumber, packageId=0)
Download a package for a given material from the GPUOpen material database.
str url
URL for the materials.
extractPackageData(self, data, pilImage)
Extract the package data from a zip file.
list getMaterialsAsJsonString(self)
Get the JSON strings for the materials.
list getMaterialNames(self)
Update the material names from the material lists.
int materials
List of materials.
list readMaterialFiles(self, fileNames)
Load the materials from a set of JSON files downloaded from the GPUOpen material database.
__init__(self)
Initialize the GPUOpen material loader.