summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Keller <tjkeller.xyz>2025-05-06 21:17:38 -0500
committerTim Keller <tjkeller.xyz>2025-05-06 21:17:38 -0500
commitb487f62ba7cd7dbbcadb2b5704ec1c99f6578390 (patch)
treed4b9152f942dfca9a4cbc3e4b1b618e199c7cd4a
downloadimmich-frame-b487f62ba7cd7dbbcadb2b5704ec1c99f6578390.tar.xz
immich-frame-b487f62ba7cd7dbbcadb2b5704ec1c99f6578390.zip
initial commit
-rw-r--r--.gitignore2
-rw-r--r--pix.py89
-rw-r--r--transition.py67
3 files changed, 158 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cf1238c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+__pycache__
+*.jpg
diff --git a/pix.py b/pix.py
new file mode 100644
index 0000000..988f83d
--- /dev/null
+++ b/pix.py
@@ -0,0 +1,89 @@
+import sys
+from OpenGL.GL import *
+from OpenGL.GLUT import *
+from OpenGL.GLU import *
+from PIL import Image
+from time import time
+
+from transition import Transition
+
+display_time = 2.0
+transition_duration = 0.5
+
+# Load image as a texture using PIL
+def load_texture(image_path):
+ img = Image.open(image_path)
+ img = img.convert("RGBA") # Ensure the image is in RGBA mode (4 channels: R, G, B, A)
+ img_data = img.tobytes("raw", "RGBA", 0, -1) # Convert image data to bytes
+
+ texture_id = glGenTextures(1)
+ glBindTexture(GL_TEXTURE_2D, texture_id)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0, GL_RGBA, 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)
+ return texture_id
+
+# Main display function
+transition = Transition()
+def display():
+ global start_time, image_time, last_time, alpha, texture_id1, texture_id2
+
+ current_time = time()
+ alive_time = current_time - start_time
+ delta_time = current_time - last_time
+ last_time = current_time
+ image_time += delta_time
+
+ if (image_time < display_time):
+ return
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+ glLoadIdentity()
+
+ # Get window size
+ window_width, window_height = glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)
+
+ # DRAW
+ transition_time = image_time - display_time
+ complete = transition.draw(texture_id1, texture_id2, window_width, window_height, delta_time, transition_time, transition_duration)
+
+ glClearColor(0.0, 0.0, 0.0, 1.0) # Set the background color to black
+
+ glutSwapBuffers()
+
+ if (complete):
+ image_time = 0
+ texture_id1, texture_id2 = texture_id2, texture_id1
+
+# Initialization and main loop
+def main():
+ global texture_id1, texture_id2, alpha, last_time, start_time, image_time
+
+ # Initialize the window
+ glutInit(sys.argv)
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
+ glutCreateWindow("Image Viewer with Fade Transition")
+ glEnable(GL_TEXTURE_2D)
+
+ # Load two images for transition
+ texture_id1 = load_texture("image1.jpg")
+ texture_id2 = load_texture("image2.jpg")
+
+ alpha = 0.0 # Start with fully transparent
+ image_time = 0
+ start_time = time()
+ last_time = time()
+
+ # Set up the OpenGL viewport and projection
+ glMatrixMode(GL_PROJECTION)
+ glLoadIdentity()
+ glOrtho(-1, 1, -1, 1, -1, 1)
+ glMatrixMode(GL_MODELVIEW)
+
+ glutDisplayFunc(display)
+ glutIdleFunc(display)
+ glutMainLoop()
+
+if __name__ == "__main__":
+ main()
+
diff --git a/transition.py b/transition.py
new file mode 100644
index 0000000..cf2acb4
--- /dev/null
+++ b/transition.py
@@ -0,0 +1,67 @@
+from OpenGL.GL import *
+from OpenGL.GLUT import *
+from OpenGL.GLU import *
+
+class Transition:
+ def draw(self, texture_prev, texture_next, window_width, window_height, delta_time, transition_time, transition_duration):
+ # Update alpha value for fade effect
+ alpha = transition_time / transition_duration
+ if alpha > 1.0:
+ alpha = 1.0
+
+ # Draw the first image
+ self._draw_image(texture_prev, 3840, 2160, window_width, window_height, 1 - alpha) # TODO instead of decreasing alpha, draw transparent letterboxes
+ # Draw the second image (with transparency)
+ self._draw_image(texture_next, 3840, 2160, window_width, window_height, alpha)
+
+ return alpha >= 1.0 # Complete
+
+
+
+ # Draw the image with blending enabled (to allow fade effect)
+ def _draw_image(self, texture_id, img_width, img_height, window_width, window_height, alpha):
+ if (not alpha): return
+
+ glEnable(GL_BLEND)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+ glBindTexture(GL_TEXTURE_2D, texture_id)
+ glColor4f(1.0, 1.0, 1.0, alpha) # Set alpha to control transparency
+
+ # Calculate aspect ratio
+ img_aspect = img_width / float(img_height)
+ win_aspect = window_width / float(window_height)
+
+ scaled_width = window_width
+ scaled_height = window_height
+
+ # Scale the image to fit inside the window while maintaining aspect ratio
+ if img_aspect > win_aspect:
+ # Image is wider than window, letterbox vertically
+ scaled_height = window_width / img_aspect
+ else:
+ # Image is taller than window, letterbox horizontally
+ scaled_width = window_height * img_aspect
+
+ # Position the image so it is centered
+ offset_x = (window_width - scaled_width) / 2
+ offset_y = (window_height - scaled_height) / 2
+
+ # Normalize coordinates to range from -1 to 1
+ x1 = (offset_x / window_width ) * 2 - 1
+ y1 = (offset_y / window_height) * 2 - 1
+ x2 = ((offset_x + scaled_width ) / window_width ) * 2 - 1
+ y2 = ((offset_y + scaled_height) / window_height) * 2 - 1
+
+ # Draw the image in the center with scaling
+ glBegin(GL_QUADS)
+ glTexCoord2f(0, 0)
+ glVertex2f(x1, y1)
+ glTexCoord2f(1, 0)
+ glVertex2f(x2, y1)
+ glTexCoord2f(1, 1)
+ glVertex2f(x2, y2)
+ glTexCoord2f(0, 1)
+ glVertex2f(x1, y2)
+ glEnd()
+
+ glDisable(GL_BLEND)