how to make a reduced image file in python - python

I'm in a beginning programming class, and our project is to reduce an image to half it's size and then to double it's size.
How do I make a new picture that is the same picture as before, but with the reduced height and width?
This is the code that I have:
def main():
originalPic=makePicture(pickAFile())
show(originalPic)
w=getWidth(originalPic)
h=getHeight(originalPic)
printNow(str(w)+ " \n" + str(h))
if w % 2:
reducedW=w/2
else:
reducedW=w/2+1
printNow(reducedW)
if h % 2:
reducedH=h/2
else:
reducedH=h/2+1
printNow(reducedH)
reducedPic=makePicture(reducedW, reducedH)
show(reducedPic)

Here's how I do that in PIL (Pillow):
from PIL import Image, ImageTk
my_image = Image.open('image.png') # open image
my_image = my_image.resize((my_image.size[0] * 2, my_image.size[1] * 2)) # resize
my_image.save('new_image.png') # save image
tk_image = ImageTk.PhotoImage(my_image) # convert for use in tkinter

As a beginner, you might want to stick to using Pygame rather than PIL to actually implement your skeleton code. We'll just load our image into Pygame, scale it up or down, and then save it.
import pygame, sys
pygame.init(); scale = 2 # or a half
image = pygame.image.load('image.png')
w = image.get_width() * scale
h = image.get_height() * scale
pygame.transform.scale(image, (w, h), image)
pygame.image.save(image, 'scaled_image.png')

Related

Python PIL - How to put text on a video

I am writing a program that puts captions on the screen and I am using PIL because it has high-quality text that is way better than the default moviepy text. I currently can put the text on a black screen, I tried using a fully transparent image as a sort of hack but that didn't work. So if anyone knows how to put PIL text on an image, or up the quality of the default moviepy text, let me know, please. Here is my basic code to put white text on a black background:
import numpy as np
from moviepy.editor import *
from PIL import Image, ImageFont, ImageDraw
SIZE = (1280, 720)
DURATION = 2
FPS = 1
TEXT = "I am having a hard time"
FONT_SIZE = 100
TEXT_COLOR_HEX = "#ffffff"
FONT = "Amiri-Bold"
def create_PIL():
img = Image.new("RGB", size=SIZE)
#draw = ImageDraw.Draw(img)
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(f"../Fonts/UniNeue-Trial-Bold.ttf", size=FONT_SIZE)
draw.text((100, 100), TEXT, font=font, fill=TEXT_COLOR_HEX)
img = np.array(img)
return VideoClip(lambda t: img, duration=DURATION).set_fps(FPS)
final = concatenate_videoclips(
[create_PIL()]
)
final.write_videofile('./test.mp4')
I am trying to put this text onto a video, and I need to have custom start and duration times but all this does it put it on a black screen, which is what I expected but not what I want.

Is there any method to provide the user an option to resize his image before uploading it to my tkinter fyi window

I am working on a project (tkinter-python) similar to the profile page of Instagram and have provided a function to the user to choose his image that needs to be uploaded to the window but I want a the size of the image that is going to be uploaded should be less than a specific size . What should I do to provide the option to the user to resize his image before uploading ?
from tkinter import *
from PIL import Image,ImageTk
import tkinter.messagebox as tmsg
#Profile Photo
image=Image.open(f"{name}.jpg")
width,height=image.size
area=width*height
if area<=160012:
photo=ImageTk.Photoimage(image)
Label(image=photo).place(X=1000,y=2)
else:
tmsg.showinfo('Crop image','WIDTH X HEIGHT must be smaller than 160012')
You can do the image resize for the user:
from tkinter import *
from PIL import Image,ImageTk
MAX_AREA = 160012
#Profile Photo
name = 'path/to/user/profile/image'
image = Image.open(f"{name}.jpg")
width, height = image.size
area = width * height
if area > MAX_AREA:
# determine the resize ratio
ratio = (MAX_AREA / area) ** 0.5
# calculate the resized width and height
new_w = int(width * ratio)
new_h = int(height * ratio)
# resize the image
image = image.resize((new_w, new_h))
print(f'Image is resized from {width}x{height} ({area}) to {new_w}x{new_h} ({new_w*new_h})')
root = Tk()
root.geometry('1000x600')
photo = ImageTk.PhotoImage(image)
Label(image=photo).place(x=1000, y=0, anchor='ne')
root.mainloop()

How to preserve RGB color while saving png using PIL?

I've written a python program that combines three png images into a single image. I'm using PIL to open, resize, combine, and save the resulting image. All the functionality is there but the resulting image has a completely diferently color profile from the original.
I have tried several options:
1. I've attempted to create the new Image as "RGBA"
Result: Image no longer displayed by TKinter GUI
2. Attempted to copy the color profile from the original image then using that profile when saving the final image:
Code: profile = image.info.get("icc_profile", "") then I use the resulting variable when saving the file using the argument icc_profile = profile
Result: No change
Minimal Reproducible Code
from PIL import Image as pImage
from tkinter.filedialog import asksaveasfilename
newImage = pImage.new('RGB', (976, 976))
background = pImage.open("Gameboy_Background.png")
screen_shot = pImage.open("screenshot.png")
cover_art = pImage.open("[coverart.png][1]")
newImage.paste(background)
w, h = screen_shot.size
newW = 875
newH = int(newW * h / w)
screen_shot = screen_shot.resize((newW, newH), pImage.ANTIALIAS)
newImage.paste(screen_shot, (50, 155))
w, h = cover_art.size
newW = 175
newH = int(newW * h / w)
cover_art = cover_art.resize((newW, newH), pImage.ANTIALIAS)
newImage.paste(cover_art, (100, 205))
file2Save = asksaveasfilename(initialdir="/", title="Select file", filetypes={("PNG files", "*.png")})
newImage.save(file2Save + ".png", "PNG")
PNG IMAGES USED
1: https://i.stack.imgur.com/Lj1wo.png
[2]: https://i.stack.imgur.com/4iauQ.png
[3]: https://i.stack.imgur.com/2voFC.png
Resulting Image
profile = image.info.get("icc_profile", "") then I use the resulting variable when saving the file using the argument icc_profile = profile
That sounds like the right approach to me, actually. image is the screenshot image, right? That's the one whose profile you want to copy.
from PIL import Image as pImage
from tkinter.filedialog import asksaveasfilename
newImage = pImage.new('RGB', (976, 976))
background = pImage.open("Gameboy_Background.png")
screen_shot = pImage.open("screenshot.png")
cover_art = pImage.open("coverart.png")
newImage.paste(background)
profile = screen_shot.info.get("icc_profile", "")
w, h = screen_shot.size
newW = 875
newH = int(newW * h / w)
screen_shot = screen_shot.resize((newW, newH), pImage.ANTIALIAS)
newImage.paste(screen_shot, (50, 155))
w, h = cover_art.size
newW = 175
newH = int(newW * h / w)
cover_art = cover_art.resize((newW, newH), pImage.ANTIALIAS)
newImage.paste(cover_art, (100, 205))
file2Save = "output"
newImage.save(file2Save + ".png", "PNG", icc_profile=profile)
Result:
I think so there is a problem when you open and read the image.Try this use tkinkter gui to open and read files and then use numpy to convert into array. A code like this:
import tkinter as tk
from tkinter import filedialog
import numpy as np
//get ur extension as png file
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename(filetypes = (("jpeg files","*.jpg"),("all files","*.*")))
images = Image.open(file_path)
image_data=np.asarray(image)
image_data = cv2.cvtColor(image_data, cv2.COLOR_BGR2RGB)
U have ur image in rgb mode in image_data variable save it or use it for further processing

Python / pygame error with my custom image import module (image animation)?

I have created a custom module for importing images and be able to resize it and easily animate them (basicly you say the frames that it have the animation, and it's split the image to the amount you say).
(I know that they are not perfect!)
Here is the module "load.py"
#IMPORT MODULES
try:
import pygame; pygame.init()
import os
except: pass
#------------------------------------------------------------------------------
#DEFAULT VALUES
Image_Frames = 1
Image_Size = (0,0)
#------------------------------------------------------------------------------
def image(name,frames=Image_Frames,size=Image_Size):
#Load Image
try:
img = pygame.image.load(name).convert_alpha()
except: return None
#Single / Multi Frame
if frames <= 1:
if not 0 in size: img = pygame.transform.scale(img,size)
return img
else:
#Set Variables
frame_y = 0
frames_list = []
frame_height = int(img.get_size()[1] / frames)
#Loop Frames
for frame in range(frames):
#Create a Surface and blit part of the image (Single Frame)
frame_surface = pygame.Surface((img.get_size()[0], frame_height),pygame.SRCALPHA)
frame_surface.blit(img,(0,0),(0,frame_y,img.get_size()[0],frame_height))
#If both values of size are not 0 scale it to size
if not 0 in size: img = pygame.transform.scale(frame_surface,size)
#Add it to list of Frames and prepare for next
frames_list.append(frame_surface)
frame_y += frame_height
#Return Frames
return frames_list
The main code (Not perfect, just simply to see the images):
import pygame; pygame.init()
Screen = pygame.display.set_mode((800,800))
import load
images = load.image("test.png",2,(400,300))
while True:
Screen.fill((255,0,255))
Screen.blit(images[0],(0,0))
Screen.blit(images[1],(0,400))
pygame.display.update()
And there is this a image that I use (Sorry I can't show images... :( )
https://www.dropbox.com/s/u7nghxntor2vbt1/test.png?dl=0
And this is the problem...
What's suppose to happen is that the images are separated into 2,
and the each image is scaled up to 400,300.
But then this happens when I run the code:
https://www.dropbox.com/s/idrsygynftb1oua/Sin%20t%C3%ADtulo.png?dl=0
The first one doesn't scale, and the second one makes something strange...
But that only happens when you do more than 1 'frames'.
If you change it to only do one image, it works fine (code example for main.py)
import pygame; pygame.init()
Screen = pygame.display.set_mode((800,800))
import load
images = load.image("test.png",1,(400,300))
while True:
Screen.fill((255,0,255))
Screen.blit(images,(0,0))
pygame.display.update()
Any fix? Ask anything you what if you need more info of me.
Actually fix!
Your code:
#If both values of size are not 0 scale it to size
if not 0 in size:
>> img << = pygame.transform.scale(frame_surface,size)
should be:
#If both values of size are not 0 scale it to size
if not 0 in size:
>> frame_surface << = pygame.transform.scale(frame_surface,size)

How can I convert canvas content to an image?

from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
I want to convert canvas content to a bitmap or other image, and then do other operations, such as rotating or scaling the image, or changing its coordinates.
Bitmaps can improve efficiency to show if I am no longer drawing.
What should I do?
You can either generate a postscript document (to feed into some other tool: ImageMagick, Ghostscript, etc):
from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
cv.update()
cv.postscript(file="file_name.ps", colormode='color')
root.mainloop()
or draw the same image in parallel on PIL and on Tkinter's canvas (see: Saving a Tkinter Canvas Drawing (Python)). For example (inspired by the same article):
from Tkinter import *
import Image, ImageDraw
width = 400
height = 300
center = height//2
white = (255, 255, 255)
green = (0,128,0)
root = Tk()
# Tkinter create a canvas to draw on
cv = Canvas(root, width=width, height=height, bg='white')
cv.pack()
# PIL create an empty image and draw object to draw on
# memory only, not visible
image1 = Image.new("RGB", (width, height), white)
draw = ImageDraw.Draw(image1)
# do the Tkinter canvas drawings (visible)
cv.create_line([0, center, width, center], fill='green')
# do the PIL image/draw (in memory) drawings
draw.line([0, center, width, center], green)
# PIL image can be saved as .png .jpg .gif or .bmp file (among others)
filename = "my_drawing.jpg"
image1.save(filename)
root.mainloop()
I have found a great way of doing this which is really helpful. For it, you need the PIL module. Here is the code:
from PIL import ImageGrab
def getter(widget):
x=root.winfo_rootx()+widget.winfo_x()
y=root.winfo_rooty()+widget.winfo_y()
x1=x+widget.winfo_width()
y1=y+widget.winfo_height()
ImageGrab.grab().crop((x,y,x1,y1)).save("file path here")
What this does is you pass a widget name into the function. The command root.winfo_rootx() and the root.winfo_rooty() get the pixel position of the top left of the overall root window.
Then, the widget.winfo_x() and widget.winfo_y() are added to, basically just get the pixel coordinate of the top left hand pixel of the widget which you want to capture (at pixels (x,y) of your screen).
I then find the (x1,y1) which is the bottom left pixel of the widget. The ImageGrab.grab() makes a printscreen, and I then crop it to only get the bit containing the widget. Although not perfect, and won't make the best possible image, this is a great tool for just getting a image of any widget and saving it.
If you have any questions, post a comment! Hope this helped!
Use Pillow to convert from Postscript to PNG
from PIL import Image
def save_as_png(canvas,fileName):
# save postscipt image
canvas.postscript(file = fileName + '.eps')
# use PIL to convert to PNG
img = Image.open(fileName + '.eps')
img.save(fileName + '.png', 'png')
Maybe you can try to use widget_winfo_id to get the HWND of the canvas.
import win32gui
from PIL import ImageGrab
HWND = canvas.winfo_id() # get the handle of the canvas
rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
im = ImageGrab.grab(rect) # get image of the current location
A better way for #B.Jenkins's answer that doesn't need a reference to the root object:
from PIL import ImageGrab
def save_widget_as_image(widget, file_name):
ImageGrab.grab(bbox=(
widget.winfo_rootx(),
widget.winfo_rooty(),
widget.winfo_rootx() + widget.winfo_width(),
widget.winfo_rooty() + widget.winfo_height()
)).save(file_name)
On my system had serious issues with ghostscript and the ImageGrab in general. Solution draw on PIL Image, save as a file, load file on PhotoImage, which is used to create new TKinter Canvas.
canvas = Canvas(win, width=IMG_W, height=IMG_H)
img = PILImg.new("RGB", (IMG_W, IMG_H), "#000")
draw = ImageDraw.Draw(img)
draw.rectangle([x,y,w,h], fill=color, outline=border)
img.save("stock-chart.png")
copyImg = PhotoImage(file="stock-chart.png")
canvas.create_image(IMG_W_2, IMG_H_2, image=copyImg)

Categories