CyGuy8 commited on
Commit
aa9ec19
·
verified ·
1 Parent(s): d18ef71

Sync from GitHub via hub-sync

Browse files
Files changed (8) hide show
  1. .python-version +1 -0
  2. Agents.md +21 -0
  3. LICENSE +21 -0
  4. README.md +30 -7
  5. app.py +86 -0
  6. pyproject.toml +15 -0
  7. requirements.txt +4 -0
  8. uv.lock +0 -0
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
Agents.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Python Environment
2
+
3
+ Always use uv to run Python scripts and manage dependencies -- never use pip or python directly.
4
+
5
+ Run scripts with `uv run python script.py` instead of `python script.py`.
6
+
7
+ Install packages with `uv add package-name` instead of `pip install`.
8
+
9
+ To run one-off commands: `uv run <command>`.
10
+
11
+ The project uses uv for virtual environment management; do not create venvs manually with `python -m venv`.
12
+
13
+ ## Common Commands
14
+
15
+ `uv run python script.py` -- run a script
16
+
17
+ `uv add <package>` -- add a dependency
18
+
19
+ `uv sync` -- install all dependencies from lockfile
20
+
21
+ `uv run pytest` -- run tests
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CyGuy8
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,15 +1,38 @@
1
  ---
2
  title: PicRotate
3
- emoji: 📈
4
- colorFrom: red
5
- colorTo: green
6
  sdk: gradio
7
- sdk_version: 6.16.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
11
  license: mit
12
- short_description: Rotates a Picture
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: PicRotate
 
 
 
3
  sdk: gradio
4
+ sdk_version: 4.44.1
5
+ python_version: 3.12
6
  app_file: app.py
7
  pinned: false
8
  license: mit
9
+ short_description: Rotate images by 90 degrees or any custom angle.
10
  ---
11
 
12
+ # PicRotate
13
+
14
+ Rotate an image from a file upload or pasted clipboard image using Gradio.
15
+
16
+ ## Hugging Face Spaces
17
+
18
+ This repository is ready for a Gradio Space. The required Space components are:
19
+
20
+ - `README.md` metadata block with `sdk: gradio`, `sdk_version: 4.44.1`, `python_version: 3.12`, and `app_file: app.py`
21
+ - `app.py` as the Gradio application entry point
22
+ - `requirements.txt` for Python dependencies installed by the Space runtime
23
+
24
+ Create a Hugging Face Space with the Gradio SDK, then push these files to the Space repository. The Space will build and launch `app.py` automatically.
25
+
26
+ ## Requirements
27
+
28
+ - `gradio==4.44.1`
29
+ - `pillow>=10.0.0`
30
+ - `huggingface-hub<1.0.0`
31
+ - `pydantic==2.10.6`
32
+
33
+ ## Run
34
+
35
+ ```powershell
36
+ uv sync
37
+ uv run python app.py
38
+ ```
app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ import gradio as gr
6
+ from PIL import Image
7
+
8
+ RotationMode = Literal["Clockwise 90", "Counterclockwise 90", "Custom angle"]
9
+
10
+
11
+ def rotate_image(
12
+ image: Image.Image | None,
13
+ rotation_mode: RotationMode,
14
+ custom_angle: float | None,
15
+ ) -> Image.Image | None:
16
+ if image is None:
17
+ return None
18
+
19
+ if rotation_mode == "Clockwise 90":
20
+ angle = -90
21
+ elif rotation_mode == "Counterclockwise 90":
22
+ angle = 90
23
+ else:
24
+ angle = -(custom_angle or 0)
25
+
26
+ return image.rotate(
27
+ angle,
28
+ expand=True,
29
+ resample=Image.Resampling.BICUBIC,
30
+ fillcolor=(255, 255, 255, 0) if image.mode == "RGBA" else None,
31
+ )
32
+
33
+
34
+ def show_custom_angle(rotation_mode: RotationMode):
35
+ return gr.update(visible=rotation_mode == "Custom angle")
36
+
37
+
38
+ def build_app() -> gr.Blocks:
39
+ with gr.Blocks(title="PicRotate", theme=gr.themes.Soft()) as demo:
40
+ gr.Markdown("# PicRotate")
41
+
42
+ with gr.Row():
43
+ input_image = gr.Image(
44
+ label="Image",
45
+ sources=["upload", "clipboard"],
46
+ type="pil",
47
+ image_mode="RGBA",
48
+ height=460,
49
+ )
50
+ output_image = gr.Image(
51
+ label="Rotated image",
52
+ type="pil",
53
+ image_mode="RGBA",
54
+ height=460,
55
+ )
56
+
57
+ with gr.Row():
58
+ rotation_mode = gr.Radio(
59
+ choices=["Clockwise 90", "Counterclockwise 90", "Custom angle"],
60
+ value="Clockwise 90",
61
+ label="Rotation",
62
+ )
63
+ custom_angle = gr.Number(
64
+ value=45,
65
+ label="Custom angle in degrees clockwise",
66
+ precision=2,
67
+ visible=False,
68
+ )
69
+
70
+ rotate_button = gr.Button("Rotate", variant="primary")
71
+ rotation_mode.change(
72
+ fn=show_custom_angle,
73
+ inputs=rotation_mode,
74
+ outputs=custom_angle,
75
+ )
76
+ rotate_button.click(
77
+ fn=rotate_image,
78
+ inputs=[input_image, rotation_mode, custom_angle],
79
+ outputs=output_image,
80
+ )
81
+
82
+ return demo
83
+
84
+
85
+ if __name__ == "__main__":
86
+ build_app().launch()
pyproject.toml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "picrotate"
3
+ version = "0.1.0"
4
+ description = "A Gradio app for rotating images."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10,<3.13"
7
+ dependencies = [
8
+ "gradio==4.44.1",
9
+ "huggingface-hub<1.0.0",
10
+ "pillow>=10.0.0",
11
+ "pydantic==2.10.6",
12
+ ]
13
+
14
+ [tool.uv]
15
+ package = false
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio==4.44.1
2
+ huggingface-hub<1.0.0
3
+ pillow>=10.0.0
4
+ pydantic==2.10.6
uv.lock ADDED
The diff for this file is too large to render. See raw diff