update upload file

This commit is contained in:
Admin 2025-09-19 13:55:03 +07:00
parent 5c36fa0d3d
commit 4a5b6dd8aa
5345 changed files with 0 additions and 837397 deletions

BIN
.DS_Store vendored

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
python -m uvicorn main:app --reload --host 127.0.0.1 --port 8443 --ssl-keyfile=key.pem --ssl-certfile=cert.pem

View File

@ -1,101 +0,0 @@
from fastapi import FastAPI, Body
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
from openai import OpenAI
import pyautogui
import os
import time
import pyperclip
print("Di chuot den o nhap tin nhan trong 5 giay ...")
time.sleep(5)
input_position = pyautogui.position()
print(f"Da lay toa do: {input_position}")
x,y = input_position
# Thiết lập API key cho OpenAI
client = OpenAI(api_key="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") # Hoặc gán trực tiếp: "sk-..."
app = FastAPI()
# Cấu hình CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Dữ liệu đầu vào cho API
class Message(BaseModel):
name: str
message: str
time: int
room_id: str
room_name: str
x: int
y: int
# Gọi OpenAI và giả lập nhập liệu
def generate_and_type_reply(sender: str, content: str, x: int, y: int):
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ban la tro ly tin nhan AI tra loi ngan gon va day du y, than thien. Tra loi tieng Anh. Format xuong dong bang \n"},
{"role": "user", "content": f"{sender} sent: {content}"}
]
)
reply = response.choices[0].message.content
print(f"AI tra loi: {reply}")
time.sleep(1)
pyautogui.click(x, y)
time.sleep(1)
for line in reply.split("\n"):
pyautogui.write(line, interval=0.01)
pyautogui.hotkey("shift", "enter")
time.sleep(1)
time.sleep(0.5)
pyautogui.press("enter")
pyautogui.press("enter")
pyautogui.press("enter")
return reply
except Exception as e:
return f"Lỗi khi gọi AI: {str(e)}"
# API để nhận tin nhắn và phản hồi
@app.post("/reply/")
def reply_to_message(msg: Message):
print(f"[{msg.room_name}] {msg.name}: {msg.message}")
reply = generate_and_type_reply(msg.name, msg.message, msg.x, msg.y)
return {
"sender": msg.name,
"message": msg.message,
"room": msg.room_name,
"reply": reply
}
@app.post("/type/")
def type(message: str = Body(..., embed=True)):
try:
print(f"Typing message: ")
pyautogui.click(x, y)
time.sleep(1)
# Copy vào clipboard và dán
pyperclip.copy(message)
pyautogui.hotkey("ctrl", "v")
time.sleep(0.5)
# Gửi Enter để gửi
pyautogui.press("enter")
return {"status": "success", "typed": message}
except Exception as e:
return {"status": "error", "detail": str(e)}

View File

@ -1,13 +0,0 @@
fastapi==0.111.0
uvicorn==0.29.0
pydantic==2.7.1
openai==1.30.1
pyautogui==0.9.54
pymsgbox==1.0.9
pytweening==1.0.7
pygetwindow==0.0.9
pyrect==0.2.0
PyScreeze==0.1.30
pyobjc-core==10.1
pyobjc-framework-Quartz==10.1
pyobjc-framework-Cocoa==10.1

View File

@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID1TCCAr2gAwIBAgIUOWbfSNEe+a/qZo/1Y7DOFM6WZZ8wDQYJKoZIhvcNAQEL
BQAwejELMAkGA1UEBhMCQVQxDjAMBgNVBAgMBUFkbWluMQ4wDAYDVQQHDAVBZG1p
bjEOMAwGA1UECgwFQWRtaW4xCzAJBgNVBAsMAkFUMQ4wDAYDVQQDDAVBZG1pbjEe
MBwGCSqGSIb3DQEJARYPYWRtaW5AZ21haWwuY29tMB4XDTI1MDgwNTAyMjMzOFoX
DTI2MDgwNTAyMjMzOFowejELMAkGA1UEBhMCQVQxDjAMBgNVBAgMBUFkbWluMQ4w
DAYDVQQHDAVBZG1pbjEOMAwGA1UECgwFQWRtaW4xCzAJBgNVBAsMAkFUMQ4wDAYD
VQQDDAVBZG1pbjEeMBwGCSqGSIb3DQEJARYPYWRtaW5AZ21haWwuY29tMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtK8sAFtijD7IG5UP7DIE1zaGUUch
YH9ubXOb0LX5tqb3asLVqFehveRUVolUoG3t+wM8yaxF/MBk4vkEZoEbhQiKGDfV
37FakHcw74cLEPgMuVGU91/yt3ca8+6zSSYcsIpJaWIWFNlGMnk3TIs4HRnM80rY
1R6q94SP3Yx2/DlcKoYxb/onnRs8pTJZPIw+YdRm1Yput6EO1WTjinG9JmAbeNsS
f643nN0oQ5JYf0JTQXi/8iLJExwJwbl+97aS2+l/+tSujqIkLUE1ighxGk7ZxZfO
3V9gd5kdSYbsMhQqDdEUjmmNqmAQ6F8MRkPu8+/jAfQH73+rzQBrqZMe+QIDAQAB
o1MwUTAdBgNVHQ4EFgQUSmsyedYpQW1A9z0IVbQ4wR2gDcYwHwYDVR0jBBgwFoAU
SmsyedYpQW1A9z0IVbQ4wR2gDcYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOCAQEAZd0OO2r/vs+56PhDLnB9fMiA8WSD9d2J8VNaA1IYCRkEQwEHlFUQ
CSu9ZIJtU+UXcDpnjzHc7hV1yYufhMTKUPWY9rlVypWoCoOyMw7Z9O0Tk+je4g2i
ChV2HSAYFSAhJrt1zNUofNBjXjgX08Mr65LYo3eIj9Pl8dmfun5wjDAlNv6uj9+F
eJzlsnCa2/fDn6zDGzKALXtNOPA/jNoKVP5uGbgCxaUNFA5dZvA5MBg8jXYC2r/Z
bL47zml8alx+HOgxJkkeQqx5rjBw+j2fNK7h3ot6ME7Gu9+MDgg2n1rKiJqrWCTH
oi0vQprP9ccgTHQB5cHTEQsOQhYcOjq9ug==
-----END CERTIFICATE-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0rywAW2KMPsgb
lQ/sMgTXNoZRRyFgf25tc5vQtfm2pvdqwtWoV6G95FRWiVSgbe37AzzJrEX8wGTi
+QRmgRuFCIoYN9XfsVqQdzDvhwsQ+Ay5UZT3X/K3dxrz7rNJJhywiklpYhYU2UYy
eTdMizgdGczzStjVHqr3hI/djHb8OVwqhjFv+iedGzylMlk8jD5h1GbVim63oQ7V
ZOOKcb0mYBt42xJ/rjec3ShDklh/QlNBeL/yIskTHAnBuX73tpLb6X/61K6OoiQt
QTWKCHEaTtnFl87dX2B3mR1JhuwyFCoN0RSOaY2qYBDoXwxGQ+7z7+MB9Afvf6vN
AGupkx75AgMBAAECggEAAlrmqUxuCUf8gnyG+1QiRnfzcf3p+28JyANjegNtmvHl
iqN5vRxQTPbCQSlm1c6Wm6JM2AMzqDunQC/QybFZqk2EhEdYO+NQFYI4nD4/vw1Z
2Bs68USaEXlfIiPf1YTs4PTnR+hjab5OKSecK7zRHH/K6uoBHJNuFQFKGtzv95gv
r0ECwJoZo+pWswYmUiHeaBLrxdAq4LNdKVLKcZ3Pi6NU3pSQynGRLkjTC1PqSiUm
KAWHFEpt6Co5AVDkgBc5TNIex90khKZIRciFNL8VjR1su3EJZ2m71cqagvMhBVz1
g4wHY7FR6liqiC9NuFT2FfVer56sX5+GZtw21J9lUQKBgQDm6avJ0NXplo7Lhta4
4CI2nn1jdk+7kGVBCHyRevdtFrcXsO8rbpv8cyuZy+tNGtPg995pJYkE55uv11T1
Ar8Qk0SbpMefexv33XcX5/wIGB34xgZ31XoUAYAkpFi7iY2hOQgpTaftOJ5D3UHj
k9OHk+zRAclv8nvvrGY6KwENqQKBgQDIUIF0sRHQWbulSGOo2PeXO5p9Gh/brEg2
/orfftj5BmY4Rmin6ZPeShh9huVxCwId3+DPZxYulyeu0BLLXloZ5Z8ZnDkiG9Ux
okm1691BUqJTguKE3EuB5yZ6kOT8QL/9yifXYn+O8BDKN/V4s+nDop2e13GRrGoM
SHS0jSo40QKBgC0IUy1XofAdIZoFoOiLJYD7Zb64+xG8NlL5gbmpfolyzaA8LFiP
CLKyD0W+JBR0b+/Gx0RAQrmHJbCkUPg7YeGspsun1hp/GtQ7B5fM8TTu5yF2FRrX
sigmpsP+nSNtzwYrJjFP6Lj1ur/HbashUDZ3nc6hB5TieFMkjwc3DcyJAoGBAK7m
TAIdURaAIu0PpaSZvKSZcCxnEQX3CR6rZYn68WuNgNcF8v8ZXPir7XI8xDzNhc2b
2mh888s+Q3HJT3+uJDGUYjQ0SVZUwvMRZhanmIoeookUMMAcsPj9YIWH2ce+qWPo
jJzs7b9aMO6/qV74h9U/OSylpA2zYuzSnsO+tezhAoGBAIDenq6wO29gCbIdiOoU
5AAKaIfHFSqr62eLjy/1ZhJ8rsmi75Du4MMwEsCJN/btx68SHnvdk1EL+sEJaUp1
cUgX4inKRajuQtVQ5BFtH0/r5g5gXgCtlloz+1jyQi+i+YidW8tW+88kXCjO1ZiS
JWLFknfFx8L1xUBW3R1Hadvz
-----END PRIVATE KEY-----

View File

@ -1,247 +0,0 @@
<#
.Synopsis
Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
$Env:PATH environment variable and sets the prompt to signify that you are
in a Python virtual environment. Makes use of the command line switches as
well as the `pyvenv.cfg` file values present in the virtual environment.
.Parameter VenvDir
Path to the directory that contains the virtual environment to activate. The
default value for this is the parent of the directory that the Activate.ps1
script is located within.
.Parameter Prompt
The prompt prefix to display when this virtual environment is activated. By
default, this prompt is the name of the virtual environment folder (VenvDir)
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
.Example
Activate.ps1
Activates the Python virtual environment that contains the Activate.ps1 script.
.Example
Activate.ps1 -Verbose
Activates the Python virtual environment that contains the Activate.ps1 script,
and shows extra information about the activation as it executes.
.Example
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
Activates the Python virtual environment located in the specified location.
.Example
Activate.ps1 -Prompt "MyPython"
Activates the Python virtual environment that contains the Activate.ps1 script,
and prefixes the current prompt with the specified string (surrounded in
parentheses) while the virtual environment is active.
.Notes
On Windows, it may be required to enable this Activate.ps1 script by setting the
execution policy for the user. You can do this by issuing the following PowerShell
command:
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For more information on Execution Policies:
https://go.microsoft.com/fwlink/?LinkID=135170
#>
Param(
[Parameter(Mandatory = $false)]
[String]
$VenvDir,
[Parameter(Mandatory = $false)]
[String]
$Prompt
)
<# Function declarations --------------------------------------------------- #>
<#
.Synopsis
Remove all shell session elements added by the Activate script, including the
addition of the virtual environment's Python executable from the beginning of
the PATH variable.
.Parameter NonDestructive
If present, do not remove this function from the global namespace for the
session.
#>
function global:deactivate ([switch]$NonDestructive) {
# Revert to original values
# The prior prompt:
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
}
# The prior PYTHONHOME:
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
}
# The prior PATH:
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
}
# Just remove the VIRTUAL_ENV altogether:
if (Test-Path -Path Env:VIRTUAL_ENV) {
Remove-Item -Path env:VIRTUAL_ENV
}
# Just remove VIRTUAL_ENV_PROMPT altogether.
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
}
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
}
# Leave deactivate function in the global namespace if requested:
if (-not $NonDestructive) {
Remove-Item -Path function:deactivate
}
}
<#
.Description
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
given folder, and returns them in a map.
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
two strings separated by `=` (with any amount of whitespace surrounding the =)
then it is considered a `key = value` line. The left hand string is the key,
the right hand is the value.
If the value starts with a `'` or a `"` then the first and last character is
stripped from the value before being captured.
.Parameter ConfigDir
Path to the directory that contains the `pyvenv.cfg` file.
#>
function Get-PyVenvConfig(
[String]
$ConfigDir
) {
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
# An empty map will be returned if no config file is found.
$pyvenvConfig = @{ }
if ($pyvenvConfigPath) {
Write-Verbose "File exists, parse `key = value` lines"
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
$pyvenvConfigContent | ForEach-Object {
$keyval = $PSItem -split "\s*=\s*", 2
if ($keyval[0] -and $keyval[1]) {
$val = $keyval[1]
# Remove extraneous quotations around a string value.
if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
$pyvenvConfig[$keyval[0]] = $val
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
}
}
}
return $pyvenvConfig
}
<# Begin Activate script --------------------------------------------------- #>
# Determine the containing directory of this script
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$VenvExecDir = Get-Item -Path $VenvExecPath
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# Set values required in priority: CmdLine, ConfigFile, Default
# First, get the location of the virtual environment, it might not be
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
}
else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
}
# Next, read the `pyvenv.cfg` file to determine any required value such
# as `prompt`.
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# Next, set the prompt from the command line, or the config file, or
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
}
else {
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
$Prompt = $pyvenvCfg['prompt'];
}
else {
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
$Prompt = Split-Path -Path $venvDir -Leaf
}
}
Write-Verbose "Prompt = '$Prompt'"
Write-Verbose "VenvDir='$VenvDir'"
# Deactivate any currently active virtual environment, but leave the
# deactivate function in place.
deactivate -nondestructive
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
# that there is an activated venv.
$env:VIRTUAL_ENV = $VenvDir
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
Write-Verbose "Setting prompt to '$Prompt'"
# Set the prompt to include the env name
# Make sure _OLD_VIRTUAL_PROMPT is global
function global:_OLD_VIRTUAL_PROMPT { "" }
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
function global:prompt {
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
_OLD_VIRTUAL_PROMPT
}
$env:VIRTUAL_ENV_PROMPT = $Prompt
}
# Clear PYTHONHOME
if (Test-Path -Path Env:PYTHONHOME) {
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
Remove-Item -Path Env:PYTHONHOME
}
# Add the venv to the PATH
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

View File

@ -1,69 +0,0 @@
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
VIRTUAL_ENV="/Users/admin/Workspace/do-something/teams-bots/write-message/venv"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1="(venv) ${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT="(venv) "
export VIRTUAL_ENV_PROMPT
fi
# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi

View File

@ -1,26 +0,0 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "/Users/admin/Workspace/do-something/teams-bots/write-message/venv"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = "(venv) $prompt"
setenv VIRTUAL_ENV_PROMPT "(venv) "
endif
alias pydoc python -m pydoc
rehash

View File

@ -1,69 +0,0 @@
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
# (https://fishshell.com/); you cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
set -e _OLD_FISH_PROMPT_OVERRIDE
# prevents error when using nested fish instances (Issue #93858)
if functions -q _old_fish_prompt
functions -e fish_prompt
functions -c _old_fish_prompt fish_prompt
functions -e _old_fish_prompt
end
end
set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
# Self-destruct!
functions -e deactivate
end
end
# Unset irrelevant variables.
deactivate nondestructive
set -gx VIRTUAL_ENV "/Users/admin/Workspace/do-something/teams-bots/write-message/venv"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT "(venv) "
end

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from distro.distro import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from dotenv.__main__ import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from email_validator.__main__ import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from fastapi_cli.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from httpx import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from markdown_it.cli.parse import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from openai.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pip._internal.cli.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from pygments.cmdline import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1 +0,0 @@
python3

View File

@ -1 +0,0 @@
/Users/admin/.pyenv/versions/3.10.13/bin/python3

View File

@ -1 +0,0 @@
python3

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from tqdm.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from typer.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from uvicorn.main import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from watchfiles.cli import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

View File

@ -1,8 +0,0 @@
#!/Users/admin/Workspace/do-something/teams-bots/write-message/venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from websockets.cli import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())

View File

@ -1,159 +0,0 @@
"""
Python mapping for the AppKit framework.
This module does not contain docstrings for the wrapped code, check Apple's
documentation for details on how to use these functions and classes.
"""
def _setup():
import sys
import Foundation
import objc
from . import _metadata, _nsapp, _AppKit
from ._inlines import _inline_list_
dir_func, getattr_func = objc.createFrameworkDirAndGetattr(
name="AppKit",
frameworkIdentifier="com.apple.AppKit",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/AppKit.framework"
),
globals_dict=globals(),
inline_list=_inline_list_,
parents=(
_nsapp,
_AppKit,
Foundation,
),
metadict=_metadata.__dict__,
)
globals()["__dir__"] = dir_func
globals()["__getattr__"] = getattr_func
del sys.modules["AppKit._metadata"]
def fontdescriptor_get(self, key, default=None):
value = self.objectForKey_(key)
if value is None:
return default
return value
def fontdescriptor_getitem(self, key, default=None):
value = self.objectForKey_(key)
if value is None:
raise KeyError(key)
return value
objc.addConvenienceForClass(
"NSFontDescriptor",
(("__getitem__", fontdescriptor_getitem), ("get", fontdescriptor_get)),
)
# Fix types for a number of character constants
# XXX: Move this to metadata
globals_dict = globals()
for nm in [
"NSEnterCharacter",
"NSBackspaceCharacter",
"NSTabCharacter",
"NSNewlineCharacter",
"NSFormFeedCharacter",
"NSCarriageReturnCharacter",
"NSBackTabCharacter",
"NSDeleteCharacter",
"NSLineSeparatorCharacter",
"NSParagraphSeparatorCharacter",
"NSUpArrowFunctionKey",
"NSDownArrowFunctionKey",
"NSLeftArrowFunctionKey",
"NSRightArrowFunctionKey",
"NSF1FunctionKey",
"NSF2FunctionKey",
"NSF3FunctionKey",
"NSF4FunctionKey",
"NSF5FunctionKey",
"NSF6FunctionKey",
"NSF7FunctionKey",
"NSF8FunctionKey",
"NSF9FunctionKey",
"NSF10FunctionKey",
"NSF11FunctionKey",
"NSF12FunctionKey",
"NSF13FunctionKey",
"NSF14FunctionKey",
"NSF15FunctionKey",
"NSF16FunctionKey",
"NSF17FunctionKey",
"NSF18FunctionKey",
"NSF19FunctionKey",
"NSF20FunctionKey",
"NSF21FunctionKey",
"NSF22FunctionKey",
"NSF23FunctionKey",
"NSF24FunctionKey",
"NSF25FunctionKey",
"NSF26FunctionKey",
"NSF27FunctionKey",
"NSF28FunctionKey",
"NSF29FunctionKey",
"NSF30FunctionKey",
"NSF31FunctionKey",
"NSF32FunctionKey",
"NSF33FunctionKey",
"NSF34FunctionKey",
"NSF35FunctionKey",
"NSInsertFunctionKey",
"NSDeleteFunctionKey",
"NSHomeFunctionKey",
"NSBeginFunctionKey",
"NSEndFunctionKey",
"NSPageUpFunctionKey",
"NSPageDownFunctionKey",
"NSPrintScreenFunctionKey",
"NSScrollLockFunctionKey",
"NSPauseFunctionKey",
"NSSysReqFunctionKey",
"NSBreakFunctionKey",
"NSResetFunctionKey",
"NSStopFunctionKey",
"NSMenuFunctionKey",
"NSUserFunctionKey",
"NSSystemFunctionKey",
"NSPrintFunctionKey",
"NSClearLineFunctionKey",
"NSClearDisplayFunctionKey",
"NSInsertLineFunctionKey",
"NSDeleteLineFunctionKey",
"NSInsertCharFunctionKey",
"NSDeleteCharFunctionKey",
"NSPrevFunctionKey",
"NSNextFunctionKey",
"NSSelectFunctionKey",
"NSExecuteFunctionKey",
"NSUndoFunctionKey",
"NSRedoFunctionKey",
"NSFindFunctionKey",
"NSHelpFunctionKey",
"NSModeSwitchFunctionKey",
]:
try:
globals_dict[nm] = chr(__getattr__(nm)) # noqa: F821
except AttributeError:
pass
globals().pop("_setup")()
def NSDictionaryOfVariableBindings(*names):
"""
Return a dictionary with the given names and there values.
"""
import sys
variables = sys._getframe(1).f_locals
return {nm: variables[nm] for nm in names}

File diff suppressed because one or more lines are too long

View File

@ -1,29 +0,0 @@
import objc as _objc
import AppKit as _AppKit
class _NSApp:
"""
Helper class to emulate NSApp in Python.
"""
def __getrealapp(self):
d = {}
_objc.loadBundleVariables(_AppKit.__bundle__, d, [("NSApp", b"@")])
return d.get("NSApp")
__class__ = property(lambda self: self.__getrealapp().__class__)
def __getattr__(self, name):
return getattr(self.__getrealapp(), name)
def __setattr__(self, name, value):
return setattr(self.__getrealapp(), name, value)
def __call__(self):
# Compatibility with previous versions.
return self.__getrealapp()
NSApp = _NSApp()
del _NSApp

View File

@ -1,27 +0,0 @@
"""
Python mapping for the Cocoa framework.
This module does not contain docstrings for the wrapped code, check Apple's
documentation for details on how to use these functions and classes.
"""
def _setup():
import AppKit
import objc
dir_func, getattr_func = objc.createFrameworkDirAndGetattr(
name="Cocoa",
frameworkIdentifier=None,
frameworkPath=None,
globals_dict=globals(),
inline_list=None,
parents=(AppKit,),
metadict={},
)
globals()["__dir__"] = dir_func
globals()["__getattr__"] = getattr_func
globals().pop("_setup")()

View File

@ -1,37 +0,0 @@
"""
Python mapping for the CoreFoundation framework.
This module does not contain docstrings for the wrapped code, check Apple's
documentation for details on how to use these functions and classes.
"""
def _setup():
import sys
import objc
from . import _metadata, _CoreFoundation, _static
from ._inlines import _inline_list_
dir_func, getattr_func = objc.createFrameworkDirAndGetattr(
name="CoreFoundation",
frameworkIdentifier="com.apple.CoreFoundation",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/CoreFoundation.framework"
),
globals_dict=globals(),
inline_list=_inline_list_,
parents=(
_CoreFoundation,
_static,
),
metadict=_metadata.__dict__,
)
globals()["__dir__"] = dir_func
globals()["__getattr__"] = getattr_func
del sys.modules["CoreFoundation._metadata"]
globals().pop("_setup")()

File diff suppressed because one or more lines are too long

View File

@ -1,107 +0,0 @@
import CoreFoundation as _CF
import objc as _objc
#
# 'Emulation' for CFArray constructors
#
def _setup():
NSArray = _objc.lookUpClass("NSArray")
NSMutableArray = _objc.lookUpClass("NSMutableArray")
def CFArrayCreate(allocator, values, numvalues, callbacks):
assert callbacks is None
return NSArray.alloc().initWithArray_(values[:numvalues])
def CFArrayCreateMutable(allocator, capacity, callbacks):
assert callbacks is None
return NSMutableArray.alloc().init()
return CFArrayCreate, CFArrayCreateMutable
CFArrayCreate, CFArrayCreateMutable = _setup()
# CFDictionary emulation functions
def _setup():
NSDictionary = _objc.lookUpClass("NSDictionary")
NSMutableDictionary = _objc.lookUpClass("NSMutableDictionary")
def CFDictionaryCreate(
allocator, keys, values, numValues, keyCallbacks, valueCallbacks
):
assert keyCallbacks is None
assert valueCallbacks is None
keys = list(keys)[:numValues]
values = list(values)[:numValues]
return NSDictionary.dictionaryWithDictionary_(dict(zip(keys, values)))
def CFDictionaryCreateMutable(allocator, capacity, keyCallbacks, valueCallbacks):
assert keyCallbacks is None
assert valueCallbacks is None
return NSMutableDictionary.dictionary()
return CFDictionaryCreate, CFDictionaryCreateMutable
CFDictionaryCreate, CFDictionaryCreateMutable = _setup()
# CFSet emulation functions
def _setup():
NSSet = _objc.lookUpClass("NSSet")
NSMutableSet = _objc.lookUpClass("NSMutableSet")
def CFSetCreate(allocator, values, numvalues, callbacks):
assert callbacks is None
return NSSet.alloc().initWithArray_(values[:numvalues])
def CFSetCreateMutable(allocator, capacity, callbacks):
assert callbacks is None
return NSMutableSet.alloc().init()
return CFSetCreate, CFSetCreateMutable
CFSetCreate, CFSetCreateMutable = _setup()
kCFTypeArrayCallBacks = None
kCFTypeDictionaryKeyCallBacks = None
kCFTypeDictionaryValueCallBacks = None
kCFTypeSetCallBacks = None
#
# Implementation of a number of macro's in the CFBundle API
#
def CFCopyLocalizedString(key, comment):
return _CF.CFBundleCopyLocalizedString(
_CF.CFBundleGetMainBundle(), (key), (key), None
)
def CFCopyLocalizedStringFromTable(key, tbl, comment):
return _CF.CFBundleCopyLocalizedString(
_CF.CFBundleGetMainBundle(), (key), (key), (tbl)
)
def CFCopyLocalizedStringFromTableInBundle(key, tbl, bundle, comment):
return _CF.CFBundleCopyLocalizedString((bundle), (key), (key), (tbl))
def CFCopyLocalizedStringWithDefaultValue(key, tbl, bundle, value, comment):
return _CF.CFBundleCopyLocalizedString((bundle), (key), (value), (tbl))
def CFSTR(strval):
return _objc.lookUpClass("NSString").stringWithString_(strval)

View File

@ -1,196 +0,0 @@
"""
Python mapping for the Foundation framework.
This module does not contain docstrings for the wrapped code, check Apple's
documentation for details on how to use these functions and classes.
"""
def _setup():
import sys
import CoreFoundation
import objc
from . import _Foundation, _metadata, _functiondefines, _context
from ._inlines import _inline_list_
dir_func, getattr_func = objc.createFrameworkDirAndGetattr(
name="Foundation",
frameworkIdentifier="com.apple.Foundation",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/Foundation.framework"
),
globals_dict=globals(),
inline_list=_inline_list_,
parents=(
_Foundation,
_functiondefines,
_context,
CoreFoundation,
),
metadict=_metadata.__dict__,
)
globals()["__dir__"] = dir_func
globals()["__getattr__"] = getattr_func
del sys.modules["Foundation._metadata"]
objc.addConvenienceForClass(
"NSAttributedString", (("__len__", lambda self: self.length()),)
)
objc.addConvenienceForBasicMapping("NSMergeConflict", True)
objc.addConvenienceForBasicMapping("NSUbiquitousKeyValueStore", False)
objc.addConvenienceForBasicMapping("NSUserDefaults", False)
NSNull = objc.lookUpClass("NSNull")
def nscache_getitem(self, key):
value = self.objectForKey_(key)
if value is None:
raise KeyError(key)
elif value is NSNull.null():
return None
else:
return value
def nscache_get(self, key, default=None):
value = self.objectForKey_(key)
if value is None:
return default
elif value is NSNull.null():
return None
return value
def nscache_setitem(self, key, value):
if value is None:
value = NSNull.null()
self.setObject_forKey_(value, key)
objc.addConvenienceForClass(
"NSCache",
(
("__getitem__", nscache_getitem),
("get", nscache_get),
("__setitem__", nscache_setitem),
("__delitem__", lambda self, key: self.removeObjectForKey_(key)),
("clear", lambda self: self.removeAllObjects()),
),
)
def hash_add(self, value):
if value is None:
value = NSNull.null()
self.addObject_(value)
def hash_contains(self, value):
if value is None:
value = NSNull.null()
return self.containsObject_(value)
def hash_remove(self, value):
if value is None:
value = NSNull.null()
self.removeObject_(value)
def hash_pop(self):
value = self.anyObject()
self.removeObject_(value)
if value is NSNull.null():
return None
else:
return value
objc.addConvenienceForClass(
"NSHashTable",
(
("__len__", lambda self: self.count()),
("clear", lambda self: self.removeAllObjects()),
("__iter__", lambda self: iter(self.objectEnumerator())),
("add", hash_add),
("remove", hash_remove),
("__contains__", hash_contains),
("pop", hash_pop),
),
)
objc.addConvenienceForClass(
"NSIndexPath", (("__len__", lambda self: self.count()),)
)
if sys.maxsize > 2**32:
NSNotFound = 0x7FFFFFFFFFFFFFFF
else:
NSNotFound = 0x7FFFFFFF
def indexset_iter(self):
value = self.firstIndex()
while value != NSNotFound:
yield value
value = self.indexGreaterThanIndex_(value)
def indexset_reversed(self):
value = self.lastIndex()
while value != NSNotFound:
yield value
value = self.indexLessThanIndex_(value)
NSIndexSet = objc.lookUpClass("NSIndexSet")
def indexset_eq(self, other):
if not isinstance(other, NSIndexSet):
return False
return self.isEqualToIndexSet_(other)
def indexset_ne(self, other):
if not isinstance(other, NSIndexSet):
return True
return not self.isEqualToIndexSet_(other)
def indexset_contains(self, value):
try:
return self.containsIndex_(value)
except ValueError:
return False
objc.addConvenienceForClass(
"NSIndexSet",
(
("__len__", lambda self: self.count()),
("__iter__", indexset_iter),
("__reversed__", indexset_reversed),
("__eq__", indexset_eq),
("__ne__", indexset_ne),
("__contains__", indexset_contains),
),
)
# Add 'update', '-=', '+='
objc.addConvenienceForClass(
"NSMutableIndexSet",
(
("clear", lambda self: self.removeAllIndexes()),
("add", lambda self, value: self.addIndex_(value)),
("remove", lambda self, value: self.removeIndex_(value)),
),
)
objc.addConvenienceForClass(
"NSLocale", (("__getitem__", lambda self, key: self.objectForKey_(key)),)
)
globals().pop("_setup")()
from objc import NSDecimal, YES, NO # isort:skip # noqa: E402, F401
import Foundation._context # isort:skip # noqa: E402
import Foundation._functiondefines # isort:skip # noqa: E402
import Foundation._nsindexset # isort:skip # noqa: E402
import Foundation._nsobject # isort:skip # noqa: E402, F401
import Foundation._nsurl # isort:skip # noqa: E402, F401

View File

@ -1,26 +0,0 @@
import Foundation
class NSDisabledAutomaticTermination:
def __init__(self, reason):
self._reason = reason
self._info = Foundation.NSProcessInfo.processInfo()
def __enter__(self):
self._info.disableAutomaticTermination_(self._reason)
def __exit__(self, exc_type, exc_val, exc_tb):
self._info.enableAutomaticTermination_(self._reason)
return False
class NSDisabledSuddenTermination:
def __init__(self):
self._info = Foundation.NSProcessInfo.processInfo()
def __enter__(self):
self._info.disableSuddenTermination()
def __exit__(self, exc_type, exc_val, exc_tb):
self._info.enableSuddenTermination()
return False

View File

@ -1,63 +0,0 @@
"""
Port of "function defines".
"""
import Foundation as _Foundation
def NSLocalizedString(key, comment):
return _Foundation.NSBundle.mainBundle().localizedStringForKey_value_table_(
key, "", None
)
def NSLocalizedStringFromTable(key, tbl, comment):
return _Foundation.NSBundle.mainBundle().localizedStringForKey_value_table_(
key, "", tbl
)
def NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment):
return bundle.localizedStringForKey_value_table_(key, "", tbl)
def NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment):
return bundle.localizedStringForKey_value_table_(key, val, tbl)
def NSLocalizedAttributedString(key, comment):
return (
_Foundation.NSBundle.mainBundle().localizedAttributedStringForKey_value_table_(
key, "", None
)
)
def NSLocalizedAttributedStringFromTable(key, tbl, comment):
return _Foundation.NSBundle.mainBundle.localizedAttributedStringForKey_value_table_(
key, "", tbl
)
def NSLocalizedAttributedStringFromTableInBundle(key, tbl, bundle, comment):
return bundle.localizedAttributedStringForKey_value_table_(key, "", tbl)
def NSLocalizedAttributedStringWithDefaultValue(key, tbl, bundle, val, comment):
return bundle.localizedAttributedStringForKey_value_table_(key, val, tbl)
def MIN(a, b):
if a < b:
return a
else:
return b
def MAX(a, b):
if a < b:
return b
else:
return a
ABS = abs

File diff suppressed because one or more lines are too long

View File

@ -1,21 +0,0 @@
import objc
def __len__(self):
return self.length()
def __getitem__(self, idx):
if isinstance(idx, slice):
raise ValueError(idx)
return self.indexAtPosition_(idx)
def __add__(self, value):
return self.indexPathByAddingIndex_(value)
objc.addConvenienceForClass(
"NSIndexPath",
(("__len__", __len__), ("__getitem__", __getitem__), ("__add__", __add__)),
)

View File

@ -1,235 +0,0 @@
"""
Define a category on NSObject with some useful methods.
"""
import sys
import objc
if sys.version_info[0] == 2:
def _str(v):
return v
exec(
"""\
def _raise(exc_type, exc_value, exc_trace):
raise exc_type, exc_value, exc_trace
"""
)
else:
def _str(v):
if isinstance(v, str):
return v
return v.decode("ascii")
def _raise(exc_type, exc_value, exc_trace):
raise exc_type(exc_value).with_traceback(exc_trace)
NSObject = objc.lookUpClass("NSObject")
class NSObject(objc.Category(NSObject)):
@objc.namedSelector(b"_pyobjc_performOnThread:")
def _pyobjc_performOnThread_(self, callinfo):
try:
sel, arg = callinfo
m = getattr(self, _str(sel))
m(arg)
except: # noqa: E722, B001
import traceback
traceback.print_exc(file=sys.stderr)
@objc.namedSelector(b"_pyobjc_performOnThreadWithResult:")
def _pyobjc_performOnThreadWithResult_(self, callinfo):
try:
sel, arg, result = callinfo
m = getattr(self, _str(sel))
r = m(arg)
result.append((True, r))
except: # noqa: E722, B001
result.append((False, sys.exc_info()))
if hasattr(NSObject, "performSelector_onThread_withObject_waitUntilDone_"):
@objc.namedSelector(
b"pyobjc_performSelector:onThread:withObject:waitUntilDone:"
)
def pyobjc_performSelector_onThread_withObject_waitUntilDone_(
self, aSelector, thread, arg, wait
):
"""
A version of performSelector:onThread:withObject:waitUntilDone: that
will log exceptions in the called method (instead of aborting the
NSRunLoop on the other thread).
"""
self.performSelector_onThread_withObject_waitUntilDone_(
b"_pyobjc_performOnThread:", thread, (aSelector, arg), wait
)
@objc.namedSelector(
b"pyobjc_performSelector:onThread:withObject:waitUntilDone:modes:"
)
def pyobjc_performSelector_onThread_withObject_waitUntilDone_modes_(
self, aSelector, thread, arg, wait, modes
):
"""
A version of performSelector:onThread:withObject:waitUntilDone:modes:
that will log exceptions in the called method (instead of aborting the
NSRunLoop on the other thread).
"""
self.performSelector_onThread_withObject_waitUntilDone_modes_(
b"_pyobjc_performOnThread:", thread, (aSelector, arg), wait, modes
)
@objc.namedSelector(b"pyobjc_performSelector:withObject:afterDelay:")
def pyobjc_performSelector_withObject_afterDelay_(self, aSelector, arg, delay):
"""
A version of performSelector:withObject:afterDelay:
that will log exceptions in the called method (instead of aborting the
NSRunLoop).
"""
self.performSelector_withObject_afterDelay_(
b"_pyobjc_performOnThread:", (aSelector, arg), delay
)
@objc.namedSelector(b"pyobjc_performSelector:withObject:afterDelay:inModes:")
def pyobjc_performSelector_withObject_afterDelay_inModes_(
self, aSelector, arg, delay, modes
):
"""
A version of performSelector:withObject:afterDelay:inModes:
that will log exceptions in the called method (instead of aborting the
NSRunLoop).
"""
self.performSelector_withObject_afterDelay_inModes_(
b"_pyobjc_performOnThread:", (aSelector, arg), delay, modes
)
if hasattr(NSObject, "performSelectorInBackground_withObject_"):
@objc.namedSelector(b"pyobjc_performSelectorInBackground:withObject:")
def pyobjc_performSelectorInBackground_withObject_(self, aSelector, arg):
"""
A version of performSelectorInBackground:withObject:
that will log exceptions in the called method (instead of aborting the
NSRunLoop).
"""
self.performSelectorInBackground_withObject_(
b"_pyobjc_performOnThread:", (aSelector, arg)
)
@objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:waitUntilDone:")
def pyobjc_performSelectorOnMainThread_withObject_waitUntilDone_(
self, aSelector, arg, wait
):
"""
A version of performSelectorOnMainThread:withObject:waitUntilDone:
that will log exceptions in the called method (instead of aborting the
NSRunLoop in the main thread).
"""
self.performSelectorOnMainThread_withObject_waitUntilDone_(
b"_pyobjc_performOnThread:", (aSelector, arg), wait
)
@objc.namedSelector(
b"pyobjc_performSelectorOnMainThread:withObject:waitUntilDone:modes:"
)
def pyobjc_performSelectorOnMainThread_withObject_waitUntilDone_modes_(
self, aSelector, arg, wait, modes
):
"""
A version of performSelectorOnMainThread:withObject:waitUntilDone:modes:
that will log exceptions in the called method (instead of aborting the
NSRunLoop in the main thread).
"""
self.performSelectorOnMainThread_withObject_waitUntilDone_modes_(
b"_pyobjc_performOnThread:", (aSelector, arg), wait, modes
)
# And some a some versions that return results
@objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:modes:")
def pyobjc_performSelectorOnMainThread_withObject_modes_(
self, aSelector, arg, modes
):
"""
Simular to performSelectorOnMainThread:withObject:waitUntilDone:modes:,
but:
- always waits until done
- returns the return value of the called method
- if the called method raises an exception, this will raise the same
exception
"""
result = []
self.performSelectorOnMainThread_withObject_waitUntilDone_modes_(
b"_pyobjc_performOnThreadWithResult:", (aSelector, arg, result), True, modes
)
isOK, result = result[0]
if isOK:
return result
else:
exc_type, exc_value, exc_trace = result
_raise(exc_type, exc_value, exc_trace)
@objc.namedSelector(b"pyobjc_performSelectorOnMainThread:withObject:")
def pyobjc_performSelectorOnMainThread_withObject_(self, aSelector, arg):
result = []
self.performSelectorOnMainThread_withObject_waitUntilDone_(
b"_pyobjc_performOnThreadWithResult:", (aSelector, arg, result), True
)
isOK, result = result[0]
if isOK:
return result
else:
exc_type, exc_value, exc_trace = result
_raise(exc_type, exc_value, exc_trace)
if hasattr(NSObject, "performSelector_onThread_withObject_waitUntilDone_"):
# These methods require Leopard, don't define them if the
# platform functionality isn't present.
@objc.namedSelector(b"pyobjc_performSelector:onThread:withObject:modes:")
def pyobjc_performSelector_onThread_withObject_modes_(
self, aSelector, thread, arg, modes
):
result = []
self.performSelector_onThread_withObject_waitUntilDone_modes_(
b"_pyobjc_performOnThreadWithResult:",
thread,
(aSelector, arg, result),
True,
modes,
)
isOK, result = result[0]
if isOK:
return result
else:
exc_type, exc_value, exc_trace = result
_raise(exc_type, exc_value, exc_trace)
@objc.namedSelector(b"pyobjc_performSelector:onThread:withObject:")
def pyobjc_performSelector_onThread_withObject_(self, aSelector, thread, arg):
result = []
self.performSelector_onThread_withObject_waitUntilDone_(
b"_pyobjc_performOnThreadWithResult:",
thread,
(aSelector, arg, result),
True,
)
isOK, result = result[0]
if isOK:
return result
else:
exc_type, exc_value, exc_trace = result
_raise(exc_type, exc_value, exc_trace)
del NSObject

View File

@ -1,23 +0,0 @@
"""
Helpers for NSURL
"""
import sys
import objc
def __fspath__(self):
if self.scheme() == "file":
# self.fileSystemRepresentation returns a byte string,
# whereas most user code expects regular strings. Decode
# in the same way as extension functions in the ``os`` module.
return self.fileSystemRepresentation().decode(
sys.getfilesystemencoding(), sys.getfilesystemencodeerrors()
)
raise TypeError(f"NSURL with scheme {self.scheme()!r} instead of 'file'")
objc.addConvenienceForClass(
"NSURL",
(("__fspath__", __fspath__),),
)

View File

@ -1,28 +0,0 @@
Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,92 +0,0 @@
Metadata-Version: 2.1
Name: MarkupSafe
Version: 3.0.2
Summary: Safely add untrusted strings to HTML/XML markup.
Maintainer-email: Pallets <contact@palletsprojects.com>
License: Copyright 2010 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Documentation, https://markupsafe.palletsprojects.com/
Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/
Project-URL: Source, https://github.com/pallets/markupsafe/
Project-URL: Chat, https://discord.gg/pallets
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Text Processing :: Markup :: HTML
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.txt
# MarkupSafe
MarkupSafe implements a text object that escapes characters so it is
safe to use in HTML and XML. Characters that have special meanings are
replaced so that they display as the actual characters. This mitigates
injection attacks, meaning untrusted user input can safely be displayed
on a page.
## Examples
```pycon
>>> from markupsafe import Markup, escape
>>> # escape replaces special characters and wraps in Markup
>>> escape("<script>alert(document.cookie);</script>")
Markup('&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
>>> # wrap in Markup to mark text "safe" and prevent escaping
>>> Markup("<strong>Hello</strong>")
Markup('<strong>hello</strong>')
>>> escape(Markup("<strong>Hello</strong>"))
Markup('<strong>hello</strong>')
>>> # Markup is a str subclass
>>> # methods and operators escape their arguments
>>> template = Markup("Hello <em>{name}</em>")
>>> template.format(name='"World"')
Markup('Hello <em>&#34;World&#34;</em>')
```
## Donate
The Pallets organization develops and supports MarkupSafe and other
popular packages. In order to grow the community of contributors and
users, and allow the maintainers to devote more time to the projects,
[please donate today][].
[please donate today]: https://palletsprojects.com/donate

View File

@ -1,14 +0,0 @@
MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
MarkupSafe-3.0.2.dist-info/METADATA,sha256=aAwbZhSmXdfFuMM-rEHpeiHRkBOGESyVLJIuwzHP-nw,3975
MarkupSafe-3.0.2.dist-info/RECORD,,
MarkupSafe-3.0.2.dist-info/WHEEL,sha256=lXrF9eVJm7UF3ZOBaBu2Y-RekBGubHbC1Bvbd4BEjAQ,109
MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
markupsafe/__init__.py,sha256=sr-U6_27DfaSrj5jnHYxWN-pvhM27sjlDplMDPZKm7k,13214
markupsafe/__pycache__/__init__.cpython-310.pyc,,
markupsafe/__pycache__/_native.cpython-310.pyc,,
markupsafe/_native.py,sha256=hSLs8Jmz5aqayuengJJ3kdT5PwNpBWpKrmQSdipndC8,210
markupsafe/_speedups.c,sha256=O7XulmTo-epI6n2FtMVOrJXl8EAaIwD2iNYmBI5SEoQ,4149
markupsafe/_speedups.cpython-310-darwin.so,sha256=3f9Fj2FHr4Ue7g2ODjkMpKlhPZCbjE0h7ZPvY4L8aUs,50688
markupsafe/_speedups.pyi,sha256=ENd1bYe7gbBUf2ywyYWOGUpnXOHNJ-cgTNqetlW8h5k,41
markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (75.2.0)
Root-Is-Purelib: false
Tag: cp310-cp310-macosx_11_0_arm64

View File

@ -1,63 +0,0 @@
Metadata-Version: 2.1
Name: MouseInfo
Version: 0.1.3
Summary: An application to display XY position and RGB color information for the pixel currently under the mouse. Works on Python 2 and 3.
Home-page: https://github.com/asweigart/mouseinfo
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: GPLv3+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Description-Content-Type: text/markdown
MouseInfo
======
An application to display XY position and RGB color information for the pixel currently under the mouse. Works on Python 2 and 3. This is useful for GUI automation planning.
The full documentation is at https://mouseinfo.readthedocs.io/en/latest/
Installation
------------
To install with pip, run:
pip install mouseinfo
Quickstart Guide
----------------
To run this application, enter the following into the terminal:
python3 -m mouseinfo
Or for Python 2, run:
python -m mouseinfo
Alternatively, to run it from the interactive shell or a Python program:
>>> import mouseinfo
>>> mouseinfo.mouseInfo()
The Mouse Info application displays the current XY coordinates of the mouse cursor, as well as the RGB color information of the pixel directly under the cursor. This can be useful for planning out GUI automation tests where the mouse is controlled by a script (such as a Python script with PyAutoGUI) to click on the screen at specific coordinates.
The "Copy" buttons will copy this mouse information to the clipboard, while the "Log" buttons will add this mouse information to the text field in the application. The RGB color information is given as a comman-delimited, three-integer red, green, and blue values as decimals from 0 to 255. The hex values of the RGB value is also given.
For practical use, you should set the keyboard focus on these buttons by tabbing over them. This leaves you free to move the mouse into position and then press space or Enter to log the current mouse coordinates/RGB value.
The contents of the log text field can be saved by clicking "Save Log". This will automatically overwrite any file with the provided name. A screenshot can also be saved by clicking "Save Screenshot"
Contribute
----------
If you'd like to contribute to MouseInfo, check out https://github.com/asweigart/mouseinfo

View File

@ -1,11 +0,0 @@
MANIFEST.in
README.md
setup.cfg
setup.py
src/MouseInfo.egg-info/PKG-INFO
src/MouseInfo.egg-info/SOURCES.txt
src/MouseInfo.egg-info/dependency_links.txt
src/MouseInfo.egg-info/requires.txt
src/MouseInfo.egg-info/top_level.txt
src/mouseinfo/__init__.py
src/mouseinfo/__main__.py

View File

@ -1,9 +0,0 @@
../mouseinfo/__init__.py
../mouseinfo/__main__.py
../mouseinfo/__pycache__/__init__.cpython-310.pyc
../mouseinfo/__pycache__/__main__.cpython-310.pyc
PKG-INFO
SOURCES.txt
dependency_links.txt
requires.txt
top_level.txt

View File

@ -1,31 +0,0 @@
pyperclip
[:platform_system == "Darwin"]
rubicon-objc
[:platform_system == "Linux" and python_version < "3.0"]
Xlib
[:platform_system == "Linux" and python_version >= "3.0"]
python3-Xlib
[:python_version == "2.7"]
Pillow>=2.0.0
[:python_version == "3.2"]
Pillow<=3.4.2,>=2.0.0
[:python_version == "3.3"]
Pillow<=4.3.0,>=2.0.0
[:python_version == "3.4"]
Pillow<=5.4.1,>=2.5.0
[:python_version == "3.5"]
Pillow>=3.2.0
[:python_version == "3.6"]
Pillow>=4.0.0
[:python_version == "3.7"]
Pillow>=5.2.0

View File

@ -1,291 +0,0 @@
from __future__ import annotations
import os
from io import BytesIO
from typing import IO
from . import ExifTags, Image, ImageFile
try:
from . import _avif
SUPPORTED = True
except ImportError:
SUPPORTED = False
# Decoder options as module globals, until there is a way to pass parameters
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
DECODE_CODEC_CHOICE = "auto"
DEFAULT_MAX_THREADS = 0
def get_codec_version(codec_name: str) -> str | None:
versions = _avif.codec_versions()
for version in versions.split(", "):
if version.split(" [")[0] == codec_name:
return version.split(":")[-1].split(" ")[0]
return None
def _accept(prefix: bytes) -> bool | str:
if prefix[4:8] != b"ftyp":
return False
major_brand = prefix[8:12]
if major_brand in (
# coding brands
b"avif",
b"avis",
# We accept files with AVIF container brands; we can't yet know if
# the ftyp box has the correct compatible brands, but if it doesn't
# then the plugin will raise a SyntaxError which Pillow will catch
# before moving on to the next plugin that accepts the file.
#
# Also, because this file might not actually be an AVIF file, we
# don't raise an error if AVIF support isn't properly compiled.
b"mif1",
b"msf1",
):
if not SUPPORTED:
return (
"image file could not be identified because AVIF support not installed"
)
return True
return False
def _get_default_max_threads() -> int:
if DEFAULT_MAX_THREADS:
return DEFAULT_MAX_THREADS
if hasattr(os, "sched_getaffinity"):
return len(os.sched_getaffinity(0))
else:
return os.cpu_count() or 1
class AvifImageFile(ImageFile.ImageFile):
format = "AVIF"
format_description = "AVIF image"
__frame = -1
def _open(self) -> None:
if not SUPPORTED:
msg = "image file could not be opened because AVIF support not installed"
raise SyntaxError(msg)
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
DECODE_CODEC_CHOICE
):
msg = "Invalid opening codec"
raise ValueError(msg)
self._decoder = _avif.AvifDecoder(
self.fp.read(),
DECODE_CODEC_CHOICE,
_get_default_max_threads(),
)
# Get info from decoder
self._size, self.n_frames, self._mode, icc, exif, exif_orientation, xmp = (
self._decoder.get_info()
)
self.is_animated = self.n_frames > 1
if icc:
self.info["icc_profile"] = icc
if xmp:
self.info["xmp"] = xmp
if exif_orientation != 1 or exif:
exif_data = Image.Exif()
if exif:
exif_data.load(exif)
original_orientation = exif_data.get(ExifTags.Base.Orientation, 1)
else:
original_orientation = 1
if exif_orientation != original_orientation:
exif_data[ExifTags.Base.Orientation] = exif_orientation
exif = exif_data.tobytes()
if exif:
self.info["exif"] = exif
self.seek(0)
def seek(self, frame: int) -> None:
if not self._seek_check(frame):
return
# Set tile
self.__frame = frame
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)]
def load(self) -> Image.core.PixelAccess | None:
if self.tile:
# We need to load the image data for this frame
data, timescale, pts_in_timescales, duration_in_timescales = (
self._decoder.get_frame(self.__frame)
)
self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale))
self.info["duration"] = round(1000 * (duration_in_timescales / timescale))
if self.fp and self._exclusive_fp:
self.fp.close()
self.fp = BytesIO(data)
return super().load()
def load_seek(self, pos: int) -> None:
pass
def tell(self) -> int:
return self.__frame
def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
_save(im, fp, filename, save_all=True)
def _save(
im: Image.Image, fp: IO[bytes], filename: str | bytes, save_all: bool = False
) -> None:
info = im.encoderinfo.copy()
if save_all:
append_images = list(info.get("append_images", []))
else:
append_images = []
total = 0
for ims in [im] + append_images:
total += getattr(ims, "n_frames", 1)
quality = info.get("quality", 75)
if not isinstance(quality, int) or quality < 0 or quality > 100:
msg = "Invalid quality setting"
raise ValueError(msg)
duration = info.get("duration", 0)
subsampling = info.get("subsampling", "4:2:0")
speed = info.get("speed", 6)
max_threads = info.get("max_threads", _get_default_max_threads())
codec = info.get("codec", "auto")
if codec != "auto" and not _avif.encoder_codec_available(codec):
msg = "Invalid saving codec"
raise ValueError(msg)
range_ = info.get("range", "full")
tile_rows_log2 = info.get("tile_rows", 0)
tile_cols_log2 = info.get("tile_cols", 0)
alpha_premultiplied = bool(info.get("alpha_premultiplied", False))
autotiling = bool(info.get("autotiling", tile_rows_log2 == tile_cols_log2 == 0))
icc_profile = info.get("icc_profile", im.info.get("icc_profile"))
exif_orientation = 1
if exif := info.get("exif"):
if isinstance(exif, Image.Exif):
exif_data = exif
else:
exif_data = Image.Exif()
exif_data.load(exif)
if ExifTags.Base.Orientation in exif_data:
exif_orientation = exif_data.pop(ExifTags.Base.Orientation)
exif = exif_data.tobytes() if exif_data else b""
elif isinstance(exif, Image.Exif):
exif = exif_data.tobytes()
xmp = info.get("xmp")
if isinstance(xmp, str):
xmp = xmp.encode("utf-8")
advanced = info.get("advanced")
if advanced is not None:
if isinstance(advanced, dict):
advanced = advanced.items()
try:
advanced = tuple(advanced)
except TypeError:
invalid = True
else:
invalid = any(not isinstance(v, tuple) or len(v) != 2 for v in advanced)
if invalid:
msg = (
"advanced codec options must be a dict of key-value string "
"pairs or a series of key-value two-tuples"
)
raise ValueError(msg)
# Setup the AVIF encoder
enc = _avif.AvifEncoder(
im.size,
subsampling,
quality,
speed,
max_threads,
codec,
range_,
tile_rows_log2,
tile_cols_log2,
alpha_premultiplied,
autotiling,
icc_profile or b"",
exif or b"",
exif_orientation,
xmp or b"",
advanced,
)
# Add each frame
frame_idx = 0
frame_duration = 0
cur_idx = im.tell()
is_single_frame = total == 1
try:
for ims in [im] + append_images:
# Get number of frames in this image
nfr = getattr(ims, "n_frames", 1)
for idx in range(nfr):
ims.seek(idx)
# Make sure image mode is supported
frame = ims
rawmode = ims.mode
if ims.mode not in {"RGB", "RGBA"}:
rawmode = "RGBA" if ims.has_transparency_data else "RGB"
frame = ims.convert(rawmode)
# Update frame duration
if isinstance(duration, (list, tuple)):
frame_duration = duration[frame_idx]
else:
frame_duration = duration
# Append the frame to the animation encoder
enc.add(
frame.tobytes("raw", rawmode),
frame_duration,
frame.size,
rawmode,
is_single_frame,
)
# Update frame index
frame_idx += 1
if not save_all:
break
finally:
im.seek(cur_idx)
# Get the final output from the encoder
data = enc.finish()
if data is None:
msg = "cannot write file as AVIF (encoder returned None)"
raise OSError(msg)
fp.write(data)
Image.register_open(AvifImageFile.format, AvifImageFile, _accept)
if SUPPORTED:
Image.register_save(AvifImageFile.format, _save)
Image.register_save_all(AvifImageFile.format, _save_all)
Image.register_extensions(AvifImageFile.format, [".avif", ".avifs"])
Image.register_mime(AvifImageFile.format, "image/avif")

View File

@ -1,122 +0,0 @@
#
# The Python Imaging Library
# $Id$
#
# bitmap distribution font (bdf) file parser
#
# history:
# 1996-05-16 fl created (as bdf2pil)
# 1997-08-25 fl converted to FontFile driver
# 2001-05-25 fl removed bogus __init__ call
# 2002-11-20 fl robustification (from Kevin Cazabon, Dmitry Vasiliev)
# 2003-04-22 fl more robustification (from Graham Dumpleton)
#
# Copyright (c) 1997-2003 by Secret Labs AB.
# Copyright (c) 1997-2003 by Fredrik Lundh.
#
# See the README file for information on usage and redistribution.
#
"""
Parse X Bitmap Distribution Format (BDF)
"""
from __future__ import annotations
from typing import BinaryIO
from . import FontFile, Image
def bdf_char(
f: BinaryIO,
) -> (
tuple[
str,
int,
tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]],
Image.Image,
]
| None
):
# skip to STARTCHAR
while True:
s = f.readline()
if not s:
return None
if s.startswith(b"STARTCHAR"):
break
id = s[9:].strip().decode("ascii")
# load symbol properties
props = {}
while True:
s = f.readline()
if not s or s.startswith(b"BITMAP"):
break
i = s.find(b" ")
props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
# load bitmap
bitmap = bytearray()
while True:
s = f.readline()
if not s or s.startswith(b"ENDCHAR"):
break
bitmap += s[:-1]
# The word BBX
# followed by the width in x (BBw), height in y (BBh),
# and x and y displacement (BBxoff0, BByoff0)
# of the lower left corner from the origin of the character.
width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split())
# The word DWIDTH
# followed by the width in x and y of the character in device pixels.
dwx, dwy = (int(p) for p in props["DWIDTH"].split())
bbox = (
(dwx, dwy),
(x_disp, -y_disp - height, width + x_disp, -y_disp),
(0, 0, width, height),
)
try:
im = Image.frombytes("1", (width, height), bitmap, "hex", "1")
except ValueError:
# deal with zero-width characters
im = Image.new("1", (width, height))
return id, int(props["ENCODING"]), bbox, im
class BdfFontFile(FontFile.FontFile):
"""Font file plugin for the X11 BDF format."""
def __init__(self, fp: BinaryIO) -> None:
super().__init__()
s = fp.readline()
if not s.startswith(b"STARTFONT 2.1"):
msg = "not a valid BDF file"
raise SyntaxError(msg)
props = {}
comments = []
while True:
s = fp.readline()
if not s or s.startswith(b"ENDPROPERTIES"):
break
i = s.find(b" ")
props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
if s.find(b"LogicalFontDescription") < 0:
comments.append(s[i + 1 : -1].decode("ascii"))
while True:
c = bdf_char(fp)
if not c:
break
id, ch, (xy, dst, src), im = c
if 0 <= ch < len(self.glyph):
self.glyph[ch] = xy, dst, src, im

View File

@ -1,497 +0,0 @@
"""
Blizzard Mipmap Format (.blp)
Jerome Leclanche <jerome@leclan.ch>
The contents of this file are hereby released in the public domain (CC0)
Full text of the CC0 license:
https://creativecommons.org/publicdomain/zero/1.0/
BLP1 files, used mostly in Warcraft III, are not fully supported.
All types of BLP2 files used in World of Warcraft are supported.
The BLP file structure consists of a header, up to 16 mipmaps of the
texture
Texture sizes must be powers of two, though the two dimensions do
not have to be equal; 512x256 is valid, but 512x200 is not.
The first mipmap (mipmap #0) is the full size image; each subsequent
mipmap halves both dimensions. The final mipmap should be 1x1.
BLP files come in many different flavours:
* JPEG-compressed (type == 0) - only supported for BLP1.
* RAW images (type == 1, encoding == 1). Each mipmap is stored as an
array of 8-bit values, one per pixel, left to right, top to bottom.
Each value is an index to the palette.
* DXT-compressed (type == 1, encoding == 2):
- DXT1 compression is used if alpha_encoding == 0.
- An additional alpha bit is used if alpha_depth == 1.
- DXT3 compression is used if alpha_encoding == 1.
- DXT5 compression is used if alpha_encoding == 7.
"""
from __future__ import annotations
import abc
import os
import struct
from enum import IntEnum
from io import BytesIO
from typing import IO
from . import Image, ImageFile
class Format(IntEnum):
JPEG = 0
class Encoding(IntEnum):
UNCOMPRESSED = 1
DXT = 2
UNCOMPRESSED_RAW_BGRA = 3
class AlphaEncoding(IntEnum):
DXT1 = 0
DXT3 = 1
DXT5 = 7
def unpack_565(i: int) -> tuple[int, int, int]:
return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3
def decode_dxt1(
data: bytes, alpha: bool = False
) -> tuple[bytearray, bytearray, bytearray, bytearray]:
"""
input: one "row" of data (i.e. will produce 4*width pixels)
"""
blocks = len(data) // 8 # number of blocks in row
ret = (bytearray(), bytearray(), bytearray(), bytearray())
for block_index in range(blocks):
# Decode next 8-byte block.
idx = block_index * 8
color0, color1, bits = struct.unpack_from("<HHI", data, idx)
r0, g0, b0 = unpack_565(color0)
r1, g1, b1 = unpack_565(color1)
# Decode this block into 4x4 pixels
# Accumulate the results onto our 4 row accumulators
for j in range(4):
for i in range(4):
# get next control op and generate a pixel
control = bits & 3
bits = bits >> 2
a = 0xFF
if control == 0:
r, g, b = r0, g0, b0
elif control == 1:
r, g, b = r1, g1, b1
elif control == 2:
if color0 > color1:
r = (2 * r0 + r1) // 3
g = (2 * g0 + g1) // 3
b = (2 * b0 + b1) // 3
else:
r = (r0 + r1) // 2
g = (g0 + g1) // 2
b = (b0 + b1) // 2
elif control == 3:
if color0 > color1:
r = (2 * r1 + r0) // 3
g = (2 * g1 + g0) // 3
b = (2 * b1 + b0) // 3
else:
r, g, b, a = 0, 0, 0, 0
if alpha:
ret[j].extend([r, g, b, a])
else:
ret[j].extend([r, g, b])
return ret
def decode_dxt3(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]:
"""
input: one "row" of data (i.e. will produce 4*width pixels)
"""
blocks = len(data) // 16 # number of blocks in row
ret = (bytearray(), bytearray(), bytearray(), bytearray())
for block_index in range(blocks):
idx = block_index * 16
block = data[idx : idx + 16]
# Decode next 16-byte block.
bits = struct.unpack_from("<8B", block)
color0, color1 = struct.unpack_from("<HH", block, 8)
(code,) = struct.unpack_from("<I", block, 12)
r0, g0, b0 = unpack_565(color0)
r1, g1, b1 = unpack_565(color1)
for j in range(4):
high = False # Do we want the higher bits?
for i in range(4):
alphacode_index = (4 * j + i) // 2
a = bits[alphacode_index]
if high:
high = False
a >>= 4
else:
high = True
a &= 0xF
a *= 17 # We get a value between 0 and 15
color_code = (code >> 2 * (4 * j + i)) & 0x03
if color_code == 0:
r, g, b = r0, g0, b0
elif color_code == 1:
r, g, b = r1, g1, b1
elif color_code == 2:
r = (2 * r0 + r1) // 3
g = (2 * g0 + g1) // 3
b = (2 * b0 + b1) // 3
elif color_code == 3:
r = (2 * r1 + r0) // 3
g = (2 * g1 + g0) // 3
b = (2 * b1 + b0) // 3
ret[j].extend([r, g, b, a])
return ret
def decode_dxt5(data: bytes) -> tuple[bytearray, bytearray, bytearray, bytearray]:
"""
input: one "row" of data (i.e. will produce 4 * width pixels)
"""
blocks = len(data) // 16 # number of blocks in row
ret = (bytearray(), bytearray(), bytearray(), bytearray())
for block_index in range(blocks):
idx = block_index * 16
block = data[idx : idx + 16]
# Decode next 16-byte block.
a0, a1 = struct.unpack_from("<BB", block)
bits = struct.unpack_from("<6B", block, 2)
alphacode1 = bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24)
alphacode2 = bits[0] | (bits[1] << 8)
color0, color1 = struct.unpack_from("<HH", block, 8)
(code,) = struct.unpack_from("<I", block, 12)
r0, g0, b0 = unpack_565(color0)
r1, g1, b1 = unpack_565(color1)
for j in range(4):
for i in range(4):
# get next control op and generate a pixel
alphacode_index = 3 * (4 * j + i)
if alphacode_index <= 12:
alphacode = (alphacode2 >> alphacode_index) & 0x07
elif alphacode_index == 15:
alphacode = (alphacode2 >> 15) | ((alphacode1 << 1) & 0x06)
else: # alphacode_index >= 18 and alphacode_index <= 45
alphacode = (alphacode1 >> (alphacode_index - 16)) & 0x07
if alphacode == 0:
a = a0
elif alphacode == 1:
a = a1
elif a0 > a1:
a = ((8 - alphacode) * a0 + (alphacode - 1) * a1) // 7
elif alphacode == 6:
a = 0
elif alphacode == 7:
a = 255
else:
a = ((6 - alphacode) * a0 + (alphacode - 1) * a1) // 5
color_code = (code >> 2 * (4 * j + i)) & 0x03
if color_code == 0:
r, g, b = r0, g0, b0
elif color_code == 1:
r, g, b = r1, g1, b1
elif color_code == 2:
r = (2 * r0 + r1) // 3
g = (2 * g0 + g1) // 3
b = (2 * b0 + b1) // 3
elif color_code == 3:
r = (2 * r1 + r0) // 3
g = (2 * g1 + g0) // 3
b = (2 * b1 + b0) // 3
ret[j].extend([r, g, b, a])
return ret
class BLPFormatError(NotImplementedError):
pass
def _accept(prefix: bytes) -> bool:
return prefix.startswith((b"BLP1", b"BLP2"))
class BlpImageFile(ImageFile.ImageFile):
"""
Blizzard Mipmap Format
"""
format = "BLP"
format_description = "Blizzard Mipmap Format"
def _open(self) -> None:
self.magic = self.fp.read(4)
if not _accept(self.magic):
msg = f"Bad BLP magic {repr(self.magic)}"
raise BLPFormatError(msg)
compression = struct.unpack("<i", self.fp.read(4))[0]
if self.magic == b"BLP1":
alpha = struct.unpack("<I", self.fp.read(4))[0] != 0
else:
encoding = struct.unpack("<b", self.fp.read(1))[0]
alpha = struct.unpack("<b", self.fp.read(1))[0] != 0
alpha_encoding = struct.unpack("<b", self.fp.read(1))[0]
self.fp.seek(1, os.SEEK_CUR) # mips
self._size = struct.unpack("<II", self.fp.read(8))
args: tuple[int, int, bool] | tuple[int, int, bool, int]
if self.magic == b"BLP1":
encoding = struct.unpack("<i", self.fp.read(4))[0]
self.fp.seek(4, os.SEEK_CUR) # subtype
args = (compression, encoding, alpha)
offset = 28
else:
args = (compression, encoding, alpha, alpha_encoding)
offset = 20
decoder = self.magic.decode()
self._mode = "RGBA" if alpha else "RGB"
self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, offset, args)]
class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder):
_pulls_fd = True
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
try:
self._read_header()
self._load()
except struct.error as e:
msg = "Truncated BLP file"
raise OSError(msg) from e
return -1, 0
@abc.abstractmethod
def _load(self) -> None:
pass
def _read_header(self) -> None:
self._offsets = struct.unpack("<16I", self._safe_read(16 * 4))
self._lengths = struct.unpack("<16I", self._safe_read(16 * 4))
def _safe_read(self, length: int) -> bytes:
assert self.fd is not None
return ImageFile._safe_read(self.fd, length)
def _read_palette(self) -> list[tuple[int, int, int, int]]:
ret = []
for i in range(256):
try:
b, g, r, a = struct.unpack("<4B", self._safe_read(4))
except struct.error:
break
ret.append((b, g, r, a))
return ret
def _read_bgra(
self, palette: list[tuple[int, int, int, int]], alpha: bool
) -> bytearray:
data = bytearray()
_data = BytesIO(self._safe_read(self._lengths[0]))
while True:
try:
(offset,) = struct.unpack("<B", _data.read(1))
except struct.error:
break
b, g, r, a = palette[offset]
d: tuple[int, ...] = (r, g, b)
if alpha:
d += (a,)
data.extend(d)
return data
class BLP1Decoder(_BLPBaseDecoder):
def _load(self) -> None:
self._compression, self._encoding, alpha = self.args
if self._compression == Format.JPEG:
self._decode_jpeg_stream()
elif self._compression == 1:
if self._encoding in (4, 5):
palette = self._read_palette()
data = self._read_bgra(palette, alpha)
self.set_as_raw(data)
else:
msg = f"Unsupported BLP encoding {repr(self._encoding)}"
raise BLPFormatError(msg)
else:
msg = f"Unsupported BLP compression {repr(self._encoding)}"
raise BLPFormatError(msg)
def _decode_jpeg_stream(self) -> None:
from .JpegImagePlugin import JpegImageFile
(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
jpeg_header = self._safe_read(jpeg_header_size)
assert self.fd is not None
self._safe_read(self._offsets[0] - self.fd.tell()) # What IS this?
data = self._safe_read(self._lengths[0])
data = jpeg_header + data
image = JpegImageFile(BytesIO(data))
Image._decompression_bomb_check(image.size)
if image.mode == "CMYK":
args = image.tile[0].args
assert isinstance(args, tuple)
image.tile = [image.tile[0]._replace(args=(args[0], "CMYK"))]
self.set_as_raw(image.convert("RGB").tobytes(), "BGR")
class BLP2Decoder(_BLPBaseDecoder):
def _load(self) -> None:
self._compression, self._encoding, alpha, self._alpha_encoding = self.args
palette = self._read_palette()
assert self.fd is not None
self.fd.seek(self._offsets[0])
if self._compression == 1:
# Uncompressed or DirectX compression
if self._encoding == Encoding.UNCOMPRESSED:
data = self._read_bgra(palette, alpha)
elif self._encoding == Encoding.DXT:
data = bytearray()
if self._alpha_encoding == AlphaEncoding.DXT1:
linesize = (self.state.xsize + 3) // 4 * 8
for yb in range((self.state.ysize + 3) // 4):
for d in decode_dxt1(self._safe_read(linesize), alpha):
data += d
elif self._alpha_encoding == AlphaEncoding.DXT3:
linesize = (self.state.xsize + 3) // 4 * 16
for yb in range((self.state.ysize + 3) // 4):
for d in decode_dxt3(self._safe_read(linesize)):
data += d
elif self._alpha_encoding == AlphaEncoding.DXT5:
linesize = (self.state.xsize + 3) // 4 * 16
for yb in range((self.state.ysize + 3) // 4):
for d in decode_dxt5(self._safe_read(linesize)):
data += d
else:
msg = f"Unsupported alpha encoding {repr(self._alpha_encoding)}"
raise BLPFormatError(msg)
else:
msg = f"Unknown BLP encoding {repr(self._encoding)}"
raise BLPFormatError(msg)
else:
msg = f"Unknown BLP compression {repr(self._compression)}"
raise BLPFormatError(msg)
self.set_as_raw(data)
class BLPEncoder(ImageFile.PyEncoder):
_pushes_fd = True
def _write_palette(self) -> bytes:
data = b""
assert self.im is not None
palette = self.im.getpalette("RGBA", "RGBA")
for i in range(len(palette) // 4):
r, g, b, a = palette[i * 4 : (i + 1) * 4]
data += struct.pack("<4B", b, g, r, a)
while len(data) < 256 * 4:
data += b"\x00" * 4
return data
def encode(self, bufsize: int) -> tuple[int, int, bytes]:
palette_data = self._write_palette()
offset = 20 + 16 * 4 * 2 + len(palette_data)
data = struct.pack("<16I", offset, *((0,) * 15))
assert self.im is not None
w, h = self.im.size
data += struct.pack("<16I", w * h, *((0,) * 15))
data += palette_data
for y in range(h):
for x in range(w):
data += struct.pack("<B", self.im.getpixel((x, y)))
return len(data), 0, data
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
if im.mode != "P":
msg = "Unsupported BLP image mode"
raise ValueError(msg)
magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2"
fp.write(magic)
assert im.palette is not None
fp.write(struct.pack("<i", 1)) # Uncompressed or DirectX compression
alpha_depth = 1 if im.palette.mode == "RGBA" else 0
if magic == b"BLP1":
fp.write(struct.pack("<L", alpha_depth))
else:
fp.write(struct.pack("<b", Encoding.UNCOMPRESSED))
fp.write(struct.pack("<b", alpha_depth))
fp.write(struct.pack("<b", 0)) # alpha encoding
fp.write(struct.pack("<b", 0)) # mips
fp.write(struct.pack("<II", *im.size))
if magic == b"BLP1":
fp.write(struct.pack("<i", 5))
fp.write(struct.pack("<i", 0))
ImageFile._save(im, fp, [ImageFile._Tile("BLP", (0, 0) + im.size, 0, im.mode)])
Image.register_open(BlpImageFile.format, BlpImageFile, _accept)
Image.register_extension(BlpImageFile.format, ".blp")
Image.register_decoder("BLP1", BLP1Decoder)
Image.register_decoder("BLP2", BLP2Decoder)
Image.register_save(BlpImageFile.format, _save)
Image.register_encoder("BLP", BLPEncoder)

View File

@ -1,515 +0,0 @@
#
# The Python Imaging Library.
# $Id$
#
# BMP file handler
#
# Windows (and OS/2) native bitmap storage format.
#
# history:
# 1995-09-01 fl Created
# 1996-04-30 fl Added save
# 1997-08-27 fl Fixed save of 1-bit images
# 1998-03-06 fl Load P images as L where possible
# 1998-07-03 fl Load P images as 1 where possible
# 1998-12-29 fl Handle small palettes
# 2002-12-30 fl Fixed load of 1-bit palette images
# 2003-04-21 fl Fixed load of 1-bit monochrome images
# 2003-04-23 fl Added limited support for BI_BITFIELDS compression
#
# Copyright (c) 1997-2003 by Secret Labs AB
# Copyright (c) 1995-2003 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#
from __future__ import annotations
import os
from typing import IO, Any
from . import Image, ImageFile, ImagePalette
from ._binary import i16le as i16
from ._binary import i32le as i32
from ._binary import o8
from ._binary import o16le as o16
from ._binary import o32le as o32
#
# --------------------------------------------------------------------
# Read BMP file
BIT2MODE = {
# bits => mode, rawmode
1: ("P", "P;1"),
4: ("P", "P;4"),
8: ("P", "P"),
16: ("RGB", "BGR;15"),
24: ("RGB", "BGR"),
32: ("RGB", "BGRX"),
}
USE_RAW_ALPHA = False
def _accept(prefix: bytes) -> bool:
return prefix.startswith(b"BM")
def _dib_accept(prefix: bytes) -> bool:
return i32(prefix) in [12, 40, 52, 56, 64, 108, 124]
# =============================================================================
# Image plugin for the Windows BMP format.
# =============================================================================
class BmpImageFile(ImageFile.ImageFile):
"""Image plugin for the Windows Bitmap format (BMP)"""
# ------------------------------------------------------------- Description
format_description = "Windows Bitmap"
format = "BMP"
# -------------------------------------------------- BMP Compression values
COMPRESSIONS = {"RAW": 0, "RLE8": 1, "RLE4": 2, "BITFIELDS": 3, "JPEG": 4, "PNG": 5}
for k, v in COMPRESSIONS.items():
vars()[k] = v
def _bitmap(self, header: int = 0, offset: int = 0) -> None:
"""Read relevant info about the BMP"""
read, seek = self.fp.read, self.fp.seek
if header:
seek(header)
# read bmp header size @offset 14 (this is part of the header size)
file_info: dict[str, bool | int | tuple[int, ...]] = {
"header_size": i32(read(4)),
"direction": -1,
}
# -------------------- If requested, read header at a specific position
# read the rest of the bmp header, without its size
assert isinstance(file_info["header_size"], int)
header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4)
# ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1
# ----- This format has different offsets because of width/height types
# 12: BITMAPCOREHEADER/OS21XBITMAPHEADER
if file_info["header_size"] == 12:
file_info["width"] = i16(header_data, 0)
file_info["height"] = i16(header_data, 2)
file_info["planes"] = i16(header_data, 4)
file_info["bits"] = i16(header_data, 6)
file_info["compression"] = self.COMPRESSIONS["RAW"]
file_info["palette_padding"] = 3
# --------------------------------------------- Windows Bitmap v3 to v5
# 40: BITMAPINFOHEADER
# 52: BITMAPV2HEADER
# 56: BITMAPV3HEADER
# 64: BITMAPCOREHEADER2/OS22XBITMAPHEADER
# 108: BITMAPV4HEADER
# 124: BITMAPV5HEADER
elif file_info["header_size"] in (40, 52, 56, 64, 108, 124):
file_info["y_flip"] = header_data[7] == 0xFF
file_info["direction"] = 1 if file_info["y_flip"] else -1
file_info["width"] = i32(header_data, 0)
file_info["height"] = (
i32(header_data, 4)
if not file_info["y_flip"]
else 2**32 - i32(header_data, 4)
)
file_info["planes"] = i16(header_data, 8)
file_info["bits"] = i16(header_data, 10)
file_info["compression"] = i32(header_data, 12)
# byte size of pixel data
file_info["data_size"] = i32(header_data, 16)
file_info["pixels_per_meter"] = (
i32(header_data, 20),
i32(header_data, 24),
)
file_info["colors"] = i32(header_data, 28)
file_info["palette_padding"] = 4
assert isinstance(file_info["pixels_per_meter"], tuple)
self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"])
if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]:
masks = ["r_mask", "g_mask", "b_mask"]
if len(header_data) >= 48:
if len(header_data) >= 52:
masks.append("a_mask")
else:
file_info["a_mask"] = 0x0
for idx, mask in enumerate(masks):
file_info[mask] = i32(header_data, 36 + idx * 4)
else:
# 40 byte headers only have the three components in the
# bitfields masks, ref:
# https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx
# See also
# https://github.com/python-pillow/Pillow/issues/1293
# There is a 4th component in the RGBQuad, in the alpha
# location, but it is listed as a reserved component,
# and it is not generally an alpha channel
file_info["a_mask"] = 0x0
for mask in masks:
file_info[mask] = i32(read(4))
assert isinstance(file_info["r_mask"], int)
assert isinstance(file_info["g_mask"], int)
assert isinstance(file_info["b_mask"], int)
assert isinstance(file_info["a_mask"], int)
file_info["rgb_mask"] = (
file_info["r_mask"],
file_info["g_mask"],
file_info["b_mask"],
)
file_info["rgba_mask"] = (
file_info["r_mask"],
file_info["g_mask"],
file_info["b_mask"],
file_info["a_mask"],
)
else:
msg = f"Unsupported BMP header type ({file_info['header_size']})"
raise OSError(msg)
# ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16
assert isinstance(file_info["width"], int)
assert isinstance(file_info["height"], int)
self._size = file_info["width"], file_info["height"]
# ------- If color count was not found in the header, compute from bits
assert isinstance(file_info["bits"], int)
file_info["colors"] = (
file_info["colors"]
if file_info.get("colors", 0)
else (1 << file_info["bits"])
)
assert isinstance(file_info["colors"], int)
if offset == 14 + file_info["header_size"] and file_info["bits"] <= 8:
offset += 4 * file_info["colors"]
# ---------------------- Check bit depth for unusual unsupported values
self._mode, raw_mode = BIT2MODE.get(file_info["bits"], ("", ""))
if not self.mode:
msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
raise OSError(msg)
# ---------------- Process BMP with Bitfields compression (not palette)
decoder_name = "raw"
if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]:
SUPPORTED: dict[int, list[tuple[int, ...]]] = {
32: [
(0xFF0000, 0xFF00, 0xFF, 0x0),
(0xFF000000, 0xFF0000, 0xFF00, 0x0),
(0xFF000000, 0xFF00, 0xFF, 0x0),
(0xFF000000, 0xFF0000, 0xFF00, 0xFF),
(0xFF, 0xFF00, 0xFF0000, 0xFF000000),
(0xFF0000, 0xFF00, 0xFF, 0xFF000000),
(0xFF000000, 0xFF00, 0xFF, 0xFF0000),
(0x0, 0x0, 0x0, 0x0),
],
24: [(0xFF0000, 0xFF00, 0xFF)],
16: [(0xF800, 0x7E0, 0x1F), (0x7C00, 0x3E0, 0x1F)],
}
MASK_MODES = {
(32, (0xFF0000, 0xFF00, 0xFF, 0x0)): "BGRX",
(32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)): "XBGR",
(32, (0xFF000000, 0xFF00, 0xFF, 0x0)): "BGXR",
(32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)): "ABGR",
(32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)): "RGBA",
(32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)): "BGRA",
(32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR",
(32, (0x0, 0x0, 0x0, 0x0)): "BGRA",
(24, (0xFF0000, 0xFF00, 0xFF)): "BGR",
(16, (0xF800, 0x7E0, 0x1F)): "BGR;16",
(16, (0x7C00, 0x3E0, 0x1F)): "BGR;15",
}
if file_info["bits"] in SUPPORTED:
if (
file_info["bits"] == 32
and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
):
assert isinstance(file_info["rgba_mask"], tuple)
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
self._mode = "RGBA" if "A" in raw_mode else self.mode
elif (
file_info["bits"] in (24, 16)
and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
):
assert isinstance(file_info["rgb_mask"], tuple)
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])]
else:
msg = "Unsupported BMP bitfields layout"
raise OSError(msg)
else:
msg = "Unsupported BMP bitfields layout"
raise OSError(msg)
elif file_info["compression"] == self.COMPRESSIONS["RAW"]:
if file_info["bits"] == 32 and (
header == 22 or USE_RAW_ALPHA # 32-bit .cur offset
):
raw_mode, self._mode = "BGRA", "RGBA"
elif file_info["compression"] in (
self.COMPRESSIONS["RLE8"],
self.COMPRESSIONS["RLE4"],
):
decoder_name = "bmp_rle"
else:
msg = f"Unsupported BMP compression ({file_info['compression']})"
raise OSError(msg)
# --------------- Once the header is processed, process the palette/LUT
if self.mode == "P": # Paletted for 1, 4 and 8 bit images
# ---------------------------------------------------- 1-bit images
if not (0 < file_info["colors"] <= 65536):
msg = f"Unsupported BMP Palette size ({file_info['colors']})"
raise OSError(msg)
else:
assert isinstance(file_info["palette_padding"], int)
padding = file_info["palette_padding"]
palette = read(padding * file_info["colors"])
grayscale = True
indices = (
(0, 255)
if file_info["colors"] == 2
else list(range(file_info["colors"]))
)
# ----------------- Check if grayscale and ignore palette if so
for ind, val in enumerate(indices):
rgb = palette[ind * padding : ind * padding + 3]
if rgb != o8(val) * 3:
grayscale = False
# ------- If all colors are gray, white or black, ditch palette
if grayscale:
self._mode = "1" if file_info["colors"] == 2 else "L"
raw_mode = self.mode
else:
self._mode = "P"
self.palette = ImagePalette.raw(
"BGRX" if padding == 4 else "BGR", palette
)
# ---------------------------- Finally set the tile data for the plugin
self.info["compression"] = file_info["compression"]
args: list[Any] = [raw_mode]
if decoder_name == "bmp_rle":
args.append(file_info["compression"] == self.COMPRESSIONS["RLE4"])
else:
assert isinstance(file_info["width"], int)
args.append(((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3))
args.append(file_info["direction"])
self.tile = [
ImageFile._Tile(
decoder_name,
(0, 0, file_info["width"], file_info["height"]),
offset or self.fp.tell(),
tuple(args),
)
]
def _open(self) -> None:
"""Open file, check magic number and read header"""
# read 14 bytes: magic number, filesize, reserved, header final offset
head_data = self.fp.read(14)
# choke if the file does not have the required magic bytes
if not _accept(head_data):
msg = "Not a BMP file"
raise SyntaxError(msg)
# read the start position of the BMP image data (u32)
offset = i32(head_data, 10)
# load bitmap information (offset=raster info)
self._bitmap(offset=offset)
class BmpRleDecoder(ImageFile.PyDecoder):
_pulls_fd = True
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
assert self.fd is not None
rle4 = self.args[1]
data = bytearray()
x = 0
dest_length = self.state.xsize * self.state.ysize
while len(data) < dest_length:
pixels = self.fd.read(1)
byte = self.fd.read(1)
if not pixels or not byte:
break
num_pixels = pixels[0]
if num_pixels:
# encoded mode
if x + num_pixels > self.state.xsize:
# Too much data for row
num_pixels = max(0, self.state.xsize - x)
if rle4:
first_pixel = o8(byte[0] >> 4)
second_pixel = o8(byte[0] & 0x0F)
for index in range(num_pixels):
if index % 2 == 0:
data += first_pixel
else:
data += second_pixel
else:
data += byte * num_pixels
x += num_pixels
else:
if byte[0] == 0:
# end of line
while len(data) % self.state.xsize != 0:
data += b"\x00"
x = 0
elif byte[0] == 1:
# end of bitmap
break
elif byte[0] == 2:
# delta
bytes_read = self.fd.read(2)
if len(bytes_read) < 2:
break
right, up = self.fd.read(2)
data += b"\x00" * (right + up * self.state.xsize)
x = len(data) % self.state.xsize
else:
# absolute mode
if rle4:
# 2 pixels per byte
byte_count = byte[0] // 2
bytes_read = self.fd.read(byte_count)
for byte_read in bytes_read:
data += o8(byte_read >> 4)
data += o8(byte_read & 0x0F)
else:
byte_count = byte[0]
bytes_read = self.fd.read(byte_count)
data += bytes_read
if len(bytes_read) < byte_count:
break
x += byte[0]
# align to 16-bit word boundary
if self.fd.tell() % 2 != 0:
self.fd.seek(1, os.SEEK_CUR)
rawmode = "L" if self.mode == "L" else "P"
self.set_as_raw(bytes(data), rawmode, (0, self.args[-1]))
return -1, 0
# =============================================================================
# Image plugin for the DIB format (BMP alias)
# =============================================================================
class DibImageFile(BmpImageFile):
format = "DIB"
format_description = "Windows Bitmap"
def _open(self) -> None:
self._bitmap()
#
# --------------------------------------------------------------------
# Write BMP file
SAVE = {
"1": ("1", 1, 2),
"L": ("L", 8, 256),
"P": ("P", 8, 256),
"RGB": ("BGR", 24, 0),
"RGBA": ("BGRA", 32, 0),
}
def _dib_save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
_save(im, fp, filename, False)
def _save(
im: Image.Image, fp: IO[bytes], filename: str | bytes, bitmap_header: bool = True
) -> None:
try:
rawmode, bits, colors = SAVE[im.mode]
except KeyError as e:
msg = f"cannot write mode {im.mode} as BMP"
raise OSError(msg) from e
info = im.encoderinfo
dpi = info.get("dpi", (96, 96))
# 1 meter == 39.3701 inches
ppm = tuple(int(x * 39.3701 + 0.5) for x in dpi)
stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
header = 40 # or 64 for OS/2 version 2
image = stride * im.size[1]
if im.mode == "1":
palette = b"".join(o8(i) * 3 + b"\x00" for i in (0, 255))
elif im.mode == "L":
palette = b"".join(o8(i) * 3 + b"\x00" for i in range(256))
elif im.mode == "P":
palette = im.im.getpalette("RGB", "BGRX")
colors = len(palette) // 4
else:
palette = None
# bitmap header
if bitmap_header:
offset = 14 + header + colors * 4
file_size = offset + image
if file_size > 2**32 - 1:
msg = "File size is too large for the BMP format"
raise ValueError(msg)
fp.write(
b"BM" # file type (magic)
+ o32(file_size) # file size
+ o32(0) # reserved
+ o32(offset) # image data offset
)
# bitmap info header
fp.write(
o32(header) # info header size
+ o32(im.size[0]) # width
+ o32(im.size[1]) # height
+ o16(1) # planes
+ o16(bits) # depth
+ o32(0) # compression (0=uncompressed)
+ o32(image) # size of bitmap
+ o32(ppm[0]) # resolution
+ o32(ppm[1]) # resolution
+ o32(colors) # colors used
+ o32(colors) # colors important
)
fp.write(b"\0" * (header - 40)) # padding (for OS/2 format)
if palette:
fp.write(palette)
ImageFile._save(
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))]
)
#
# --------------------------------------------------------------------
# Registry
Image.register_open(BmpImageFile.format, BmpImageFile, _accept)
Image.register_save(BmpImageFile.format, _save)
Image.register_extension(BmpImageFile.format, ".bmp")
Image.register_mime(BmpImageFile.format, "image/bmp")
Image.register_decoder("bmp_rle", BmpRleDecoder)
Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
Image.register_save(DibImageFile.format, _dib_save)
Image.register_extension(DibImageFile.format, ".dib")
Image.register_mime(DibImageFile.format, "image/bmp")

View File

@ -1,75 +0,0 @@
#
# The Python Imaging Library
# $Id$
#
# BUFR stub adapter
#
# Copyright (c) 1996-2003 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#
from __future__ import annotations
import os
from typing import IO
from . import Image, ImageFile
_handler = None
def register_handler(handler: ImageFile.StubHandler | None) -> None:
"""
Install application-specific BUFR image handler.
:param handler: Handler object.
"""
global _handler
_handler = handler
# --------------------------------------------------------------------
# Image adapter
def _accept(prefix: bytes) -> bool:
return prefix.startswith((b"BUFR", b"ZCZC"))
class BufrStubImageFile(ImageFile.StubImageFile):
format = "BUFR"
format_description = "BUFR"
def _open(self) -> None:
if not _accept(self.fp.read(4)):
msg = "Not a BUFR file"
raise SyntaxError(msg)
self.fp.seek(-4, os.SEEK_CUR)
# make something up
self._mode = "F"
self._size = 1, 1
loader = self._load()
if loader:
loader.open(self)
def _load(self) -> ImageFile.StubHandler | None:
return _handler
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
if _handler is None or not hasattr(_handler, "save"):
msg = "BUFR save handler not installed"
raise OSError(msg)
_handler.save(im, fp, filename)
# --------------------------------------------------------------------
# Registry
Image.register_open(BufrStubImageFile.format, BufrStubImageFile, _accept)
Image.register_save(BufrStubImageFile.format, _save)
Image.register_extension(BufrStubImageFile.format, ".bufr")

Some files were not shown because too many files have changed in this diff Show More