Insert Image into a pdf at a specified location - python

I'm relatively new to python, and I'm trying to replace an image at a given location.
The idea is to check if the extracted image in the PDF matches the image I want to replace. If it does, I extract the location and put the new image in its place. I'm done with the extracting and checking part. Could someone please help me with the later part?

Step 1: convert mypdf.pdf to full_page_image.jpg
from pdf2image import convert_from_path
pages = convert_from_path('mypdf.pdf', 500)
pages[x].save('full_page_image.jpg', 'JPEG') #where x is your page number minus one
Step 2: overlay image_to_be_added onto full_page_image
import cv2
import numpy as np
full_page_image = cv2.imread('full_page_image.jpg')
image_to_be_added = cv2.imread('image_to_be_added.jpg')
final_image = full_page_image.copy()
final_image[100:400,100:400,:] = image_to_be_added[100:400,100:400,:] #adjust the numbers according to the dimensions of the image_to_be_added
cv2.imwrite(final_image.jpg, final_image)
Step3: convert final_image.jpg to final_pdf.pdf
from PIL import Image
final_image2 = Image.open(r'final_image.jpg')
final_image3 = final_image2.convert('RGB')
final_image3.save(r'final_pdf.pdf')

Related

When i convert images to greyscale with pil it rotates them

When i convert images to greyscale with pil it rotates them.
How do i disable this?
from PIL import Image
import os
path = 'spanish_pages_photos/'
pathContents = os.listdir(path)
list = []
# get file names and append to list
for i in pathContents:
list.append(i)
list = sorted(list)
#loop through and change to grey scale
for i in list[2:]:
img = Image.open(f'spanish_pages_photos/{i}').convert('L')
img.save(f'spanish_pages_photos/{i}')
print('finished')
The EXIF data can contain an "EXIF Orientation" field. Try auto-orienting with PIL.ImageOps.exif_transpose().
See here.

Interpret bytes in a string as RGB in Python

I was wondering if this was possible.
I'm currently drafting a simple project that would transform my text files into images by using the values of the characters to determine the RGB values of the outputted image.
I know it sounds counterintuitive and no, I don't want to print a string into an image file, I want the text itself to determine the RGB values of each pixel. This is just a rough idea and is far from refined.
I just want a simple program that will work as a proof of concept.
Code so far:
#first contact
from ctypes import sizeof
from PIL import Image
import math as m
def test():
f='qran.txt'
file = open(f)
text = file.read()
file.close() # this is dumb, should just read from file instead of dumping it into a
text = list(text) #rudimentary fix, turn text into list so we can manage the characters
size = m.floor(m.sqrt(len(text)//3)) #round the value for a square image
print(size)
# for elem in text:
# print(ord(elem))
img = Image.new('RGB', (size,size))
pixels = img.load() # create the pixel map
c = 0
for i in range(img.size[0]): # for every col:
for j in range(img.size[1]): # For every row
pixels[i,j] = (ord(text[c]), ord(text[c+1]), ord(text[c+2])) # set the colour accordingly
c+=1
c+=1
img.show()
img.save('qran.png')
test()
As you can see right now my idea is working as a rough concept. You can copy the quran in plaintext and paste it in the same folder as this simple py program to see this output
The image comes out as dull, since characters are converted into integers and their values are too high, and so most colors come off as light-dark gray.
Are there some libraries that could help with exaggerating the values so that they would come off as more representative? I've thought of multiplying by 10 and truncating the result of inverting the values then applying some filters.
I know its pretty much trial and error by this point (as well as polishing the actual code to provide usable functions that allow tweaking images without editing the function over and over again) but I'd like some outside input from people that have dwelved into image processing and such in python.
I apologize in advance if this post was too wordy or contained some unnecessary tidbits, it's my first post in this community.
Just implementing Christoph's idea in the comments:
#!/usr/bin/env python3
from PIL import Image
import math as m
import pathlib
import numpy as np
# Load document as bytes
qran = pathlib.Path('qran.txt').read_bytes()
size = m.floor(m.sqrt(len(qran))) #round the value for a square image
# Make palette image from bytes
img = Image.frombuffer('P', (size,size), qran, "raw", 'P', 0, 1)
# Add random palette of 256 RGB triplets to image
palette = np.random.randint(0,256, 768, np.uint8)
img.putpalette(palette)
img.save('qran.png')

Lost information getting pdf page as image

I am not an expert in any sense, I am trying to extract a pdf page as an image to do some processing later. I used the following code for that, that I built from other recommendations in this page.
import fitz
from PIL import Image
dir = r'C:\Users\...'
files = os.listdir(dir)
print(dir+files[21])
doc = fitz.open(dir+files[21])
page = doc.loadPage(2)
zoom = 2
mat = fitz.Matrix(zoom, zoom)
pix = page.getPixmap(matrix = mat)
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
density=img.getdata()
Usually this would give me the pixel information of the image, but in this case it returns a list of white pixels. I have no clue as for what is the reason of this... The image (img) is displayed if asked, but not its data.
I will appreciate any help?
If you want to convert pdf to image, and process, you might use something along these lines. This particular simple example reads in 5 pages of the PDF, and for the last page, looks at what percentage of the image is a particular color; the slow way and fast way.
import pdf2image
import numpy as np
# details:
# https://pypi.org/project/pdf2image/
images = pdf2image.convert_from_path('test.pdf')
# Get first five pages, just for testing
i = 1
for image in images:
print(i," shape: ", image.size)
image.save('output' + str(i) + '.jpg', 'JPEG')
i = i + 1
if(i>5):
break
color_test=(128,128,128)
other=0
specific_color=0
# Look at last image
for i in range(image.width):
for j in range(image.height):
x=image.getpixel((i,j))
if(x[0]==color_test[0] and x[1]==color_test[1] and x[2]==color_test[2]):
specific_color=specific_color+1
else:
other=other+1
print("frac of specific color = ", specific_color/(specific_color+other))
# faster!
x=np.asarray(image)
a=np.where(np.all(x==color_test,axis=-1))
print("(faster) frac of color = ", len(a[0])/((image.width)*(image.height)))
The code works if I take a shorter path and replace doc.loadPage with doc.getPagePixmap
import fitz
from PIL import Image
dir = r'C:\Users\...'
files = os.listdir(dir)
print(dir+files[21])
doc = fitz.open(dir+files[21])
pix= doc.getPagePixmap(2)
img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
density=img.getdata()
I still don't know why the long code fails, and the working method doesn't allows me to get a better resolution version of the exctracted page.

Imageio or OpenCv saves black blank image after altering image array

Okay, I am trying to do sort of simple image encryption for my college project, all I need to do is open an image as a numpy array and increment the pixel values by an integer key, then save it as 16 bit image, then open that Image and. But whenever I increment the pixels the result turns into a deformed image of that only has shades of black, and when I try to get the original image by performing the reverse (decremented the pixels with the same integer key), it results in a full black blank image. The dimensions are correct but all the data seems to be lost(though when I print the matrices the values seem to be correct).
I have tried using Imageio with freeimage plugin, and open cv but nothing seems to work. I am also a noob so I don't know if I am missing something else
from tkinter import filedialog
from tkinter import *
from PIL import Image
import cv2 as cv
import os
import numpy as np
def encrypt(k):
iload = filedialog.askopenfilename(parent=Main,initialdir=os.getcwd(),title="Please select a file:",filetypes = (("PNG files","*.png"),("jpeg files","*.jpg"),("all files","*.*")))
im= cv.imread(iload,cv.IMREAD_UNCHANGED)
im = im.astype(np.uint16)
print("After Open File Type : ",im.dtype)
print("Orinigal Image : ",im)
im = im.tolist()
for l in range(len(im)):
for j in range(len(im[l])):
for i in range(len(im[l][j])):
im[l][j][i]+=k
#im.putdata(npxls)
im=np.array(im).astype(np.uint16)
#imen.show()
print("Encrypted Image : ",im)
#imageio.imwrite("encrypted.png",im,format='PNG-FI')
cv.imwrite("encrypted.png",im)
img=cv.imread("encrypted.png",cv.IMREAD_UNCHANGED | cv.IMREAD_ANYCOLOR | cv.IMREAD_ANYDEPTH)
print("After Encrypting Saved File Type :",img.dtype)
def decrypt(k):
iload = filedialog.askopenfilename(parent=Main,initialdir=os.getcwd(),title="Please select a file:",filetypes = (("PNG files","*.png"),("jpeg files","*.jpg"),("all files","*.*")))
im=cv.imread(iload, cv.IMREAD_UNCHANGED | cv.IMREAD_ANYCOLOR | cv.IMREAD_ANYDEPTH)
print("Original Image : ",im)
print("After Decrypting Image Type: ",im.dtype)
im = im.astype(np.uint16)
im = im.tolist()
for l in range(len(im)):
for j in range(len(im[l])):
for i in range(len(im[l][j])):
im[l][j][i]-=k
im=np.array(im).astype(np.uint16)
#imen.show()
print("Decrypted Image : ",im)
cv.imwrite("decrypted.png",im,[CV_LOAD_IMAGE_ANYDEPTH ])
img=cv.imread("decrypted.png", cv.IMREAD_ANYCOLOR | cv.IMREAD_ANYDEPTH)
print("After Decrypting Saved Image type: ",img.dtype)
I just need the Image to get changed by adding a key to the pixel values in way that I can change it back with the reverse operation.

Storing/Retrieving array images with Pyautogui (AttributeError: 'Image' object has not attribute 'read')

I'm trying to locate an image, then store another image relative to the first one within an array. Afterwards, I want those images to drop into a word document using the docx library. Currently, I'm getting the following error, despite a few different solutions I've tried below. Here's the code:
import sys
import PIL
import pyautogui
import docx
import numpy
def grab_paperclip_images():
'''
This'll look at the documents that're on
the current screen, and create images of
each document with a paperclip. I'll be
testing on an unsorted screen first.
'''
image_array = []
clip_array = find_all_objects("WHITE_PAPERCLIP.png")
for item in clip_array:
coordinates = item[0]+45, item[1], 222, item[3]
image_array.append(pyautogui.screenshot(region=coordinates))
return image_array
doc = docx.Document()
images = grab_paperclip_images()
for image in images:
#print image
#yields: [<PIL.Image.Image image mode=RGB size=222x12 at 0x7CC7770>,etc]
#Tried this - no dice
#img = PIL.Image.open(image)
#doc.add_picture(img)
doc.add_picture(image)
doc.save("testDoc.docx")
Please let me know what I'm misunderstanding, and if you see any suggestions to make the code more pythonic, better scoped, etc.
As always, thanks for the help, sincerely!
Figured out a way around this. I had to save the images to disk. I could still reference the array, but I couldn't reference the image without saving it. Here's my workaround:
def grab_paperclip_images():
'''
This'll look at the documents that're on
the current screen, and create images of
each document with a paperclip. I'll be
testing it on an unsorted screen first.
INSPIRATION:
bottom_record = pyautogui.screenshot(
"LAST_RECORD.png",
region=(
last_clip[0],
last_clip[1]+18,
1100,
14
)
)
'''
image_array = []
clip_array = find_all_objects("WHITE_PAPERCLIP.png")
count = 0
for item in clip_array:
coordinates = item[0]+45, item[1], 222, item[3]
filename = "image"+str(count)+".png"
image = pyautogui.screenshot(filename, region=coordinates)
image_array.append(filename)
count += 1
return image_array
doc = docx.Document()
images = grab_paperclip_images()
for image in images:
doc.add_picture(image)
doc.save("dingding2.docx")
delete_all(images)

Categories