imgstat 2.0.6 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -19
- package/bin/imgstat +13 -2
- package/lib/analyze.sh +49 -18
- package/lib/format-json.sh +49 -0
- package/lib/ui.sh +18 -1
- package/lib/write-agent.sh +31 -0
- package/lib/write-claude.sh +42 -0
- package/lib/write-cursor.sh +32 -0
- package/lib/write-windsurf.sh +47 -0
- package/package.json +1 -1
- package/build_deb.sh +0 -48
- package/imagestat +0 -124
- package/install.sh +0 -68
package/README.md
CHANGED
|
@@ -3,32 +3,17 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/imgstat)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
imgstat is a CLI tool that embeds image dimensions directly into filenames, or analyzes remote imagery, to give AI context without needing external parsers.
|
|
6
|
+
give AI context about your images.
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
imgstat scans your project and generates image dimension reports your AI coding assistant
|
|
9
|
+
can actually read — without guessing, without vision tokens, without touching your source files.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## install
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm install -g imgstat
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Or run it directly without installing:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx imgstat
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Features
|
|
24
|
-
|
|
25
|
-
imgstat handles renaming smoothly and idempotently—it will never re-append dimensions to a file that already has them. When dealing with remote imagery from URLs or scanning your codebase, it securely generates dimension reports without leaving permanent downloads on your machine. For AI integration, the `analyze` mode seamlessly builds an `.agent/rules/image_dimensions.md` file, giving your local language models instant, zero-config context about the images used in your project.
|
|
26
|
-
|
|
27
|
-
## Usage
|
|
28
|
-
|
|
29
|
-
Run `imgstat` with no arguments to get an interactive menu. You will be prompted to select the mode you want to use.
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
17
|
imgstat
|
|
33
18
|
```
|
|
34
19
|
|
package/bin/imgstat
CHANGED
|
@@ -21,6 +21,7 @@ MODE=""
|
|
|
21
21
|
TARGET=""
|
|
22
22
|
DRY_RUN="false"
|
|
23
23
|
YES_FLAG="false"
|
|
24
|
+
FORMAT=""
|
|
24
25
|
|
|
25
26
|
# Simple parser
|
|
26
27
|
while [[ $# -gt 0 ]]; do
|
|
@@ -50,14 +51,24 @@ while [[ $# -gt 0 ]]; do
|
|
|
50
51
|
echo " inspect Print dimensions of local directory images"
|
|
51
52
|
echo " rename Rename local files (e.g. image-800x600.jpg)"
|
|
52
53
|
echo " remote Print dimensions of images from a URL"
|
|
53
|
-
echo " analyze Scan codebase for URLs, write
|
|
54
|
+
echo " analyze Scan codebase for URLs, write dimension report for your IDE"
|
|
54
55
|
echo ""
|
|
55
56
|
echo "Options:"
|
|
57
|
+
echo " --format Set output format (e.g. --format json)"
|
|
56
58
|
echo " --dry-run Show what would happen without making changes"
|
|
57
59
|
echo " --yes, -y Skip confirmation prompts (for rename)"
|
|
58
60
|
echo " --help, -h Show this help message"
|
|
59
61
|
exit 0
|
|
60
62
|
;;
|
|
63
|
+
--format)
|
|
64
|
+
shift
|
|
65
|
+
FORMAT="$1"
|
|
66
|
+
if [[ "$FORMAT" != "json" ]]; then
|
|
67
|
+
echo "Error: unsupported format '$FORMAT'. Only 'json' is supported."
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
shift
|
|
71
|
+
;;
|
|
61
72
|
-*)
|
|
62
73
|
echo "Unknown flag: $1"
|
|
63
74
|
exit 1
|
|
@@ -109,6 +120,6 @@ case "$MODE" in
|
|
|
109
120
|
;;
|
|
110
121
|
analyze)
|
|
111
122
|
source "$LIB_DIR/analyze.sh"
|
|
112
|
-
cmd_analyze "$TARGET"
|
|
123
|
+
cmd_analyze "$TARGET" "1" "$FORMAT"
|
|
113
124
|
;;
|
|
114
125
|
esac
|
package/lib/analyze.sh
CHANGED
|
@@ -4,6 +4,8 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utils.sh"
|
|
|
4
4
|
|
|
5
5
|
cmd_analyze() {
|
|
6
6
|
local dir="$1"
|
|
7
|
+
local target_option="${2:-1}"
|
|
8
|
+
local json_format="$3"
|
|
7
9
|
echo "Analyzing codebase for remote image references in $dir..."
|
|
8
10
|
|
|
9
11
|
# ── Step 1: Extract all http/https URLs from common code files ──────────────
|
|
@@ -84,22 +86,8 @@ cmd_analyze() {
|
|
|
84
86
|
trap 'rm -rf "$TEMP_DIR"' EXIT
|
|
85
87
|
|
|
86
88
|
# Output file setup
|
|
87
|
-
local
|
|
88
|
-
|
|
89
|
-
mkdir -p "$rules_dir"
|
|
90
|
-
|
|
91
|
-
# Write header
|
|
92
|
-
cat << 'EOF' > "$rules_file"
|
|
93
|
-
# Codebase Remote Images
|
|
94
|
-
|
|
95
|
-
> [!NOTE]
|
|
96
|
-
> This file is strictly auto-generated by `imgstat`.
|
|
97
|
-
> It maps remote image URLs found in the codebase to their exact physical dimensions.
|
|
98
|
-
> AI assistants should use this dictionary when asked about layout constraints, native sizes, or aspect ratios of referenced images.
|
|
99
|
-
|
|
100
|
-
| Documented URL | Detected Size (W x H) |
|
|
101
|
-
|---|---|
|
|
102
|
-
EOF
|
|
89
|
+
local TEMP_RESULTS=$(mktemp)
|
|
90
|
+
trap 'rm -rf "$TEMP_DIR" "$TEMP_RESULTS"' EXIT
|
|
103
91
|
|
|
104
92
|
local processed=0
|
|
105
93
|
|
|
@@ -109,7 +97,9 @@ EOF
|
|
|
109
97
|
--user-agent="Mozilla/5.0" \
|
|
110
98
|
-P "$TEMP_DIR" "$url" 2>/dev/null || true
|
|
111
99
|
|
|
100
|
+
shopt -s nullglob
|
|
112
101
|
local all_files=( "$TEMP_DIR"/* )
|
|
102
|
+
shopt -u nullglob
|
|
113
103
|
local found_image=""
|
|
114
104
|
|
|
115
105
|
for file in "${all_files[@]}"; do
|
|
@@ -128,7 +118,7 @@ EOF
|
|
|
128
118
|
if [[ -n "$dim" ]]; then
|
|
129
119
|
local w="${dim% *}"
|
|
130
120
|
local h="${dim#* }"
|
|
131
|
-
echo "
|
|
121
|
+
echo "${url}|${w}|${h}" >> "$TEMP_RESULTS"
|
|
132
122
|
printf " \033[1;32m📐 %s → %sx%s\033[0m\n" "$url" "$w" "$h"
|
|
133
123
|
processed=$((processed + 1))
|
|
134
124
|
fi
|
|
@@ -140,6 +130,47 @@ EOF
|
|
|
140
130
|
|
|
141
131
|
echo ""
|
|
142
132
|
echo "Analysis complete!"
|
|
143
|
-
|
|
133
|
+
|
|
134
|
+
if [[ $processed -eq 0 ]]; then
|
|
135
|
+
echo "No matching images with dimension info could be parsed."
|
|
136
|
+
return 0
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# Depending on Target Option, write file.
|
|
140
|
+
if [[ "$json_format" == "json" ]]; then
|
|
141
|
+
# if it's format json without target, only output json
|
|
142
|
+
if [[ -z "$2" ]]; then
|
|
143
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/format-json.sh" "$dir" "$TEMP_RESULTS" "0"
|
|
144
|
+
return 0
|
|
145
|
+
else
|
|
146
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/format-json.sh" "$dir" "$TEMP_RESULTS" "1"
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
case "$target_option" in
|
|
151
|
+
1)
|
|
152
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-agent.sh" "$dir" "$TEMP_RESULTS"
|
|
153
|
+
;;
|
|
154
|
+
2)
|
|
155
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-cursor.sh" "$dir" "$TEMP_RESULTS"
|
|
156
|
+
;;
|
|
157
|
+
3)
|
|
158
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-windsurf.sh" "$dir" "$TEMP_RESULTS"
|
|
159
|
+
;;
|
|
160
|
+
4)
|
|
161
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-claude.sh" "$dir" "$TEMP_RESULTS"
|
|
162
|
+
;;
|
|
163
|
+
5)
|
|
164
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-agent.sh" "$dir" "$TEMP_RESULTS"
|
|
165
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-cursor.sh" "$dir" "$TEMP_RESULTS"
|
|
166
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-windsurf.sh" "$dir" "$TEMP_RESULTS"
|
|
167
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-claude.sh" "$dir" "$TEMP_RESULTS"
|
|
168
|
+
;;
|
|
169
|
+
*)
|
|
170
|
+
# default
|
|
171
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/write-agent.sh" "$dir" "$TEMP_RESULTS"
|
|
172
|
+
;;
|
|
173
|
+
esac
|
|
174
|
+
|
|
144
175
|
echo "This file can now be read by autonomous coding agents."
|
|
145
176
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Inputs
|
|
4
|
+
# $1: Directory path
|
|
5
|
+
# $2: Temp file containing results in format: url|width|height
|
|
6
|
+
# $3: Optional. Target flag meaning we must write to file instead of stdout.
|
|
7
|
+
|
|
8
|
+
DIR="$1"
|
|
9
|
+
RESULTS_FILE="$2"
|
|
10
|
+
HAS_TARGET="$3"
|
|
11
|
+
|
|
12
|
+
JSON_FILE=""
|
|
13
|
+
if [[ "$HAS_TARGET" == "1" ]]; then
|
|
14
|
+
JSON_FILE="$DIR/image_dimensions.json"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
18
|
+
|
|
19
|
+
TEMP_JSON=$(mktemp)
|
|
20
|
+
|
|
21
|
+
echo "{" > "$TEMP_JSON"
|
|
22
|
+
echo " \"generated_at\": \"$NOW\"," >> "$TEMP_JSON"
|
|
23
|
+
echo " \"images\": [" >> "$TEMP_JSON"
|
|
24
|
+
|
|
25
|
+
FIRST_ITEM=true
|
|
26
|
+
|
|
27
|
+
while IFS='|' read -r url w h; do
|
|
28
|
+
if [ "$FIRST_ITEM" = "true" ]; then
|
|
29
|
+
FIRST_ITEM=false
|
|
30
|
+
else
|
|
31
|
+
echo " ," >> "$TEMP_JSON"
|
|
32
|
+
fi
|
|
33
|
+
# We escape the URL safely
|
|
34
|
+
# Assuming url doesn't have quotes for now, but good practice
|
|
35
|
+
SAFE_URL=$(echo -n "$url" | sed 's/"/\\"/g')
|
|
36
|
+
echo -n " { \"path\": \"$SAFE_URL\", \"width\": $w, \"height\": $h }" >> "$TEMP_JSON"
|
|
37
|
+
done < "$RESULTS_FILE"
|
|
38
|
+
|
|
39
|
+
echo "" >> "$TEMP_JSON"
|
|
40
|
+
echo " ]" >> "$TEMP_JSON"
|
|
41
|
+
echo "}" >> "$TEMP_JSON"
|
|
42
|
+
|
|
43
|
+
if [[ -n "$JSON_FILE" ]]; then
|
|
44
|
+
mv "$TEMP_JSON" "$JSON_FILE"
|
|
45
|
+
echo "Wrote JSON dimension report to: $JSON_FILE"
|
|
46
|
+
else
|
|
47
|
+
cat "$TEMP_JSON"
|
|
48
|
+
rm -f "$TEMP_JSON"
|
|
49
|
+
fi
|
package/lib/ui.sh
CHANGED
|
@@ -74,7 +74,24 @@ cmd_ui() {
|
|
|
74
74
|
3)
|
|
75
75
|
read -e -p "Enter codebase directory to analyze [./]: " dir
|
|
76
76
|
dir="${dir:-./}"
|
|
77
|
-
|
|
77
|
+
echo ""
|
|
78
|
+
echo "where should the report go?"
|
|
79
|
+
echo ""
|
|
80
|
+
echo " 1. .agent/rules/image_dimensions.md (generic / all tools)"
|
|
81
|
+
echo " 2. .cursor/rules/image_dimensions.mdc (cursor)"
|
|
82
|
+
echo " 3. .windsurfrules (windsurf — appends block)"
|
|
83
|
+
echo " 4. CLAUDE.md (claude code — appends block)"
|
|
84
|
+
echo " 5. all of the above"
|
|
85
|
+
echo ""
|
|
86
|
+
read -e -p "Enter choice [1]: " target_env
|
|
87
|
+
target_env="${target_env:-1}"
|
|
88
|
+
|
|
89
|
+
if [[ ! "$target_env" =~ ^[1-5]$ ]]; then
|
|
90
|
+
echo "Invalid choice. Defaulting to 1."
|
|
91
|
+
target_env=1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
cmd_analyze "$dir" "$target_env" ""
|
|
78
95
|
;;
|
|
79
96
|
4)
|
|
80
97
|
echo "Exiting."
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Inputs
|
|
4
|
+
# $1: Directory path
|
|
5
|
+
# $2: Temp file containing results in format: url|width|height
|
|
6
|
+
|
|
7
|
+
DIR="$1"
|
|
8
|
+
RESULTS_FILE="$2"
|
|
9
|
+
|
|
10
|
+
RULES_DIR="$DIR/.agent/rules"
|
|
11
|
+
RULES_FILE="$RULES_DIR/image_dimensions.md"
|
|
12
|
+
|
|
13
|
+
mkdir -p "$RULES_DIR"
|
|
14
|
+
|
|
15
|
+
cat << 'EOF' > "$RULES_FILE"
|
|
16
|
+
# Codebase Remote Images
|
|
17
|
+
|
|
18
|
+
> [!NOTE]
|
|
19
|
+
> This file is strictly auto-generated by `imgstat`.
|
|
20
|
+
> It maps remote image URLs found in the codebase to their exact physical dimensions.
|
|
21
|
+
> AI assistants should use this dictionary when asked about layout constraints, native sizes, or aspect ratios of referenced images.
|
|
22
|
+
|
|
23
|
+
| Documented URL | Detected Size (W x H) |
|
|
24
|
+
|---|---|
|
|
25
|
+
EOF
|
|
26
|
+
|
|
27
|
+
while IFS='|' read -r url w h; do
|
|
28
|
+
echo "| \`$url\` | **${w}x${h}** |" >> "$RULES_FILE"
|
|
29
|
+
done < "$RESULTS_FILE"
|
|
30
|
+
|
|
31
|
+
echo "Wrote generic rules to: $RULES_FILE"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Inputs
|
|
4
|
+
# $1: Directory path
|
|
5
|
+
# $2: Temp file containing results in format: url|width|height
|
|
6
|
+
|
|
7
|
+
DIR="$1"
|
|
8
|
+
RESULTS_FILE="$2"
|
|
9
|
+
RULES_FILE="$DIR/CLAUDE.md"
|
|
10
|
+
|
|
11
|
+
TEMP_BLOCK=$(mktemp)
|
|
12
|
+
|
|
13
|
+
cat << 'EOF' > "$TEMP_BLOCK"
|
|
14
|
+
## image dimensions
|
|
15
|
+
|
|
16
|
+
generated by imgstat. run `npx imgstat` to regenerate.
|
|
17
|
+
|
|
18
|
+
never guess image sizes. use the table below.
|
|
19
|
+
|
|
20
|
+
| file | width | height |
|
|
21
|
+
|------|-------|--------|
|
|
22
|
+
EOF
|
|
23
|
+
|
|
24
|
+
while IFS='|' read -r url w h; do
|
|
25
|
+
echo "| $url | $w | $h |" >> "$TEMP_BLOCK"
|
|
26
|
+
done < "$RESULTS_FILE"
|
|
27
|
+
|
|
28
|
+
# Appending / Replacing logic
|
|
29
|
+
if [[ -f "$RULES_FILE" ]] && grep -q "## image dimensions" "$RULES_FILE"; then
|
|
30
|
+
# Block exists. Let's delete it.
|
|
31
|
+
sed -i.bak '/## image dimensions/,$d' "$RULES_FILE"
|
|
32
|
+
rm -f "${RULES_FILE}.bak"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [[ -f "$RULES_FILE" ]]; then
|
|
36
|
+
echo "" >> "$RULES_FILE"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
cat "$TEMP_BLOCK" >> "$RULES_FILE"
|
|
40
|
+
rm -f "$TEMP_BLOCK"
|
|
41
|
+
|
|
42
|
+
echo "Wrote claude code rules to: $RULES_FILE"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Inputs
|
|
4
|
+
# $1: Directory path
|
|
5
|
+
# $2: Temp file containing results in format: url|width|height
|
|
6
|
+
|
|
7
|
+
DIR="$1"
|
|
8
|
+
RESULTS_FILE="$2"
|
|
9
|
+
|
|
10
|
+
RULES_DIR="$DIR/.cursor/rules"
|
|
11
|
+
RULES_FILE="$RULES_DIR/image_dimensions.mdc"
|
|
12
|
+
|
|
13
|
+
mkdir -p "$RULES_DIR"
|
|
14
|
+
|
|
15
|
+
cat << 'EOF' > "$RULES_FILE"
|
|
16
|
+
---
|
|
17
|
+
description: image dimension context for all assets in this project
|
|
18
|
+
alwaysApply: true
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
when working with images in this project, always refer to this file.
|
|
22
|
+
never guess dimensions. never use vision tokens to infer size.
|
|
23
|
+
|
|
24
|
+
| file | width | height |
|
|
25
|
+
|------|-------|--------|
|
|
26
|
+
EOF
|
|
27
|
+
|
|
28
|
+
while IFS='|' read -r url w h; do
|
|
29
|
+
echo "| $url | $w | $h |" >> "$RULES_FILE"
|
|
30
|
+
done < "$RESULTS_FILE"
|
|
31
|
+
|
|
32
|
+
echo "Wrote cursor rules to: $RULES_FILE"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Inputs
|
|
4
|
+
# $1: Directory path
|
|
5
|
+
# $2: Temp file containing results in format: url|width|height
|
|
6
|
+
|
|
7
|
+
DIR="$1"
|
|
8
|
+
RESULTS_FILE="$2"
|
|
9
|
+
RULES_FILE="$DIR/.windsurfrules"
|
|
10
|
+
|
|
11
|
+
TEMP_BLOCK=$(mktemp)
|
|
12
|
+
|
|
13
|
+
cat << 'EOF' > "$TEMP_BLOCK"
|
|
14
|
+
# imgstat — image dimensions
|
|
15
|
+
# generated by imgstat. do not edit this block manually.
|
|
16
|
+
# run `npx imgstat` to regenerate.
|
|
17
|
+
|
|
18
|
+
when working with images, never guess dimensions. refer to the table below.
|
|
19
|
+
|
|
20
|
+
| file | width | height |
|
|
21
|
+
|------|-------|--------|
|
|
22
|
+
EOF
|
|
23
|
+
|
|
24
|
+
while IFS='|' read -r url w h; do
|
|
25
|
+
echo "| $url | $w | $h |" >> "$TEMP_BLOCK"
|
|
26
|
+
done < "$RESULTS_FILE"
|
|
27
|
+
|
|
28
|
+
# Appending / Replacing logic
|
|
29
|
+
if [[ -f "$RULES_FILE" ]] && grep -q "# imgstat — image dimensions" "$RULES_FILE"; then
|
|
30
|
+
# Block exists, let's remove it and everything after it (assuming block is at the bottom)
|
|
31
|
+
# Actually, safer to sed replace everything from the start tag until the end of file.
|
|
32
|
+
# But the instructions say "append a clearly delimited block at the bottom".
|
|
33
|
+
# If it exists, replace only that block.
|
|
34
|
+
# Let's assume the block starts at "# imgstat — image dimensions" and continues to EOF.
|
|
35
|
+
sed -i.bak '/# imgstat — image dimensions/,$d' "$RULES_FILE"
|
|
36
|
+
rm -f "${RULES_FILE}.bak"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
if [[ -f "$RULES_FILE" ]]; then
|
|
40
|
+
# Ensure there's a newline before appending
|
|
41
|
+
echo "" >> "$RULES_FILE"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
cat "$TEMP_BLOCK" >> "$RULES_FILE"
|
|
45
|
+
rm -f "$TEMP_BLOCK"
|
|
46
|
+
|
|
47
|
+
echo "Wrote windsurf rules to: $RULES_FILE"
|
package/package.json
CHANGED
package/build_deb.sh
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
PACKAGE_NAME="imagestat"
|
|
3
|
-
VERSION="1.0"
|
|
4
|
-
ARCH="all"
|
|
5
|
-
DEB_DIR="${PACKAGE_NAME}_${VERSION}_${ARCH}"
|
|
6
|
-
|
|
7
|
-
echo "Building .deb package for $PACKAGE_NAME..."
|
|
8
|
-
|
|
9
|
-
# Create directory structure
|
|
10
|
-
mkdir -p "$DEB_DIR/usr/local/bin"
|
|
11
|
-
mkdir -p "$DEB_DIR/DEBIAN"
|
|
12
|
-
|
|
13
|
-
# Determine source file (handle rename)
|
|
14
|
-
if [ -f "imagestat" ]; then
|
|
15
|
-
cp imagestat "$DEB_DIR/usr/local/bin/$PACKAGE_NAME"
|
|
16
|
-
elif [ -f "imgstat.sh" ]; then
|
|
17
|
-
cp imgstat.sh "$DEB_DIR/usr/local/bin/$PACKAGE_NAME"
|
|
18
|
-
else
|
|
19
|
-
echo "Error: Source script not found (looked for 'imagestat' and 'imgstat.sh')."
|
|
20
|
-
exit 1
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
chmod 755 "$DEB_DIR/usr/local/bin/$PACKAGE_NAME"
|
|
24
|
-
|
|
25
|
-
# Create control file
|
|
26
|
-
cat > "$DEB_DIR/DEBIAN/control" <<EOF
|
|
27
|
-
Package: $PACKAGE_NAME
|
|
28
|
-
Version: $VERSION
|
|
29
|
-
Section: utils
|
|
30
|
-
Priority: optional
|
|
31
|
-
Architecture: $ARCH
|
|
32
|
-
Allowed-Architectures: all
|
|
33
|
-
Maintainer: User <user@example.com>
|
|
34
|
-
Depends: imagemagick, wget
|
|
35
|
-
Description: Image dimensions scanner and renamer
|
|
36
|
-
Recursively scans directories for images and renames them to include their
|
|
37
|
-
dimensions (e.g., image-800x600.jpg). Ignores heavy directories like node_modules.
|
|
38
|
-
EOF
|
|
39
|
-
|
|
40
|
-
# Build package
|
|
41
|
-
dpkg-deb --build "$DEB_DIR"
|
|
42
|
-
|
|
43
|
-
# Cleanup
|
|
44
|
-
mv "${DEB_DIR}.deb" "${PACKAGE_NAME}.deb" 2>/dev/null || true
|
|
45
|
-
rm -rf "$DEB_DIR"
|
|
46
|
-
|
|
47
|
-
echo "Build complete: ${PACKAGE_NAME}.deb"
|
|
48
|
-
echo "Install with: sudo apt install ./$PACKAGE_NAME.deb"
|
package/imagestat
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Function to display usage
|
|
4
|
-
usage() {
|
|
5
|
-
echo "Usage: imagestat [-u|--url <url>] [directory]"
|
|
6
|
-
echo " -u, --url <url> URL to download images from"
|
|
7
|
-
echo " directory Directory to scan (default: current directory)"
|
|
8
|
-
exit 1
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
# Parse arguments
|
|
12
|
-
URL=""
|
|
13
|
-
TARGET_DIR="."
|
|
14
|
-
|
|
15
|
-
while [[ "$#" -gt 0 ]]; do
|
|
16
|
-
case $1 in
|
|
17
|
-
-u|--url) URL="$2"; shift ;;
|
|
18
|
-
-*) echo "Unknown parameter passed: $1"; usage ;;
|
|
19
|
-
*) TARGET_DIR="$1" ;;
|
|
20
|
-
esac
|
|
21
|
-
shift
|
|
22
|
-
done
|
|
23
|
-
|
|
24
|
-
# Create target directory if it doesn't exist
|
|
25
|
-
if [ ! -d "$TARGET_DIR" ]; then
|
|
26
|
-
mkdir -p "$TARGET_DIR"
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
# Download images if URL is provided
|
|
30
|
-
# Download images if URL is provided
|
|
31
|
-
if [ -n "$URL" ]; then
|
|
32
|
-
echo "Downloading images from $URL to temp folder..."
|
|
33
|
-
TEMP_DIR=$(mktemp -d)
|
|
34
|
-
|
|
35
|
-
# Download with wget (no extension restriction to catch all images)
|
|
36
|
-
# -nd: no directories (flatten)
|
|
37
|
-
# -r: recursive (useful if URL is a directory, but works for single file too)
|
|
38
|
-
# -l 1: limit recursion depth to 1 just in case (optional, but safer)
|
|
39
|
-
# --no-parent: don't go up
|
|
40
|
-
wget -nd -H -P "$TEMP_DIR" -e robots=off --user-agent="Mozilla/5.0" "$URL" 2>/dev/null
|
|
41
|
-
|
|
42
|
-
echo "Processing downloaded files..."
|
|
43
|
-
shopt -s nullglob
|
|
44
|
-
for f in "$TEMP_DIR"/*; do
|
|
45
|
-
if [ -f "$f" ]; then
|
|
46
|
-
# Identify format and dimensions (take first frame for animated gifs etc)
|
|
47
|
-
# Use -ping to be faster? identification doesn't need full read usually
|
|
48
|
-
ID_OUTPUT=$(identify -format "%m %w %h" "$f[0]" 2>/dev/null)
|
|
49
|
-
|
|
50
|
-
if [ -n "$ID_OUTPUT" ]; then
|
|
51
|
-
read -r TYPE W H <<< "$ID_OUTPUT"
|
|
52
|
-
|
|
53
|
-
# Normalize extension
|
|
54
|
-
EXT=$(echo "$TYPE" | tr '[:upper:]' '[:lower:]')
|
|
55
|
-
case "$EXT" in
|
|
56
|
-
jpeg) EXT="jpg" ;;
|
|
57
|
-
esac
|
|
58
|
-
|
|
59
|
-
# Get clean basename (remove query params)
|
|
60
|
-
BASENAME=$(basename "$f")
|
|
61
|
-
CLEAN_NAME=$(echo "$BASENAME" | sed 's/[?=&].*//')
|
|
62
|
-
# Remove existing extension if it matches common ones
|
|
63
|
-
CLEAN_NAME="${CLEAN_NAME%.*}"
|
|
64
|
-
|
|
65
|
-
# Construct new filename
|
|
66
|
-
NEW_FILENAME="${CLEAN_NAME}-${W}x${H}.${EXT}"
|
|
67
|
-
NEW_PATH="$TARGET_DIR/$NEW_FILENAME"
|
|
68
|
-
|
|
69
|
-
# Move to target
|
|
70
|
-
mv -n "$f" "$NEW_PATH"
|
|
71
|
-
echo "Saved: $NEW_FILENAME ($W x $H)"
|
|
72
|
-
fi
|
|
73
|
-
fi
|
|
74
|
-
done
|
|
75
|
-
rm -rf "$TEMP_DIR"
|
|
76
|
-
echo "Download processing complete."
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# Export function so xargs can use it
|
|
80
|
-
process_image() {
|
|
81
|
-
IMG="$1"
|
|
82
|
-
|
|
83
|
-
# Get dimensions
|
|
84
|
-
DIMENSIONS=$(identify -format "%wx%h" "$IMG" 2>/dev/null)
|
|
85
|
-
|
|
86
|
-
if [ -z "$DIMENSIONS" ]; then
|
|
87
|
-
echo "Skipping (not an image or identify failed): $IMG"
|
|
88
|
-
return
|
|
89
|
-
fi
|
|
90
|
-
|
|
91
|
-
DIRNAME=$(dirname "$IMG")
|
|
92
|
-
BASENAME=$(basename "$IMG")
|
|
93
|
-
EXTENSION="${BASENAME##*.}"
|
|
94
|
-
FILENAME="${BASENAME%.*}"
|
|
95
|
-
|
|
96
|
-
# Normalize filename: lowercase, replace spaces/underscores with hyphens
|
|
97
|
-
NEW_FILENAME=$(echo "$FILENAME" | tr '[:upper:]' '[:lower:]' | sed 's/[ _]/-/g' | sed 's/-\{2,\}/-/g')
|
|
98
|
-
|
|
99
|
-
# Check if dimensions are already in the filename
|
|
100
|
-
if [[ "$NEW_FILENAME" != *"$DIMENSIONS"* ]]; then
|
|
101
|
-
NEW_FILENAME="${NEW_FILENAME}-${DIMENSIONS}"
|
|
102
|
-
fi
|
|
103
|
-
|
|
104
|
-
NEW_BASENAME="${NEW_FILENAME}.${EXTENSION}"
|
|
105
|
-
NEW_PATH="$DIRNAME/$NEW_BASENAME"
|
|
106
|
-
|
|
107
|
-
if [ "$IMG" != "$NEW_PATH" ]; then
|
|
108
|
-
mv "$IMG" "$NEW_PATH"
|
|
109
|
-
echo "Renamed: $IMG -> $NEW_PATH"
|
|
110
|
-
else
|
|
111
|
-
echo "No change: $IMG"
|
|
112
|
-
fi
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export -f process_image
|
|
116
|
-
|
|
117
|
-
# Find and process images
|
|
118
|
-
echo "Scanning for images in $TARGET_DIR..."
|
|
119
|
-
# Prune standard ignored directories
|
|
120
|
-
find "$TARGET_DIR" \
|
|
121
|
-
\( -type d -name ".git" -o -name "node_modules" -o -name "dist" -o -name "build" -o -name "vendor" -o -name ".next" -o -name "coverage" \) -prune \
|
|
122
|
-
-o -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.svg" \) -print0 | xargs -0 -P 4 -I {} bash -c 'process_image "$@"' _ {}
|
|
123
|
-
|
|
124
|
-
echo "Done."
|
package/install.sh
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
APP_NAME="imagestat"
|
|
4
|
-
INSTALL_DIR="/usr/local/bin"
|
|
5
|
-
TARGET_PATH="$INSTALL_DIR/$APP_NAME"
|
|
6
|
-
SOURCE_FILE=""
|
|
7
|
-
|
|
8
|
-
# Colors
|
|
9
|
-
GREEN='\033[0;32m'
|
|
10
|
-
RED='\033[0;31m'
|
|
11
|
-
YELLOW='\033[1;33m'
|
|
12
|
-
NC='\033[0m' # No Color
|
|
13
|
-
|
|
14
|
-
echo -e "${GREEN}Installing $APP_NAME...${NC}"
|
|
15
|
-
|
|
16
|
-
# Check sudo
|
|
17
|
-
if [ "$EUID" -ne 0 ]; then
|
|
18
|
-
echo -e "${YELLOW}Please run as root (sudo) to install globally.${NC}"
|
|
19
|
-
echo "Try: sudo ./install.sh"
|
|
20
|
-
exit 1
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
# Locate source file
|
|
24
|
-
if [ -f "imagestat" ]; then
|
|
25
|
-
SOURCE_FILE="imagestat"
|
|
26
|
-
elif [ -f "imgstat.sh" ]; then
|
|
27
|
-
SOURCE_FILE="imgstat.sh"
|
|
28
|
-
else
|
|
29
|
-
echo "Local script not found. Downloading from GitHub..."
|
|
30
|
-
REMOTE_URL="https://raw.githubusercontent.com/isaac0yen/imgstat/main/imagestat"
|
|
31
|
-
if command -v curl &> /dev/null; then
|
|
32
|
-
curl -fsSL "$REMOTE_URL" -o imagestat
|
|
33
|
-
elif command -v wget &> /dev/null; then
|
|
34
|
-
wget -q "$REMOTE_URL" -O imagestat
|
|
35
|
-
else
|
|
36
|
-
echo -e "${RED}Error: Neither curl nor wget found. Cannot download script.${NC}"
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
if [ ! -f "imagestat" ]; then
|
|
41
|
-
echo -e "${RED}Error: Failed to download script.${NC}"
|
|
42
|
-
exit 1
|
|
43
|
-
fi
|
|
44
|
-
SOURCE_FILE="imagestat"
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
# Check dependencies
|
|
48
|
-
MISSING_DEPS=0
|
|
49
|
-
if ! command -v identify &> /dev/null; then
|
|
50
|
-
echo -e "${RED}Error: 'identify' (ImageMagick) is not installed.${NC}"
|
|
51
|
-
MISSING_DEPS=1
|
|
52
|
-
fi
|
|
53
|
-
if ! command -v wget &> /dev/null; then
|
|
54
|
-
echo -e "${RED}Error: 'wget' is not installed.${NC}"
|
|
55
|
-
MISSING_DEPS=1
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
if [ $MISSING_DEPS -eq 1 ]; then
|
|
59
|
-
echo -e "${YELLOW}Please install missing dependencies first.${NC}"
|
|
60
|
-
exit 1
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
echo "Installing $SOURCE_FILE to $TARGET_PATH..."
|
|
64
|
-
cp "$SOURCE_FILE" "$TARGET_PATH"
|
|
65
|
-
chmod +x "$TARGET_PATH"
|
|
66
|
-
|
|
67
|
-
echo -e "${GREEN}Success! $APP_NAME has been installed.${NC}"
|
|
68
|
-
echo -e "Usage: ${GREEN}$APP_NAME [-u|--url <url>] [directory]${NC}"
|