def test_read_file_bytearrays(): for fn in glob.glob('tests/images/*.heic'): with open(fn, 'rb') as f: d = f.read() d = bytearray(d) heif_file = pyheif.read_heif(d) assert (heif_file is not None) assert (heif_file.mode in ['RGB', 'RGBA']) width, height = heif_file.size assert (width > 0) assert (height > 0) assert (len(heif_file.data) > 0)
def read_heic(path: str): with open(path, 'rb') as file: image = pyheif.read_heif(file) for metadata in image.metadata or []: if metadata['type'] == 'Exif': fstream = io.BytesIO(metadata['data'][6:]) # now just convert to jpeg pi = PIL.Image.open(fstream) pi.save("file.jpg", "JPEG") # or do EXIF processing with exifread tags = exifread.process_file(fstream)
def decodeImage(bytesIo, save_path): try: fmt = whatimage.identify_image(bytesIo) # print('fmt = ', fmt) if fmt in ['heic']: i = pyheif.read_heif(bytesIo) # print('i = ', i) # print('i.metadata = ', i.metadata) pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) # print('pi = ', pi) pi.save(save_path, format="jpeg") except: traceback.print_exc()
def load_heif(full_file_name: str, catch_pyheif_exceptions: bool=True, process_name: str=''): """ Load HEIF file and convert it to a QImage using Pillow :param full_file_name: image to load :return: ImageQt (subclass of QImage). Must keep this in memory for duration of operations on it """ global _error_logged try: image = pyheif.read_heif(full_file_name) except pyheif.error.HeifError: if not _error_logged: if process_name: process_id = "the %s" % process_name else: process_id = 'this' logging.error( "Error using pyheif to load HEIF file %s. " "If encountered on another file, this error message will only be repeated once " "for %s process.", full_file_name, process_id ) _error_logged = True if not catch_pyheif_exceptions: raise return None except FileNotFoundError: if not _error_logged: if process_name: process_id = "the %s" % process_name else: process_id = 'this' logging.error( "FileNotFoundError using pyheif to load HEIF file %s ." "If encountered on another file, this error message will only be repeated once " "for %s process.", full_file_name, process_id ) _error_logged = True if not catch_pyheif_exceptions: raise return None pillow_image = Image.frombytes(mode=image.mode, size=image.size, data=image.data) if pillow_image.mode not in ('RGB', 'RGBA', '1', 'L', 'P'): pillow_image = pillow_image.convert('RGBA') imageqt = ImageQt.ImageQt(pillow_image) if imageqt is not None and not imageqt.isNull(): return imageqt return None
async def homepage(request): url = request.query_params.get("url") if not url: return JSONResponse({"error": "?url= is required"}) async with httpx.AsyncClient(verify=False) as client: image_response = await client.get(url) if image_response.status_code != 200: return JSONResponse( { "error": "Status code not 200", "status_code": image_response.status_code, "body": repr(image_response.content), } ) heic = pyheif.read_heif(image_response.content) image = Image.frombytes(mode=heic.mode, size=heic.size, data=heic.data) # Resize based on ?w= and ?h=, if set width, height = image.size w = request.query_params.get("w") h = request.query_params.get("h") if w is not None or h is not None: if h is None: # Set h based on w w = int(w) h = int((float(height) / width) * w) elif w is None: h = int(h) # Set w based on h w = int((float(width) / height) * h) w = int(w) h = int(h) image.thumbnail((w, h)) # ?bw= converts to black and white if request.query_params.get("bw"): image = image.convert("L") # ?q= sets the quality - defaults to 75 quality = 75 q = request.query_params.get("q") if q and q.isdigit() and 1 <= int(q) <= 100: quality = int(q) jpeg = io.BytesIO() image.save(jpeg, "JPEG", quality=quality) return Response( jpeg.getvalue(), media_type="image/jpeg", headers={"cache-control": "s-maxage={}, public".format(365 * 24 * 60 * 60)}, )
def decodeImage(bytesIo): i = pyheif.read_heif(bytesIo) # Extract metadata etc for metadata in i.metadata or []: if metadata['type']=='Exif': # do whatever # Convert to other file format like jpeg s = io.BytesIO() pi = Image.frombytes( mode=i.mode, size=i.size, data=i.data) pi.save(s, format="jpeg")
def decode_image(input_path, output_path): bytesIo = open(input_path, 'rb').read() try: fmt = whatimage.identify_image(bytesIo) # print('fmt = ', fmt) if fmt in ['heic', 'avif']: i = pyheif.read_heif(bytesIo) # print('i = ', i) # print('i.metadata = ', i.metadata) pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) # print('pi = ', pi) pi.save(output_path, format="jpeg") except: traceback.print_exc()
def convert_heic_to_png(filename: str, new_path: str): if os.path.splitext(filename)[1].lower() == ".heic": with open(filename, 'rb') as file: i = pyheif.read_heif(file) # Convert to other file format. pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) _, name = os.path.split(filename) new_filename = os.path.join(new_path, os.path.splitext(name)[0] + ".png") pi.save(new_filename, format="png") print(filename, "converted into", new_filename) else: print(filename, "is not right format, skipped")
def convert_heic_to_jpeg(f): f.seek(0) i = pyheif.read_heif(f) # Extract metadata etc # for metadata in i.metadata or []: # if metadata['type']=='Exif': # do whatever # Convert to other file format like jpeg s = io.BytesIO() pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) pi.save(s, format="jpeg")
def decodeHEICImage(bytesIo): fmt = whatimage.identify_image(bytesIo.read()) if fmt in ['heic', 'avif']: i = pyheif.read_heif(bytesIo.read()) # Extract metadata etc #for metadata in i.metadata or []: # if metadata['type']=='Exif': # # do whatever # Convert to other file format like jpeg s = BytesIO() pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) pi.save(s, format="jpeg") return s
def convert_heif_to_pil(heif_file_path): """ Converts a .heif/.heic image file into a PIL object :param heif_file_path: A string which leads to a valid .heif/.heic file. :return: A PIL object read in from the given image path. """ # process .heif file if it exists try: heif_file = pyheif.read_heif(heif_file_path) pil_img = Image.frombytes(mode=heif_file.mode, size=heif_file.size, data=heif_file.data) return pil_img except IOError as err: print(err)
def heic_to_jpg(file_path): # read_image_file_rb with open(file_path, 'rb') as f: bytesIo = f.read() try: fmt = whatimage.identify_image(bytesIo) print('fmt = ', fmt) if fmt in ['heic']: i = pyheif.read_heif(bytesIo) # print('i = ', i) # print('i.metadata = ', i.metadata) pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) # print('pi = ', pi) pi.save('heeh.jpg', format="jpeg") except: traceback.print_exc()
def run_ocr(image_path: str, resize_threshold=1000): if image_path.endswith('.heic'): heif_file = pyheif.read_heif(image_path) image = Image.frombytes(mode=heif_file.mode, size=heif_file.size, data=heif_file.data) image = resize(image, threshold=resize_threshold) else: image = Image.open(image_path) image = resize(image, threshold=resize_threshold) image.save("../resources/temp.jpg", "JPEG") image_path = "../resources/temp.jpg" encoded_image = open(image_path, 'rb').read() encoded_image = base64.b64encode(encoded_image) return requests.post('http://188.246.224.225:8420/ocr', json={ 'image': encoded_image }).json()['answer']
def get_exif_data(ifile): if re.search(r'jpeg$|bmp$|png$|jpg$', str(ifile), re.IGNORECASE): image = Image.open(ifile) exifdata = image.getexif() geotags = get_geotagging(exifdata) if "{1:" in str(exifdata[34853]): lat_long = get_coordinates(geotags) geo_loc = get_location(str(lat_long)[1:-1]) else: geo_loc = "No location Data" return exifdata.get(271), exifdata.get(272), exifdata.get(36867), geo_loc, os.path.basename(ifile) elif re.search(r'heic$', str(ifile), re.IGNORECASE): # this part of the decision tree processes HEIC files heif_file = pyheif.read_heif(str(ifile)) for metadata in heif_file.metadata: if metadata['type'] == 'Exif': fstream = io.BytesIO(metadata['data'][6:]) tags = exifread.process_file(fstream, details=False) return str(tags.get("Image Make")), str(tags.get("Image Model")), str( tags.get('EXIF DateTimeOriginal')), "N/A", os.path.basename(ifile) # strips path from file elif re.search(r'CR2$|NEF$', str(ifile), re.IGNORECASE): # this part of the decision tree processes raw files (Cannon and Nikon) f = open(ifile, 'rb') # Return Exif tags tags = exifread.process_file(f, details=False) make = tags['Image Make'] model = tags['Image Model'] orig_date = tags['EXIF DateTimeOriginal'] return make, str(model).partition(' ')[2], str(orig_date)[:10], "N/A", os.path.basename(ifile) else: logfile.write(str(path) + " doesn't seem to be an image file \n")
def hash_file(file): try: mime = magic.from_file(file, mime=True) if mime.rsplit('/', 1)[1] == 'heic': heif = pyheif.read_heif(open(file, 'rb')) img = Image.frombytes( mode=heif.mode, size=heif.size, data=heif.data) else: img = Image.open(file) file_size = get_file_size(file) hashes, image_size, capture_time = hash_image(img) cprint("\tHashed {}".format(file), "blue") return file, hashes, file_size, image_size, capture_time except OSError: cprint("\tUnable to open {}".format(file), "red") return None
def heic2jpg(): path = "/Users/kun/Desktop/岐下村" total_dir = [os.path.join(path, i) for i in os.listdir(path)] # print(total_dir) for img_dir in total_dir: if "DS_S" in img_dir: pass else: img_list = [os.path.join(img_dir, i)for i in os.listdir(img_dir)] for img in img_list: if "heic" in img: print(2) img_name = img.split("/")[-1] hi_img = pyheif.read_heif(img) jpg_img = Image.frombytes(data=hi_img.data, size=hi_img.size, mode=hi_img.mode) jpg_img.save(img_dir+"/%s.jpg"%img_name) os.remove(img)
def post_image(): if request.method == 'POST': if 'file' in request.files: file = request.files['file'] if file: if file.filename != '': filename = file.filename ext = filename.split(".")[-1].lower() if ext in ALLOWED_IMAGES: UPLOAD_FOLDER = join(HOME, 'images') file.save(join(UPLOAD_FOLDER, filename)) elif ext in ['heic', 'avif']: CONV_FOLDER = join(HOME, 'conversion') UPLOAD_FOLDER = join(HOME, 'images') file.save(join(CONV_FOLDER, filename)) with open(join(CONV_FOLDER, filename), 'rb') as file: i = read_heif(file) pi = Image.frombytes( mode=i.mode, size=i.size, data=i.data ) pi.save(join(UPLOAD_FOLDER,filename.split(".")[0] + '.jpeg'), format="jpeg") return get_breed_info(filename) else: return jsonify({"result": "No image recieved"}) elif 'file' in request.form: file = request.form['file'] if file: if file.filename != '': filename = file.filename UPLOAD_FOLDER = join(HOME, 'images') file.save(join(UPLOAD_FOLDER, filename)) return get_breed_info(filename) else: return jsonify({"result": "No image recieved"}) else: return jsonify({'result':'Nothing recieved'}) if request.method == 'GET': return render_template('upload.html')
def get_exif_data(ifile): # if the file is a standard image file if re.search(r'jpeg$|bmp$|png$|jpg$', str(ifile), re.IGNORECASE): image = Image.open(ifile) exifdata = image.getexif() return exifdata.get(271), exifdata.get(272), exifdata.get(36867), ifile elif re.search(r'heic$', str(ifile), re.IGNORECASE): # if an Apple Heic file heif_file = pyheif.read_heif(str(ifile)) for metadata in heif_file.metadata: if metadata['type'] == 'Exif': fstream = io.BytesIO(metadata['data'][6:]) tags = exifread.process_file(fstream, details=False) return str(tags.get("Image Make")), str(tags.get("Image Model")), str( tags.get('EXIF DateTimeOriginal')), ifile elif re.search( r'CR2$|NEF$', str(ifile), re.IGNORECASE): # for raw files. Canon and NIkon is this case. f = open(ifile, 'rb') # open the file in bytes / ro mode # Return Exif tags tags = exifread.process_file( f, details=False ) # the "False" statement filters out a lot of comment data from # device maker make = tags['Image Make'] model = tags['Image Model'] orig_date = tags['EXIF DateTimeOriginal'] return make, str(model).partition(' ')[2], str( orig_date)[:10], ifile # some hoops to get the correct format else: logfile.write(ifile + " this file is corrupt")
def convert(student_name): image_directory = join(r"PATH TO INPUT IMAGES", student_name) image_files = [ f for f in listdir(image_directory) if isfile(join(image_directory, f)) ] # print(image_files) for file_name in image_files: if "heic" in file_name.lower(): save_dir = join( image_directory, join( file_name.replace(".HEIC", ".JPG").replace(".heic", ".jpg"))) if isfile(save_dir): print("Skipping : " + file_name + ", jpg version already exists") continue print(file_name) file_bytes = open(join(image_directory, file_name), "rb") i = pyheif.read_heif(file_bytes) image = Image.frombytes(mode=i.mode, size=i.size, data=i.data) image.save(save_dir, format="JPEG")
def load_image(path): """ Safe method for loading PIL.Image instances with additional support for HEIF files. """ # Check to see if we need to do special-case HEIF handling. # If we do, then we convert the file to an in-memory JPEG, that can then be opened using PIL. with open(path, 'rb') as fh: image_data = fh.read() format = whatimage.identify_image(image_data) if format in ['heic', 'avif']: heif_image = pyheif.read_heif(image_data) pi = Image.frombytes(mode=heif_image.mode, size=heif_image.size, data=heif_image.data) exif = None for metadata in heif_image.metadata or []: if metadata['type'] == 'Exif': exif = metadata['data'] stream = io.BytesIO() pi.save(stream, format="jpeg", exif=exif) return Image.open(stream) return Image.open(path)
def heic_to_jpg(f, hashed_file_name): image_heic = read_heif(f) image_jpg = ImagePIL.frombytes(mode=image_heic.mode, size=image_heic.size, data=image_heic.data) image_jpg.save(os.path.join(os.getcwd(), 'app/static/images', hashed_file_name), format="jpeg")
import pyheif import io from PIL import Image import numpy as np file_name = "20200205_151125.heic" i = pyheif.read_heif(file_name) # Convert to other file format like jpeg # https://stackoverflow.com/questions/54395735/how-to-work-with-heic-image-file-types-in-python s = io.BytesIO() pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) # https://stackoverflow.com/questions/384759/how-to-convert-a-pil-image-into-a-numpy-array img = np.asarray(pi) print("Hello")
def run(self): while True: self.imagePath = self.queueIMG.get() self.imageDir, self.imageName = os.path.split(self.imagePath) self.thumbDir = os.path.join(self.imageDir, "@eaDir", self.imageName) status = "Skipping" if not os.path.isfile(os.path.join( self.thumbDir, xlName)) and not os.path.isfile( os.path.join(self.thumbDir, oldxlName)): status = "Working on" if os.path.isdir(self.thumbDir) != 1: try: os.makedirs(self.thumbDir) except: continue # Following if statements converts raw images using dcraw first ext = os.path.splitext(self.imagePath)[1].lower() need_rotatation = True if ext == ".cr2": self.dcrawcmd = "dcraw -c -b 8 -q 0 -w -H 5 '%s'" % self.imagePath self.dcraw_proc = subprocess.Popen(shlex.split( self.dcrawcmd), stdout=subprocess.PIPE) self.raw = StringIO(self.dcraw_proc.communicate()[0]) self.image = Image.open(self.raw) elif ext == '.heic' or ext == '.avif': heic = pyheif.read_heif(self.imagePath) self.image = Image.frombytes(heic.mode, heic.size, heic.data, "raw", heic.mode, heic.stride) need_rotatation = False else: self.image = Image.open(self.imagePath) if need_rotatation: self._read_img_and_correct_exif_orientation() # end of orientation part try: self.image = self.image.convert('RGB') self.image.thumbnail(xlSize, Image.ANTIALIAS) self.image.save(os.path.join(self.thumbDir, xlName), quality=90) self.image.thumbnail(lSize, Image.ANTIALIAS) self.image.save(os.path.join(self.thumbDir, lName), quality=90) self.image.thumbnail(bSize, Image.ANTIALIAS) self.image.save(os.path.join(self.thumbDir, bName), quality=90) self.image.thumbnail(mSize, Image.ANTIALIAS) self.image.save(os.path.join(self.thumbDir, mName), quality=90) self.image.thumbnail(sSize, Image.ANTIALIAS) self.image.save(os.path.join(self.thumbDir, sName), quality=90) self.image.thumbnail(pSize, Image.ANTIALIAS) # pad out image self.image_size = self.image.size self.preview_img = self.image.crop( (0, 0, pSize[0], pSize[1])) self.offset_x = max((pSize[0] - self.image_size[0]) / 2, 0) self.offset_y = max((pSize[1] - self.image_size[1]) / 2, 0) self.preview_img = ImageChops.offset( self.preview_img, int(self.offset_x), int(self.offset_y )) # offset has to be integer, not float self.preview_img.save(os.path.join(self.thumbDir, pName), quality=90) except IOError as e: # image file is corrupt / can't be read / or we can't write to the mounted share with open(self.badImageFileList, "a") as badFileList: badFileList.write("%s: '%s' \n" % (self.imagePath, e)) print(" [- | %s] %s %s" % (time.strftime('%X'), status, self.imagePath)) self.queueIMG.task_done()
def heic2jpg(src_file, result_file): heif_file = pyheif.read_heif(src_file) pi = Image.frombytes(mode=heif_file.mode, size=heif_file.size, data=heif_file.data) pi.save(result_file, format='jpeg')
def merge_media(src, des, prefix, start_num, sort_media, show_same, show_unsupport): try: sort_media = eval(sort_media) show_same = eval(show_same) show_unsupport = eval(show_unsupport) except: print('Error: invalid show_same or show_unsupport') sys.exit(1) src_path, des_path = get_real_path(src, des) src_backup_path = src_path + '_backup' shutil.copytree(src_path, src_backup_path) all_media_extensions = set() all_media_files = list( filter(lambda x: not x.startswith('.'), os.listdir(src_path))) num_of_media_files = 0 num_of_move_media_files = 0 image_extensions = ['JPG', 'JPEG', 'PNG'] video_extensions = ['MOV', 'MP4'] live_extensions = ['HEIC'] support_extensions = image_extensions + video_extensions + live_extensions duplicate_indexes = set() if src_path == '': print('Error: source path does not exist') sys.exit(1) print('---------- Get all extensions ----------') for media_filename in tqdm(all_media_files): media_extension = os.path.splitext(media_filename)[1][1:].upper() if len(media_extension) > 0: all_media_extensions.add(media_extension) num_of_media_files += 1 print('All extensions:', all_media_extensions) print('Number of all media files:', num_of_media_files) extension_counter = {ext: 0 for ext in all_media_extensions} print('---------- Move media processing ----------') for i in tqdm(range(num_of_media_files)): if i in duplicate_indexes: continue media_1_path = os.path.join(src_path, all_media_files[i]) media_1_extension = os.path.splitext(media_1_path)[1][1:].upper() for j in range(i + 1, num_of_media_files): if j in duplicate_indexes: continue media_2_path = os.path.join(src_path, all_media_files[j]) media_2_extension = os.path.splitext(media_2_path)[1][1:].upper() if media_1_extension == media_2_extension: # Same extensions if media_1_extension in image_extensions: # Image image_1 = Image.open(media_1_path) image_2 = Image.open(media_2_path) if list(image_1.getdata()) == list(image_2.getdata()): duplicate_indexes.add(j) # Save duplicate image index if show_same: print('SAME IMAGE:', media_1_path, '--', media_2_path) elif media_1_extension in video_extensions: # Video video_1 = cv2.VideoCapture(media_1_path) property_id = int(cv2.CAP_PROP_FRAME_COUNT) length_video_1 = int( cv2.VideoCapture.get(video_1, property_id)) video_2 = cv2.VideoCapture(media_2_path) length_video_2 = int( cv2.VideoCapture.get(video_2, property_id)) if length_video_1 == length_video_2: frame = 0 is_same_video = True while frame < length_video_1: ret_1, frame_1 = video_1.read() ret_2, frame_2 = video_2.read() # Compare video by frame if different, continue if not np.array_equal(frame_1, frame_2): is_same_video = False break frame += (length_video_1 // 5) - 1 if is_same_video: duplicate_indexes.add( j) # Save duplicated video index if show_same: print('SAME VIDEO:', media_1_path, '--', media_2_path) elif media_1_extension in live_extensions: # Live live_1 = pyheif.read_heif(media_1_path) image_from_live_1 = Image.frombytes(mode=live_1.mode, size=live_1.size, data=live_1.data) live_2 = pyheif.read_heif(media_2_path) image_from_live_2 = Image.frombytes(mode=live_2.mode, size=live_2.size, data=live_2.data) if list(image_from_live_1.getdata()) == list( image_from_live_2.getdata()): duplicate_indexes.add(j) # Save duplicated live index if show_same: print('SAME LIVE:', media_1_path, '--', media_2_path) else: if show_unsupport: print('Error: unsupported', media_1_extension, 'media format') break else: continue # Different extensions # Save media at index i if in supported extensions if media_1_extension in support_extensions: extension_counter[media_1_extension] += 1 # Create folder due to extension if not exist if not os.path.exists(des_path): os.makedirs(des_path) media_src = os.path.join(src_path, all_media_files[i]) str_of_move_media_files = str(num_of_move_media_files) full_media_extension = '.' + media_1_extension media_des = os.path.join( des_path, prefix[:-len(str_of_move_media_files)] + str_of_move_media_files + full_media_extension) # Move file with prefix name move_media_des = shutil.move(media_src, media_des) print('Moved media:', move_media_des) num_of_move_media_files += 1 else: if show_unsupport: print('Error: unsupported', media_1_extension, 'media format') src_dup_path = src_path + '_duplicated' if os.path.exists(src_dup_path): shutil.rmtree(src_dup_path) os.rename(src_path, src_dup_path) os.rename(src_backup_path, src_path) print('---------- Moved done ----------') print('Each moved media extensions:', extension_counter) print('Number of moved media files:', num_of_move_media_files) if sort_media: get_sorted_media(des_path, prefix, start_num) sys.exit(0)
pattern = r'.\w+$' lst = os.listdir(path) for i in lst: inp = os.path.join(path, i) file = re.search(pattern, i).group(0).lower() if file in ['.mov', '.mp4']: print(i) outp = os.path.join(video, i) shutil.move(inp, outp) elif file in ['.png', '.jpg', '.jpeg']: print(i) outp = os.path.join(photo, i) shutil.move(inp, outp) elif file in ['.heic', 'heif']: print(i) outp = photo + '/' + i[:-5] + '.jpg' heif_file = pyheif.read_heif(inp) image = Image.frombytes(mode=heif_file.mode, size=heif_file.size, data=heif_file.data) image.save(outp, "JPEG") """Save heic files in new dir""" make_dir('heic') heic = os.path.join(path, 'heic') outp = os.path.join(heic, i) shutil.move(inp, outp) """Or delete heic files""" # os.remove(inp)
directory = '/content/drive/My Drive/New_Colab/Myhal photos' ind = 1 n_classes = 7 for subdir in os.listdir(directory): dirpath = os.path.join(directory,subdir) count = 0 for f in os.listdir(dirpath): count+=1 filename = os.path.join(dirpath,f) if filename.endswith('.HEIC'): bytesIo = filename # fmt = whatimage.identify_image(bytesIo) # if fmt in ['heic', 'avif']: i = pyheif.read_heif(bytesIo) # Extract metadata etc for metadata in i.metadata or []: if metadata['type']=='Exif': pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data) pi = pi.resize([480,640]) if count == ind: plt.figure(num=None, figsize=(4,3), dpi=200, edgecolor='k') plt.imshow(pi) pi = np.array(pi) pi = pi/127.5-1 pii = Image.fromarray(((pi+1)*127.5).astype(np.uint8),'RGB') if count == ind: plt.figure(num=None, figsize=(4,3), dpi=200, edgecolor='k') plt.imshow(pii)
async def image(request): key = request.path_params["key"] sha256, ext = key.split(".") url = url_for_image(sha256, ext) # Fetch original async with httpx.AsyncClient(verify=False) as client: image_response = await client.get(url) if image_response.status_code != 200: return JSONResponse( { "error": "Status code not 200", "status_code": image_response.status_code, "body": repr(image_response.content), } ) # Load it into Pillow if ext == "heic": heic = pyheif.read_heif(image_response.content) image = Image.frombytes(mode=heic.mode, size=heic.size, data=heic.data) else: image = Image.open(io.BytesIO(image_response.content)) # Does EXIF tell us to rotate it? try: exif = dict(image._getexif().items()) if exif[ORIENTATION_TAG] == 3: image = image.rotate(180, expand=True) elif exif[ORIENTATION_TAG] == 6: image = image.rotate(270, expand=True) elif exif[ORIENTATION_TAG] == 8: image = image.rotate(90, expand=True) except (AttributeError, KeyError, IndexError): pass # Resize based on ?w= and ?h=, if set width, height = image.size w = request.query_params.get("w") h = request.query_params.get("h") if w is not None or h is not None: if h is None: # Set h based on w w = int(w) h = int((float(height) / width) * w) elif w is None: h = int(h) # Set w based on h w = int((float(width) / height) * h) w = int(w) h = int(h) image.thumbnail((w, h)) # ?bw= converts to black and white if request.query_params.get("bw"): image = image.convert("L") # ?q= sets the quality - defaults to 75 quality = 75 q = request.query_params.get("q") if q and q.isdigit() and 1 <= int(q) <= 100: quality = int(q) # Output as JPEG or PNG output_image = io.BytesIO() image_type = "JPEG" kwargs = {"quality": quality} if image.format == "PNG": image_type = "PNG" kwargs = {} image.save(output_image, image_type, **kwargs) return Response( output_image.getvalue(), media_type="image/jpeg", headers={"cache-control": "s-maxage={}, public".format(365 * 24 * 60 * 60)}, )