from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * from PIL import Image, ExifTags class ImageTexture: def __init__(self, image_source, exif=None): self.id = None img = Image.open(image_source) self.exif = exif or self.get_exif(img) img = self.handle_orientation(img, self.exif) img = img.convert("RGBA") # Ensure the image is in RGBA mode self.width = img.width self.height = img.height self._img_data = img.tobytes("raw", "RGBA", 0, -1) # Convert image data to bytes self.initialized = True def gl_init(self): if self.id: return #glPixelStorei(GL_UNPACK_ALIGNMENT, 1) self.id = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, self.id) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, self._img_data) #glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width, img.height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) del self._img_data # No longer needed, clear mem #print(f"Loaded texture {self.id}") def free(self): if self.id is None: del self._img_data else: glBindTexture(GL_TEXTURE_2D, 0) # Unbind glDeleteTextures([self.id]) @staticmethod def get_exif(img): return { ExifTags.TAGS[k]: v for k, v in img.getexif().items() if k in ExifTags.TAGS } @staticmethod def handle_orientation(img, exif): orientation = exif.get("Orientation", 1) if exif is not None else 1 if orientation == 3: return img.rotate(180, expand=True) if orientation == 6: return img.rotate(270, expand=True) if orientation == 8: return img.rotate( 90, expand=True) return img class ImageTextureImmichAsset(ImageTexture): def __init__(self, asset, asset_index): self.initialized = False self.asset_index = asset_index self.asset_key = asset["id"] self.exif = asset.get("exif", None) # So that free can work self.id = None self._img_data = None def initialize(self, image_source): super().__init__(image_source, self.exif)