<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged image-processing</title>
<link>https://coderlegion.com/tag/image-processing</link>
<description>Powered by Question2Answer</description>
<item>
<title>Validate AI Video Reference Images with Python Before Generation</title>
<link>https://coderlegion.com/32496/validate-ai-video-reference-images-with-python-before-generation</link>
<description>&lt;p&gt;A reference image can look perfectly fine in a browser and still cause problems in an AI video workflow.&lt;/p&gt;
&lt;p&gt;Perhaps a character portrait was accidentally exported at 320 × 320 pixels. Two reference files might contain exactly the same image under different filenames. Or a damaged image might still exist in the project folder even though it can no longer be opened properly.&lt;/p&gt;
&lt;p&gt;These are problems we can catch before sending anything to a video generation tool.&lt;/p&gt;
&lt;p&gt;In this tutorial, we'll build a small Python validator that checks image formats, dimensions, aspect ratios, file integrity, and duplicate content.&lt;/p&gt;
&lt;p&gt;We'll also generate test images to verify that the script actually works.&lt;/p&gt;
&lt;p&gt;The solution uses Pillow and Python's standard library. No API key or AI video service is required.&lt;/p&gt;
&lt;h3 id=&quot;1-why-validate-reference-images-&quot;&gt;1. Why Validate Reference Images?&lt;/h3&gt;
&lt;p&gt;Reference-guided video generation often involves several assets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Character portraits&lt;/li&gt;
&lt;li&gt;Product photographs&lt;/li&gt;
&lt;li&gt;Background images&lt;/li&gt;
&lt;li&gt;Visual style references&lt;/li&gt;
&lt;li&gt;Storyboard frames&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a project grows, these files may be renamed, resized, replaced, or duplicated.&lt;/p&gt;
&lt;p&gt;A basic validation step can catch some of these mistakes before generation begins.&lt;/p&gt;
&lt;p&gt;For this example, our validator will check five things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Whether the image uses a supported format.&lt;/li&gt;
&lt;li&gt;Whether it can be opened and decoded.&lt;/li&gt;
&lt;li&gt;Whether its dimensions meet a configurable minimum.&lt;/li&gt;
&lt;li&gt;Whether its aspect ratio matches an optional requirement.&lt;/li&gt;
&lt;li&gt;Whether another file has identical contents.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These checks do not guarantee better AI video output. They simply help ensure the input files meet a known set of requirements.&lt;/p&gt;
&lt;h3 id=&quot;2-set-up-the-project&quot;&gt;2. Set Up the Project&lt;/h3&gt;
&lt;p&gt;Install Pillow:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python -m pip install Pillow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the following project structure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;video-project/
├── references/
├── check_references.py
└── make_test_images.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We'll first create the validator, then generate several images to test it.&lt;/p&gt;
&lt;h3 id=&quot;3-build-the-image-validator&quot;&gt;3. Build the Image Validator&lt;/h3&gt;
&lt;p&gt;Create &lt;code&gt;check_references.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import argparse
import hashlib
import json
import warnings
from pathlib import Path

from PIL import Image, UnidentifiedImageError

ALLOWED = {
    &quot;.png&quot;: &quot;PNG&quot;,
    &quot;.jpg&quot;: &quot;JPEG&quot;,
    &quot;.jpeg&quot;: &quot;JPEG&quot;,
    &quot;.webp&quot;: &quot;WEBP&quot;,
}


def fingerprint(path):
    h = hashlib.sha256()

    with path.open(&quot;rb&quot;) as fh:
        for chunk in iter(
            lambda: fh.read(1024 * 1024), b&quot;&quot;
        ):
            h.update(chunk)

    return h.hexdigest()


def inspect(path, minimum, ratio):
    errors = []

    try:
        expected = ALLOWED.get(
            path.suffix.lower()
        )

        if expected is None:
            return {
                &quot;file&quot;: path.name,
                &quot;errors&quot;: [&quot;Unsupported extension&quot;],
            }

        # Check file structure and decode image data.
        with warnings.catch_warnings():
            warnings.simplefilter(
                &quot;error&quot;,
                Image.DecompressionBombWarning
            )

            with Image.open(path) as image:
                actual = image.format
                width, height = image.size
                image.verify()

            # Reopen after verify() for decoding.
            with Image.open(path) as image:
                image.load()

        if actual != expected:
            errors.append(
                f&quot;Extension/format mismatch: {actual}&quot;
            )

        if min(width, height) &amp;lt; minimum:
            errors.append(
                f&quot;Too small: {width}x{height}&quot;
            )

        if ratio is not None:
            actual_ratio = width / height

            if abs(actual_ratio - ratio) &amp;gt; 0.03:
                errors.append(
                    f&quot;Unexpected ratio: {actual_ratio:.3f}&quot;
                )

        return {
            &quot;file&quot;: path.name,
            &quot;size&quot;: [width, height],
            &quot;sha256&quot;: fingerprint(path),
            &quot;errors&quot;: errors,
        }

    except (
        OSError,
        ValueError,
        UnidentifiedImageError,
        Image.DecompressionBombError,
        Image.DecompressionBombWarning,
    ) as exc:
        return {
            &quot;file&quot;: path.name,
            &quot;errors&quot;: [f&quot;Unreadable image: {exc}&quot;],
        }


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument(
        &quot;directory&quot;,
        type=Path
    )

    parser.add_argument(
        &quot;--min-side&quot;,
        type=int,
        default=512
    )

    parser.add_argument(
        &quot;--ratio&quot;,
        type=float
    )

    args = parser.parse_args()

    if (
        args.min_side &amp;lt; 1
        or (
            args.ratio is not None
            and args.ratio &amp;lt;= 0
        )
    ):
        parser.error(&quot;Invalid size or ratio&quot;)

    if not args.directory.is_dir():
        parser.error(&quot;Directory not found&quot;)

    paths = sorted(
        path
        for path in args.directory.iterdir()
        if path.is_file()
    )

    if not paths:
        parser.error(&quot;Directory is empty&quot;)

    seen = {}
    results = []

    for path in paths:
        item = inspect(
            path,
            args.min_side,
            args.ratio
        )

        digest = item.get(&quot;sha256&quot;)

        if digest:
            if digest in seen:
                item[&quot;errors&quot;].append(
                    f&quot;Byte-identical to {seen[digest]}&quot;
                )
            else:
                seen[digest] = path.name

        results.append(item)

    print(json.dumps(results, indent=2))

    return (
        1 if any(item[&quot;errors&quot;] for item in results)
        else 0
    )


if __name__ == &quot;__main__&quot;:
    raise SystemExit(main())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script processes each file in the selected directory and generates a JSON report.&lt;/p&gt;
&lt;p&gt;It returns exit code &lt;code&gt;0&lt;/code&gt; when every file passes, or &lt;code&gt;1&lt;/code&gt; when one or more files fail.&lt;/p&gt;
&lt;p&gt;That makes it usable in local scripts and automated pipelines.&lt;/p&gt;
&lt;h3 id=&quot;4-generate-test-images&quot;&gt;4. Generate Test Images&lt;/h3&gt;
&lt;p&gt;We should not assume the validator works just because the code runs.&lt;/p&gt;
&lt;p&gt;Let's create files that exercise its main checks.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;make_test_images.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pathlib import Path
from shutil import copyfile

from PIL import Image

folder = Path(&quot;references&quot;)
folder.mkdir(exist_ok=True)

# A valid image.
Image.new(
    &quot;RGB&quot;,
    (1024, 1024),
    &quot;white&quot;
).save(folder / &quot;valid.png&quot;)

# An undersized image.
Image.new(
    &quot;RGB&quot;,
    (320, 320),
    &quot;red&quot;
).save(folder / &quot;small.png&quot;)

# A byte-identical duplicate.
copyfile(
    folder / &quot;valid.png&quot;,
    folder / &quot;valid_copy.png&quot;
)

# A deliberately invalid image file.
(folder / &quot;broken.png&quot;).write_bytes(
    b&quot;not a real image&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python make_test_images.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;references&lt;/code&gt; directory should now contain four files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;references/
├── valid.png
├── valid_copy.png
├── small.png
└── broken.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These test assets allow us to check several error conditions without downloading external images.&lt;/p&gt;
&lt;h3 id=&quot;5-run-the-validator&quot;&gt;5. Run the Validator&lt;/h3&gt;
&lt;p&gt;Execute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python check_references.py references
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The validator should identify:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;File &lt;/th&gt;&lt;th&gt;Expected result&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;valid.png&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Valid size and format&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;valid_copy.png&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Exact duplicate detected&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;small.png&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Too small: 320x320&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;broken.png&lt;/code&gt; &lt;/td&gt;&lt;td&gt;Unreadable image&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The duplicate may be reported against either filename, depending on the order in which the files are processed.&lt;/p&gt;
&lt;h4 id=&quot;what-happens-when-everything-is-valid-&quot;&gt;What happens when everything is valid?&lt;/h4&gt;
&lt;p&gt;Remove the broken, small, and duplicate files, leaving only &lt;code&gt;valid.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run the validator again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python check_references.py references
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result should contain an empty &lt;code&gt;errors&lt;/code&gt; list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;file&quot;: &quot;valid.png&quot;,
  &quot;size&quot;: [1024, 1024],
  &quot;sha256&quot;: &quot;...&quot;,
  &quot;errors&quot;: []
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The SHA-256 value is abbreviated here for readability. The actual script prints the complete hash.&lt;/p&gt;
&lt;p&gt;The process should also exit successfully.&lt;/p&gt;
&lt;h4 id=&quot;test-a-custom-minimum-size&quot;&gt;Test a custom minimum size&lt;/h4&gt;
&lt;p&gt;You can change the minimum dimensions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python check_references.py references --min-side 768
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This requires both dimensions to be at least 768 pixels.&lt;/p&gt;
&lt;p&gt;It is a project-level rule, not a universal requirement imposed by AI video models.&lt;/p&gt;
&lt;p&gt;A character portrait and a wide landscape background may need different dimension policies.&lt;/p&gt;
&lt;h4 id=&quot;test-an-aspect-ratio&quot;&gt;Test an aspect ratio&lt;/h4&gt;
&lt;p&gt;For a project expecting roughly 16:9 images:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;python check_references.py references --ratio 1.777778
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script allows a difference of 0.03 between the actual and requested width-to-height ratios.&lt;/p&gt;
&lt;p&gt;This is useful for a consistent background-image set, but shouldn't automatically be applied to every reference image.&lt;/p&gt;
&lt;p&gt;Portraits, objects, and backgrounds often need different framing.&lt;/p&gt;
&lt;h3 id=&quot;6-why-use-sha-256-for-duplicate-detection-&quot;&gt;6. Why Use SHA-256 for Duplicate Detection?&lt;/h3&gt;
&lt;p&gt;The validator calculates a SHA-256 fingerprint for every successfully inspected image.&lt;/p&gt;
&lt;p&gt;If two files have identical bytes, their hashes match.&lt;/p&gt;
&lt;p&gt;This catches a common asset-management mistake: copying an image under another filename and accidentally including both files in a reference set.&lt;/p&gt;
&lt;p&gt;However, SHA-256 is not a visual similarity detector.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two identical files with different names will be detected.&lt;/li&gt;
&lt;li&gt;A JPEG recompressed with different settings will usually produce a different hash.&lt;/li&gt;
&lt;li&gt;An image with modified metadata may have a different hash.&lt;/li&gt;
&lt;li&gt;Two images showing the same subject at different resolutions will generally not match.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For visual similarity detection, teams would need a separate method such as perceptual hashing.&lt;/p&gt;
&lt;p&gt;The choice depends on the problem being solved.&lt;/p&gt;
&lt;p&gt;If the goal is to find exact duplicate files, SHA-256 is simple and reliable.&lt;/p&gt;
&lt;h3 id=&quot;7-use-validation-before-ai-video-generation&quot;&gt;7. Use Validation Before AI Video Generation&lt;/h3&gt;
&lt;p&gt;Reference-heavy video projects often use separate images to guide characters, environments, objects, and camera composition.&lt;/p&gt;
&lt;p&gt;Platforms such as &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.kling3ai.net/kling/kling-4&quot;&gt;Kling 4.0&lt;/a&gt; describe reference-guided generation and multi-keyframe controls, making reference preparation a relevant part of the workflow.&lt;/p&gt;
&lt;p&gt;The validator operates entirely on local files. It does not connect to Kling 4.0 or require a provider-specific API.&lt;/p&gt;
&lt;p&gt;It can detect invalid or duplicate files before upload, while actual reference limits, accepted formats, and model requirements must be confirmed through the selected service.&lt;/p&gt;
&lt;p&gt;A practical workflow might be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Collect reference images in a project directory.&lt;/li&gt;
&lt;li&gt;Validate file formats and dimensions.&lt;/li&gt;
&lt;li&gt;Identify duplicates and corrupted files.&lt;/li&gt;
&lt;li&gt;Review asset permissions.&lt;/li&gt;
&lt;li&gt;Upload only the approved references.&lt;/li&gt;
&lt;li&gt;Review the generated video for visual accuracy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Local validation reduces avoidable input problems, but it does not guarantee that a generated character or object will remain consistent.&lt;/p&gt;
&lt;h3 id=&quot;8-production-considerations&quot;&gt;8. Production Considerations&lt;/h3&gt;
&lt;p&gt;This validator is deliberately small.&lt;/p&gt;
&lt;p&gt;For a production asset pipeline, several additions may be useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EXIF orientation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Some photographs include orientation metadata that changes how they are displayed. The script checks stored image dimensions rather than applying EXIF-based rotation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File-size and pixel limits&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Large or malicious image files can consume significant memory during decoding. Production systems handling untrusted files should enforce resource limits and use isolated processing environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Different reference roles&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A character portrait, product image, and background scene should not necessarily share the same minimum dimensions or aspect-ratio rules.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset permissions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A technically valid reference is not automatically authorized for upload.&lt;/p&gt;
&lt;p&gt;Teams should confirm that they have permission to use customer photographs, internal screenshots, copyrighted artwork, and images of recognizable people.&lt;/p&gt;
&lt;p&gt;Removing private information does not necessarily make confidential business assets eligible for external processing.&lt;/p&gt;
&lt;p&gt;These issues matter just as much as file dimensions when a tool becomes part of a real production workflow.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;AI video generation involves creative uncertainty, but basic reference-file validation is predictable.&lt;/p&gt;
&lt;p&gt;Before using generation credits, a team can check whether its images are readable, large enough for the intended purpose, correctly formatted, and free of exact duplicates.&lt;/p&gt;
&lt;p&gt;The process does not guarantee better motion, perfect character continuity, or accurate generated details.&lt;/p&gt;
&lt;p&gt;It simply removes a few preventable mistakes before the creative work begins.&lt;/p&gt;
&lt;p&gt;For teams handling many reference files, that's a useful place to introduce a small amount of automation.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32496/validate-ai-video-reference-images-with-python-before-generation</guid>
<pubDate>Mon, 26 Oct 2026 10:47:37 +0000</pubDate>
</item>
<item>
<title>Our AI staging model sometimes moves the camera. Here is how to spot it, and how we catch it</title>
<link>https://coderlegion.com/32350/our-ai-staging-model-sometimes-moves-the-camera-here-is-how-to-spot-it-and-how-we-catch-it</link>
<description>&lt;p&gt;A virtual staging render is supposed to be the same photo with different furniture. Same walls, same windows, same door, and the same spot where the photographer stood. Most of the time the image model gives exactly that. Sometimes it does not.&lt;/p&gt;
&lt;p&gt;We run an AI virtual staging tool, and one of the quieter failures we deal with is this one: the model moves the camera.&lt;/p&gt;
&lt;h3 id=&quot;what-it-looks-like&quot;&gt;What it looks like&lt;/h3&gt;
&lt;p&gt;It is rarely dramatic. On its own the render looks great. The sofa is nice, the light is warm, nothing is melted or floating. Only when you put it next to the original do you notice that the room is being seen from a different place.&lt;/p&gt;
&lt;p&gt;The versions we see most often:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A step back.&lt;/strong&gt; A wardrobe that the photo cut off at the edge turns into a wall, and the view moves back behind it. Suddenly there is more room than the photographer ever captured.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Straightened up.&lt;/strong&gt; A bedroom shot from the corner comes back facing the bed square on, like a catalogue page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zoomed in.&lt;/strong&gt; The frame creeps toward the fireplace or the archway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a listing photo this matters. The picture is supposed to show the room a buyer will walk into. Some MLS rules go further and require an unstaged photo of the same view alongside the staged one. If the staged version was taken from somewhere else, the pair does not match, and anyone comparing them will see it.&lt;/p&gt;
&lt;h3 id=&quot;how-to-spot-it-by-eye&quot;&gt;How to spot it by eye&lt;/h3&gt;
&lt;p&gt;You do not need software for the obvious cases. Put the original and the render side by side and ignore the furniture. Look at the things furniture cannot change:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The line where the ceiling meets the walls.&lt;/strong&gt; It should sit in the same place in both images. If it is higher, lower or tilted differently, the camera moved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Window and door edges.&lt;/strong&gt; Check how far each one is from the edge of the frame. If a door that touched the left edge now has a strip of wall beside it, the view shifted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Whatever is cut off.&lt;/strong&gt; Anything the original cropped at the frame edge should be cropped at the same place.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If all three line up, the camera almost certainly stayed put, whatever happened to the sofa.&lt;/p&gt;
&lt;h3 id=&quot;why-we-could-not-just-ask-an-ai&quot;&gt;Why we could not just ask an AI&lt;/h3&gt;
&lt;p&gt;Our first idea was the obvious one. We already use a vision model to compare every render with its original and answer a fixed list of yes-or-no questions: is the window still there, is the door still a door, and so on. So we added one more question: is this the same viewpoint?&lt;/p&gt;
&lt;p&gt;It did not work. Renders shot from a visibly different spot kept passing, across three separate rounds of cases we had checked by hand. We tried laying the two images over each other at half strength and asking whether the walls looked doubled. Not reliable either. A stronger model later had the opposite habit and called good renders moved. Today its answers about the camera do not count for room photos at all.&lt;/p&gt;
&lt;h3 id=&quot;what-we-built-instead&quot;&gt;What we built instead&lt;/h3&gt;
&lt;p&gt;So we measure it, much the way you would by eye, with two plain checks.&lt;/p&gt;
&lt;p&gt;The first one traces the line where the walls meet the ceiling across the whole width of the photo and compares the two lines. Furniture rarely reaches the ceiling, so that line should not change. Its weak spot is decoration: a dark beam or a picture hung high can pull the traced line off course.&lt;/p&gt;
&lt;p&gt;The second one estimates how far away the back wall is, column by column, in the upper part of the image, and compares the two results. Its weak spot is glass. Windows and mirrors are read differently every time.&lt;/p&gt;
&lt;p&gt;The useful part is that the two weak spots rarely meet. A picture on the wall does not change depth, and glass does not move the ceiling line. So a render is flagged only when both checks agree that the camera moved. On our hand-labelled set of 24 pairs, that caught all 5 moved renders with no false alarms. The margin was thin, so borderline scores are only logged and never fail a render.&lt;/p&gt;
&lt;p&gt;A flagged render is rejected the same way as one with a missing door, and the pipeline makes another attempt. If the check itself breaks or runs slow, the render is judged by the other checks instead of being held up.&lt;/p&gt;
&lt;h3 id=&quot;what-it-still-gets-wrong&quot;&gt;What it still gets wrong&lt;/h3&gt;
&lt;p&gt;Three things, and we would rather name them than hide them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Decoration and glass in the same room.&lt;/strong&gt; A towel rail next to a glass shower. A picture shelf beside a full-height window. Both checks get fooled a little at the same time, and a render is flagged even though the camera held still.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A turn under a flat ceiling.&lt;/strong&gt; If the camera only turns and the ceiling is flat, the ceiling line barely changes, the first check stays quiet, and the render slips through. A bedroom straightened to face the bed is the usual case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A straight step back.&lt;/strong&gt; This one showed up in October on close-up, cluttered photos. Both checks look at where things sit across the frame, not at how big they look, so a pure pull-back hardly registers. On 20 hard photos the check caught 2 of 5 bad frames and missed 3, all of them pull-backs. A simple scale comparison caught 2 of those 3, but it also raised false alarms of its own, so it is not live yet.&lt;/p&gt;
&lt;h3 id=&quot;what-we-took-from-it&quot;&gt;What we took from it&lt;/h3&gt;
&lt;p&gt;A model that describes a room well is not the same as a model that can tell where the camera stood. For that one question, two boring measurements did better. They are not perfect, but they fail in ways we can name and test.&lt;/p&gt;
&lt;p&gt;If you are checking a staged photo yourself, the same habit works: skip the furniture and look at the ceiling line, the window edges and what is cut off at the frame. If you are buying, you can &lt;a rel=&quot;nofollow&quot; href=&quot;https://aifliproom.com/blog/what-buyers-can-demand-from-virtually-staged-listings&quot;&gt;ask for the unedited original of every staged photo&lt;/a&gt;. And if you are the one taking the picture, remember that close-up, cluttered shots are where the step-back problem showed up, so &lt;a rel=&quot;nofollow&quot; href=&quot;https://aifliproom.com/blog/how-to-photograph-rooms-for-virtual-staging&quot;&gt;shoot the room wide and level&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The full technical write-up, with the six approaches we tried, the calibration numbers and the bugs we hit in production, is &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/aifliproom/the-judge-said-the-camera-held-still-it-had-not-measuring-viewpoint-drift-in-ai-room-renders-4ac3&quot;&gt;on dev.to&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We build this at &lt;a rel=&quot;nofollow&quot; href=&quot;https://aifliproom.com&quot;&gt;AI Flip Room&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32350/our-ai-staging-model-sometimes-moves-the-camera-here-is-how-to-spot-it-and-how-we-catch-it</guid>
<pubDate>Sat, 24 Oct 2026 23:14:24 +0000</pubDate>
</item>
<item>
<title>Validate Image Enlargement at the Size Users Will Actually See</title>
<link>https://coderlegion.com/32167/validate-image-enlargement-at-the-size-users-will-actually-see</link>
<description>&lt;p&gt;Disclosure: I work on upscaleimg.org. These are practical quality checks, not measured performance claims about the service.&lt;/p&gt;
&lt;p&gt;An enlarged image can look impressive in a small preview and still fail when placed on a product page. More pixels are not the same thing as more reliable detail. A useful review checks both the output file and its intended display context.&lt;/p&gt;
&lt;h3 id=&quot;calculate-the-required-dimensions-first&quot;&gt;Calculate the required dimensions first&lt;/h3&gt;
&lt;p&gt;For a web image, start from the largest rendered width and the display density you want to support. A 600 CSS-pixel slot at 2x density calls for roughly 1200 image pixels across. That is a delivery target, not a guarantee of perceived sharpness.&lt;/p&gt;
&lt;p&gt;Choose an &lt;a rel=&quot;nofollow&quot; href=&quot;https://upscaleimg.org/&quot;&gt;upscale image&lt;/a&gt; workflow only after identifying the source dimensions and crop. Upscaling a wide photo does not solve the problem of needing a portrait composition.&lt;/p&gt;
&lt;h3 id=&quot;use-paired-comparisons&quot;&gt;Use paired comparisons&lt;/h3&gt;
&lt;p&gt;Keep the original and enlarged file. Compare them at the same display size, then inspect output pixels around text, faces, thin lines, and repeated patterns. Look for halos, invented texture, altered letters, and softened edges.&lt;/p&gt;
&lt;p&gt;Do not compare a zoomed original with a fit-to-window output and call the difference an accuracy improvement. Record the viewing scale and note which details changed.&lt;/p&gt;
&lt;h3 id=&quot;check-delivery-separately&quot;&gt;Check delivery separately&lt;/h3&gt;
&lt;p&gt;Record output width, height, format, byte size, and the intended slot. Generate appropriately sized delivery variants after approval rather than serving the largest download everywhere. Preserve the approved master so later compression changes can be reviewed independently.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://upscaleimg.org/&quot;&gt;Upscale Image&lt;/a&gt; provides browser-based enlargement and enhancement. The final review is still important when the image contains factual details such as product labels or diagrams. AI-created detail should not be treated as recovered evidence.&lt;/p&gt;
&lt;p&gt;For print, calculate pixels per inch using the final crop and physical size, then inspect a proof when practical. A resolution calculation alone cannot certify print quality.&lt;/p&gt;
&lt;p&gt;Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://upscaleimg.org/&quot;&gt;https://upscaleimg.org/&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32167/validate-image-enlargement-at-the-size-users-will-actually-see</guid>
<pubDate>Fri, 23 Oct 2026 16:37:50 +0000</pubDate>
</item>
<item>
<title>Should a Resized Image Export Need a Fresh Visual Review?</title>
<link>https://coderlegion.com/32193/should-a-resized-image-export-need-a-fresh-visual-review</link>
<description>&lt;p&gt;&lt;em&gt;Cover: an original AI-generated illustration of a hypothetical review/export workflow, not an actual product result.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A reviewer approves revision R-2 of an AI-edited property photo. The export step then creates a smaller JPEG for delivery.&lt;/p&gt;
&lt;p&gt;Where should the review boundary sit?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allow predetermined resizing/compression after approval, with a separate export record.&lt;/li&gt;
&lt;li&gt;Require a final visual check of every delivered file.&lt;/li&gt;
&lt;li&gt;Use both, with a stricter check when the transform changes the crop, label or visible content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The distinction I would test is whether the derivative merely changes encoding or changes what the client sees. Even a routine export can make a disclosure label unreadable.&lt;/p&gt;
&lt;p&gt;A file digest can identify the exact exported bytes, but it does not establish visual correctness. MDN explains the narrow role of a digest here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What rule has worked in your image or document pipeline, and which edge case made you change it?&lt;/p&gt;
&lt;p&gt;Context: I work on EstateAI content and SEO. This is a hypothetical workflow question, not a claim about its current implementation.&lt;/p&gt;
</description>
<category>Discussions</category>
<guid isPermaLink="true">https://coderlegion.com/32193/should-a-resized-image-export-need-a-fresh-visual-review</guid>
<pubDate>Fri, 23 Oct 2026 13:03:59 +0000</pubDate>
</item>
<item>
<title>A Regression Checklist for Prompt-Based Image Editing</title>
<link>https://coderlegion.com/32164/a-regression-checklist-for-prompt-based-image-editing</link>
<description>&lt;p&gt;Disclosure: I work on nanobanana-ai.org. The checklist below is a suggested evaluation method, not a published benchmark or a description of private model internals.&lt;/p&gt;
&lt;p&gt;Prompt edits are difficult to test because the expected output is not a single exact file. A byte-for-byte snapshot comparison will reject harmless variations while saying little about whether the important content survived.&lt;/p&gt;
&lt;h3 id=&quot;build-a-small-fixture-set&quot;&gt;Build a small fixture set&lt;/h3&gt;
&lt;p&gt;Choose images you have permission to use: a product with readable text, a portrait, an object with fine edges, and a scene with repeating texture. Keep the input files unchanged between evaluations. Record the selected model or mode, prompt, aspect ratio, and date when available.&lt;/p&gt;
&lt;p&gt;For a browser editor such as &lt;a rel=&quot;nofollow&quot; href=&quot;https://nanobanana-ai.org/&quot;&gt;nano banana&lt;/a&gt;, start with one narrow edit per fixture. Changing background, color, framing, and lighting in the same request makes a failure hard to diagnose.&lt;/p&gt;
&lt;h3 id=&quot;test-invariants-instead-of-identical-pixels&quot;&gt;Test invariants instead of identical pixels&lt;/h3&gt;
&lt;p&gt;For each fixture, define a short acceptance checklist. A product image might require the same package shape, legible original label, and no invented attachments. A portrait needs identity and expression review. A patterned surface needs checks for repeated seams and distorted perspective.&lt;/p&gt;
&lt;p&gt;Separate required checks from preferences. A more attractive result can still fail if it changes a product's identifying details. Log the failed check and keep the output that demonstrates it.&lt;/p&gt;
&lt;h3 id=&quot;compare-changes-fairly&quot;&gt;Compare changes fairly&lt;/h3&gt;
&lt;p&gt;When refining a prompt, keep the source and output format fixed. Repeat a small number of attempts if your budget permits, but report the number of runs and failures instead of presenting one selected image as typical performance.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://nanobanana-ai.org/&quot;&gt;Nano Banana AI&lt;/a&gt; provides image upload and text instructions in the browser. This article does not claim deterministic generation, guaranteed identity preservation, or an official relationship with a model vendor.&lt;/p&gt;
&lt;p&gt;A practical release rule is simple: generation creates a candidate; a separate review approves an asset.&lt;/p&gt;
&lt;p&gt;Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://nanobanana-ai.org/&quot;&gt;https://nanobanana-ai.org/&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32164/a-regression-checklist-for-prompt-based-image-editing</guid>
<pubDate>Fri, 23 Oct 2026 11:10:20 +0000</pubDate>
</item>
<item>
<title>Treat AI Photo Edits Like Changesets: A Practical Review Workflow</title>
<link>https://coderlegion.com/32163/treat-ai-photo-edits-like-changesets-a-practical-review-workflow</link>
<description>&lt;p&gt;Disclosure: I work on Photo Tea. This is a proposed review workflow, not a claim that the product implements the code or automatically preserves every detail.&lt;/p&gt;
&lt;p&gt;An image edit has two requirements: make the requested change and leave unrelated content alone. Checking only the first is how a clean background can hide a changed product label.&lt;/p&gt;
&lt;h3 id=&quot;write-a-small-change-contract&quot;&gt;Write a small change contract&lt;/h3&gt;
&lt;p&gt;Before opening an &lt;a rel=&quot;nofollow&quot; href=&quot;https://phototea.art/&quot;&gt;ai photo editor&lt;/a&gt;, record three fields: change, preserve, and reject. For a product shot, change might be the background; preserve might include packaging geometry and label text; reject might include invented accessories or new shadows crossing the label.&lt;/p&gt;
&lt;p&gt;Keep the original file. Give each attempt its own name rather than overwriting the last result. A useful record is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{&quot;asset&quot;:&quot;bottle-01&quot;,&quot;revision&quot;:2,&quot;change&quot;:&quot;light gray background&quot;,&quot;preserve&quot;:[&quot;label&quot;,&quot;cap shape&quot;],&quot;decision&quot;:&quot;needs-review&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an example record for your own process, not a Photo Tea API payload.&lt;/p&gt;
&lt;h3 id=&quot;inspect-the-change-and-the-invariants-separately&quot;&gt;Inspect the change and the invariants separately&lt;/h3&gt;
&lt;p&gt;First compare the full composition at the intended display size. Then inspect the label, silhouette, reflections, and contact shadow at full resolution. A successful background replacement does not compensate for an incorrect ingredient label.&lt;/p&gt;
&lt;p&gt;Record failures by region, not just as a score. “Cap became wider” gives the next prompt a concrete constraint; “looks bad” does not. Change one instruction per attempt so you can understand which change helped.&lt;/p&gt;
&lt;h3 id=&quot;keep-approval-outside-generation&quot;&gt;Keep approval outside generation&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://phototea.art/&quot;&gt;Photo Tea&lt;/a&gt; offers prompt-based photo editing. The final publishing decision should still be explicit: approved, rejected, or needs manual repair. File existence and image dimensions are useful automated checks, but neither proves product accuracy.&lt;/p&gt;
&lt;p&gt;Use only images you own or may edit, and check privacy requirements before uploading customer photos. For sensitive details, a conventional editor may be the better final step.&lt;/p&gt;
&lt;p&gt;Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://phototea.art/&quot;&gt;https://phototea.art/&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/32163/treat-ai-photo-edits-like-changesets-a-practical-review-workflow</guid>
<pubDate>Fri, 23 Oct 2026 11:10:04 +0000</pubDate>
</item>
<item>
<title>Why JPEG can blur colored text even at a high quality setting</title>
<link>https://coderlegion.com/31603/why-jpeg-can-blur-colored-text-even-at-a-high-quality-setting</link>
<description>&lt;p&gt;A JPEG export can leave a soft fringe around colored text even when the image keeps its original dimensions. Before pushing the quality slider higher, check whether the encoder is reducing the resolution of the color channels. That process is called chroma subsampling.&lt;/p&gt;
&lt;p&gt;Consider a small red label beside a gray button. Its edge has an abrupt color change. A cloudy sky usually has gentler transitions, so settings that suit that photograph may leave the label looking smeared.&lt;/p&gt;
&lt;h3 id=&quot;color-has-its-own-resolution&quot;&gt;Color has its own resolution&lt;/h3&gt;
&lt;p&gt;A common JPEG encoding path converts RGB into YCbCr. Y carries luma, a brightness-related signal; Cb and Cr carry color-difference information. Chroma subsampling reduces the spatial resolution of those color components. The decoded picture still has the same pixel dimensions.&lt;/p&gt;
&lt;p&gt;With 4:4:4, each color-difference component has a sample at every pixel position. With 4:2:2, each has half the horizontal resolution. With 4:2:0, each has half the horizontal and half the vertical resolution. For a conceptual 4-by-4 patch, that means 16 samples per chroma component at 4:4:4, compared with four at 4:2:0. These are sample counts, not predictions of compressed file size. The &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/src/turbojpeg.h&quot;&gt;TurboJPEG API documentation&lt;/a&gt; describes these sampling arrangements.&lt;/p&gt;
&lt;p&gt;When decoding a subsampled image, the decoder reconstructs color samples for the full output grid. A narrow colored stroke can acquire a softer edge in that reconstruction. Inspect the small labels directly: fitting the whole screenshot into a preview can conceal the damage.&lt;/p&gt;
&lt;h3 id=&quot;quality-and-subsampling-are-different-controls&quot;&gt;Quality and subsampling are different controls&lt;/h3&gt;
&lt;p&gt;In libjpeg-turbo's lossy JPEG encoder, the quality setting scales the quantization tables. Subsampling has its own control. Its &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/doc/usage.txt&quot;&gt;command-line documentation&lt;/a&gt; explains that quality 100 still allows losses from subsampling and rounding. A high quality value does not, by itself, establish that full chroma resolution was retained.&lt;/p&gt;
&lt;p&gt;An application may tie its quality slider to several encoder settings. Check the exporter you are using; the number 90 alone tells you too little to reproduce its output in another application.&lt;/p&gt;
&lt;h3 id=&quot;compare-exports-from-the-same-source&quot;&gt;Compare exports from the same source&lt;/h3&gt;
&lt;p&gt;Start with a screenshot containing small colored text. From that source, export two JPEG copies at identical dimensions and quality settings. Use 4:2:0 for one and 4:4:4 for the other if the encoder lets you choose. Put those settings in the filenames and keep a note of the encoder version. Someone checking your result should be able to recreate the exports.&lt;/p&gt;
&lt;p&gt;View the copies at a consistent image zoom, including 100%, then inspect an enlarged crop of the label. Keep any resizing out of this first comparison. Otherwise, a resizing filter adds another explanation for a soft edge. Compare the downloaded files, because a preview in an export dialog may be scaled differently.&lt;/p&gt;
&lt;p&gt;Treat this as an experiment to run on your own images. No benchmark measurements are reported here. If the two copies look alike, record that observation and investigate the other processing steps before attributing the problem to subsampling.&lt;/p&gt;
&lt;p&gt;I work on &lt;a rel=&quot;nofollow&quot; href=&quot;https://morphio.online/&quot;&gt;Morphio&lt;/a&gt;, which offers HEIC conversion tools. When deciding on an output format, I would include small colored labels in the visual checks if they are part of the image. The encoder controls described above are not a statement about which settings Morphio exposes.&lt;/p&gt;
&lt;h3 id=&quot;choose-a-format-for-the-content&quot;&gt;Choose a format for the content&lt;/h3&gt;
&lt;p&gt;For screenshots with text or diagrams, include PNG in the comparison. PNG compresses losslessly, so it can preserve the raster samples supplied to its encoder. It cannot restore details already lost in a previous JPEG export. MDN's &lt;a rel=&quot;nofollow&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types&quot;&gt;image format guide&lt;/a&gt; discusses PNG and JPEG in this context.&lt;/p&gt;
&lt;p&gt;If the destination requires JPEG, compare a 4:4:4 export with the subsampled copy. Other lossy encoding steps still affect both. Then inspect the image served by the destination page: an upload service may resize or recompress your file after you send it.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/31603/why-jpeg-can-blur-colored-text-even-at-a-high-quality-setting</guid>
<pubDate>Sun, 18 Oct 2026 11:12:46 +0000</pubDate>
</item>
<item>
<title>Canvas cropping: keep source pixels separate from output size</title>
<link>https://coderlegion.com/31492/canvas-cropping-keep-source-pixels-separate-from-output-size</link>
<description>&lt;p&gt;A crop box and an export size describe two different things. The crop box chooses pixels from the decoded source; the export size decides how many pixels to write. Keeping those numbers separate makes an image editor much easier to reason about.&lt;/p&gt;
&lt;h3 id=&quot;start-with-image-pixels-not-the-preview-rectangle&quot;&gt;Start with image pixels, not the preview rectangle&lt;/h3&gt;
&lt;p&gt;Suppose the decoded image is 320 × 240 pixels. You want the region beginning at &lt;code&gt;(40, 24)&lt;/code&gt;, with a width of 200 and a height of 160. That rectangle fits because &lt;code&gt;40 + 200 &amp;lt;= 320&lt;/code&gt; and &lt;code&gt;24 + 160 &amp;lt;= 240&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The preview might be displayed at half size. In that case, a pointer position of 20 CSS pixels from its left edge represents 40 source pixels. Convert pointer coordinates using the actual displayed image rectangle before storing the crop. If the image is letterboxed inside a larger container, use the image rectangle rather than the container, or subtract the padding first.&lt;/p&gt;
&lt;p&gt;For an image drawn without rotation, the conversion is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const sourceX = (pointerX - imageRect.left) * source.width / imageRect.width;
const sourceY = (pointerY - imageRect.top) * source.height / imageRect.height;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clamp the final rectangle to the source bounds and choose an explicit rounding rule. Do not let a partially outside selection silently become an unexpected export.&lt;/p&gt;
&lt;h3 id=&quot;pass-both-rectangles-to-canvas&quot;&gt;Pass both rectangles to Canvas&lt;/h3&gt;
&lt;p&gt;The nine-argument form of &lt;code&gt;drawImage&lt;/code&gt; keeps the two jobs visible. For that 200 × 160 crop, a 500 × 400 export preserves the 5:4 aspect ratio:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;canvas.width = 500;
canvas.height = 400;
ctx.drawImage(source, 40, 24, 200, 160, 0, 0, 500, 400);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first rectangle belongs to the source image. The second belongs to the destination canvas. Setting the canvas bitmap dimensions matters: changing only its CSS width changes the preview, not the exported pixel dimensions.&lt;/p&gt;
&lt;p&gt;Validate that the dimensions are positive and the crop fits the decoded image. Also apply a pixel budget before allocating a large canvas. A very long, narrow image and a square image can have the same pixel count but different side-length constraints, so check both.&lt;/p&gt;
&lt;h3 id=&quot;encode-the-result-then-inspect-it&quot;&gt;Encode the result, then inspect it&lt;/h3&gt;
&lt;p&gt;Export through &lt;code&gt;canvas.toBlob&lt;/code&gt;, handle a null result, and check the returned type. For PNG, the browser can preserve transparency. JPEG is useful when a photographic image needs a smaller raster file, but a quality setting does not change the crop geometry. When decoding an external URL, its cross-origin policy can affect whether the canvas is exportable; a local file selected by the user avoids that particular remote-origin workflow.&lt;/p&gt;
&lt;h3 id=&quot;keep-svg-tracing-as-a-separate-decision&quot;&gt;Keep SVG tracing as a separate decision&lt;/h3&gt;
&lt;p&gt;Resizing a raster image does not turn its pixels into vector paths. Tracing is another step, with choices about color detail and smoothing. For a flat-color motif, crop away irrelevant borders first, trace it, and compare the original and vector preview at more than one zoom level. Look at small gaps, corners and separate color regions before downloading.&lt;/p&gt;
&lt;p&gt;A useful no-setup way to explore that sequence is the &lt;a rel=&quot;nofollow&quot; href=&quot;https://jpgtosvg.io/image-editor/&quot;&gt;browser image workspace in JPG to SVG&lt;/a&gt;: crop or resize a local image, then send it to tracing without selecting the file again. Processing stays in the browser, and the SVG output contains paths. I help maintain the product.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/31492/canvas-cropping-keep-source-pixels-separate-from-output-size</guid>
<pubDate>Sat, 17 Oct 2026 06:37:13 +0000</pubDate>
</item>
<item>
<title>How to Upscale Images for the Web Without Over-Sharpening: An Upscayl Workflow</title>
<link>https://coderlegion.com/27784/how-to-upscale-images-for-the-web-without-over-sharpening-an-upscayl-workflow</link>
<description>&lt;p&gt;An image can have more pixels and still look worse. Enlarging a compressed photograph may produce crunchy edges, waxy skin, or invented texture. For a website or product page, the goal is not the largest possible file. It is an image that remains clear at its actual display size without misrepresenting the subject.&lt;/p&gt;
&lt;p&gt;This guide uses the browser-based &lt;a rel=&quot;nofollow&quot; href=&quot;https://upscayl.app/&quot;&gt;Upscayl image upscaler&lt;/a&gt; to explain a preparation, enhancement, and review workflow. The steps focus on decisions you can repeat with your own images, not unverified performance scores.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I am affiliated with upscayl.app. This article refers specifically to that website and its browser interface; it should not be read as a guide to similarly named desktop software. This is not an independent comparative review. Features and credit requirements depend on current settings and account access.&lt;/p&gt;
&lt;p&gt;Website: &lt;a rel=&quot;nofollow&quot; href=&quot;https://upscayl.app/&quot;&gt;https://upscayl.app/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-does-ai-image-upscaling-change-&quot;&gt;What Does AI Image Upscaling Change?&lt;/h3&gt;
&lt;p&gt;Ordinary resizing calculates additional pixels from existing ones. AI upscaling can also infer likely edges and textures from learned patterns. That can make an image look clearer, but inferred detail is not the same as recovered evidence.&lt;/p&gt;
&lt;p&gt;This distinction matters for product labels, faces, artwork, and historical photographs. An enhancement that makes a tiny serial number look readable might have changed its characters. A cleaner face might no longer preserve the person's precise features. Evaluate fidelity as well as visual appeal.&lt;/p&gt;
&lt;p&gt;Keep your original unchanged. Save enhanced copies under separate filenames so you can return to the source if a client questions a detail or if a later export requires different dimensions.&lt;/p&gt;
&lt;h3 id=&quot;how-much-larger-does-your-image-need-to-be-&quot;&gt;How Much Larger Does Your Image Need to Be?&lt;/h3&gt;
&lt;p&gt;Work backward from the layout. Suppose a photograph is displayed at 800 CSS pixels wide. A 1600-pixel-wide image can be a reasonable candidate for a high-density display, but the right delivery size also depends on responsive breakpoints, compression, and the user's device.&lt;/p&gt;
&lt;p&gt;If the source is 800 pixels wide, start by evaluating a 2x output rather than automatically requesting 8x. A larger scale multiplies storage and review costs without necessarily adding useful detail. It may also exaggerate artifacts already present in the input.&lt;/p&gt;
&lt;p&gt;For a product gallery, inspect the zoomed view as well as the thumbnail. A result that looks fine in a small card can look unnatural when a shopper opens the full image.&lt;/p&gt;
&lt;h3 id=&quot;how-to-prepare-a-source-image-before-uploading&quot;&gt;How to Prepare a Source Image Before Uploading&lt;/h3&gt;
&lt;p&gt;Choose the best available original, not a screenshot of a compressed social-media copy. Avoid repeated JPEG exports before enhancement: those exports discard information and can introduce edge artifacts that the model may amplify.&lt;/p&gt;
&lt;p&gt;Crop only when the destination genuinely requires it. If you need several layouts, preserve a larger master rather than permanently cutting away useful composition. Straighten obvious rotation where necessary so you can compare the source and output consistently.&lt;/p&gt;
&lt;p&gt;Use only images you own or have permission to process. For portraits or sensitive client material, review the website's current privacy and retention policies instead of assuming that a browser interface means all processing happens locally.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-the-current-upscayl-browser-interface&quot;&gt;How to Use the Current Upscayl Browser Interface&lt;/h3&gt;
&lt;p&gt;At the time of inspection, the upload panel listed JPG, PNG, WEBP, and ZIP input options, a per-file size limit, and a visible batch limit. It also offered modes such as Standard, Portrait, Anime / Art, Face Restore, and Scratch Restore, along with scaling and output-format controls. Check these values in your own session because account limits can differ.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Upload one representative image before committing an entire batch.&lt;/li&gt;
&lt;li&gt;Choose a mode that matches the image. Start with Standard for general photographs; test specialized modes only when they address a real problem.&lt;/li&gt;
&lt;li&gt;Select a modest scale that meets your delivery dimensions.&lt;/li&gt;
&lt;li&gt;Review the displayed credit cost and any optional face-enhancement setting.&lt;/li&gt;
&lt;li&gt;Generate the output, compare it against the original, and download only after inspecting important details.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For a batch, choose a test image with the hardest characteristics: fine hair, small lettering, repeated fabric texture, or compression damage. A setting that works on a simple background may fail on those details.&lt;/p&gt;
&lt;h3 id=&quot;standard-enhancement-vs-face-restoration-vs-artwork-modes&quot;&gt;Standard Enhancement vs Face Restoration vs Artwork Modes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;General enhancement&lt;/strong&gt; is a sensible starting point when the photograph already represents the subject well and mainly needs more usable pixels or clearer edges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Face restoration&lt;/strong&gt; is a more specialized decision. It can affect the appearance of facial details, so inspect eyes, teeth, skin texture, and identifying marks. For documentary or identity-sensitive use, a less dramatic result may be preferable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Artwork-oriented enhancement&lt;/strong&gt; should be judged on line continuity, edge cleanliness, color boundaries, and preservation of artistic intent. A mode that makes a photograph look detailed can add unwanted texture to flat-color illustration.&lt;/p&gt;
&lt;p&gt;These are selection principles, not claims that every mode will outperform another. Compare outputs at the same viewing size and keep a note of which mode produced each file.&lt;/p&gt;
&lt;h3 id=&quot;why-do-upscaled-images-sometimes-look-artificial-&quot;&gt;Why Do Upscaled Images Sometimes Look Artificial?&lt;/h3&gt;
&lt;p&gt;Over-sharpening often appears as bright or dark outlines around high-contrast edges. Excessive texture reconstruction can make smooth materials look rough. Strong facial processing can produce a polished but inaccurate face. Existing JPEG blocks can become more noticeable when enlarged.&lt;/p&gt;
&lt;p&gt;Review at both the intended display size and a one-to-one pixel view. The first answers whether the image works for the audience. The second helps locate artifacts. Neither view alone is sufficient: extreme zoom can make harmless issues look severe, while a small preview can hide meaningful errors.&lt;/p&gt;
&lt;p&gt;If the result is too aggressive, try a different mode, a smaller scale, or a better original. Do not keep upscaling previously enhanced copies in the hope that more passes will reliably recover the source.&lt;/p&gt;
&lt;h3 id=&quot;which-export-format-should-you-choose-&quot;&gt;Which Export Format Should You Choose?&lt;/h3&gt;
&lt;p&gt;The inspected interface offered JPG, PNG, and WEBP. Choose according to the destination rather than assuming one format is always superior.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JPG is useful for ordinary photographic delivery when lossy compression is acceptable.&lt;/li&gt;
&lt;li&gt;PNG is useful when a lossless workflow or supported transparency is needed, although file sizes can be larger. Selecting PNG does not itself remove a background.&lt;/li&gt;
&lt;li&gt;WEBP is useful for web delivery when supported by the destination and your content pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After using the &lt;a rel=&quot;nofollow&quot; href=&quot;https://upscayl.app/&quot;&gt;online AI image enhancer&lt;/a&gt;, treat web optimization as a separate step. Generate appropriately sized responsive variants and avoid sending a huge master image to every mobile visitor.&lt;/p&gt;
&lt;h3 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;can-upscaling-reliably-recover-unreadable-text-&quot;&gt;Can upscaling reliably recover unreadable text?&lt;/h4&gt;
&lt;p&gt;No. Small lettering can be altered or invented. For product labels, specifications, and legal text, obtain a higher-quality source or recreate the text from an authoritative original.&lt;/p&gt;
&lt;h4 id=&quot;should-every-image-use-the-same-settings-&quot;&gt;Should every image use the same settings?&lt;/h4&gt;
&lt;p&gt;Not necessarily. Group similar image types, test each group, and inspect representative results. Portraits, screenshots, product photography, and illustrations have different failure modes.&lt;/p&gt;
&lt;h4 id=&quot;is-the-largest-output-always-the-best-one-to-publish-&quot;&gt;Is the largest output always the best one to publish?&lt;/h4&gt;
&lt;p&gt;No. The best publishing asset balances clarity, fidelity, dimensions, and loading cost. Archive the master separately from the optimized website version.&lt;/p&gt;
&lt;h3 id=&quot;before-you-publish&quot;&gt;Before You Publish&lt;/h3&gt;
&lt;p&gt;Compare the result with the original, confirm no important feature has changed, test the image in the actual page layout, and check its file size. A useful enhancement preserves what matters while making the image easier to use. Bigger dimensions alone do not prove that you achieved that goal.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27784/how-to-upscale-images-for-the-web-without-over-sharpening-an-upscayl-workflow</guid>
<pubDate>Sun, 20 Sep 2026 05:36:35 +0000</pubDate>
</item>
<item>
<title>How to Compress, Resize, Convert, and Remove EXIF Data From Images Online</title>
<link>https://coderlegion.com/27649/how-to-compress-resize-convert-and-remove-exif-data-from-images-online</link>
<description>&lt;p&gt;Working with images usually sounds more complicated than it actually is. Most of the time, you don't need Photoshop or another large image editor. You just need to make an image smaller, change its dimensions, convert it to another format, or remove some information stored inside the file.&lt;/p&gt;
&lt;p&gt;The problem is that these jobs are often spread across different tools. You might find one website for compression, another for converting PNG to JPG, another for resizing, and another for checking image metadata.&lt;/p&gt;
&lt;p&gt;That's why having a collection of image utilities in one place is useful. Image Tools Kit is built around exactly that idea, with tools for image compression, conversion, resizing, metadata, privacy, and several other image-related tasks.&lt;/p&gt;
&lt;p&gt;Here is a practical look at how to handle some of the most common image tasks online.&lt;/p&gt;
&lt;p&gt;Compressing an Image Online&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/tools/compress-image/&quot;&gt;Image compression&lt;/a&gt; is one of the simplest ways to reduce the size of an image without changing its dimensions.&lt;/p&gt;
&lt;p&gt;For example, you might have a photograph that is 6 MB but only need to use it on a website. There's usually little reason to make visitors download the entire 6 MB file if a properly compressed version can look almost identical while being much smaller.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=13596080396401559320&quot; alt=&quot;&quot;&gt;&lt;br&gt;
An image compressor reduces the amount of data stored in the file. The amount of compression you should use depends on the image and where you're going to use it.&lt;/p&gt;
&lt;p&gt;For a website, moderate compression is usually a good starting point. You want the image to load quickly, but you also don't want obvious quality loss.&lt;/p&gt;
&lt;p&gt;You can use the Image Tools Kit image compressor to reduce the size of an image before uploading it to a website, sending it to someone, or storing it online.&lt;/p&gt;
&lt;p&gt;Image compression is particularly useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blog images&lt;/li&gt;
&lt;li&gt;Website photographs&lt;/li&gt;
&lt;li&gt;Product images&lt;/li&gt;
&lt;li&gt;Social media graphics&lt;/li&gt;
&lt;li&gt;Screenshots&lt;/li&gt;
&lt;li&gt;Large camera photos&lt;/li&gt;
&lt;li&gt;Images being uploaded to a CMS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One thing worth remembering is that smaller isn't always better. If you push compression too far, you can start seeing blurry details, blocky areas, and other artifacts. The goal is to find a reasonable balance between file size and image quality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/tools/compress-jpg/&quot;&gt;Compressing JPG Images&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;JPG, also written as JPEG, is one of the most common formats for photographs.&lt;/p&gt;
&lt;p&gt;A modern smartphone or camera can produce surprisingly large JPEG files, especially when the photo is taken at a high resolution. If you're uploading those images to a website, compressing them first can save both storage space and bandwidth.&lt;/p&gt;
&lt;p&gt;The Image Tools Kit JPG compressor can be used when you specifically want to optimize JPEG files.&lt;/p&gt;
&lt;p&gt;JPG compression is generally lossy, which means some image information is discarded during compression. This is why repeatedly compressing and saving the same JPEG isn't a great idea.&lt;/p&gt;
&lt;p&gt;It's better to keep the original photograph and create a compressed copy for the particular place where you're going to use it.&lt;/p&gt;
&lt;p&gt;For example, your original might remain untouched on your computer while a smaller version is created specifically for your website.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/tools/compress-png/&quot;&gt;Compressing PNG Images&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PNG is a different story.&lt;/p&gt;
&lt;p&gt;PNG is useful when you need transparency or want to preserve sharp graphics without the type of compression normally associated with JPEG. Logos, icons, screenshots, interface graphics, and illustrations are common examples.&lt;/p&gt;
&lt;p&gt;The downside is that PNG files can become quite large.&lt;/p&gt;
&lt;p&gt;If you have a PNG that is larger than it needs to be, you can use the Image Tools Kit PNG compressor to create a smaller version.&lt;/p&gt;
&lt;p&gt;However, don't assume that PNG is automatically the best format for every image. A photograph saved as PNG can be much larger than the same photograph saved as a properly compressed JPEG or WebP.&lt;/p&gt;
&lt;p&gt;The type of image matters.&lt;/p&gt;
&lt;p&gt;A transparent logo and a photograph have very different requirements, so choosing the format first and then optimizing the file usually makes more sense than simply compressing everything in the same way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/tools/resize-image/&quot;&gt;Resizing an Image Online&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Compression and resizing are often confused, but they solve two different problems.&lt;/p&gt;
&lt;p&gt;Compression reduces the amount of data in the file.&lt;/p&gt;
&lt;p&gt;Resizing changes the actual dimensions of the image.&lt;/p&gt;
&lt;p&gt;Imagine you have a photograph that is 6000 × 4000 pixels. That's a perfectly reasonable resolution for an original camera photo, but it may be excessive for a website that displays the image at around 1200 pixels wide.&lt;/p&gt;
&lt;p&gt;You could compress the 6000-pixel image, but you're still keeping millions of pixels that the visitor may never actually see.&lt;/p&gt;
&lt;p&gt;This is where an image resizer is useful.&lt;/p&gt;
&lt;p&gt;With the Image Tools Kit image resizer, you can create a version with dimensions that make more sense for its intended use.&lt;/p&gt;
&lt;p&gt;Resizing can be useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Website images&lt;/li&gt;
&lt;li&gt;Blog thumbnails&lt;/li&gt;
&lt;li&gt;Profile pictures&lt;/li&gt;
&lt;li&gt;Product photos&lt;/li&gt;
&lt;li&gt;Social media images&lt;/li&gt;
&lt;li&gt;Gallery previews&lt;/li&gt;
&lt;li&gt;Email attachments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you know the maximum size an image will actually be displayed at, resizing it to something close to that size can make a significant difference.&lt;/p&gt;
&lt;p&gt;For example, there isn't much benefit in uploading a 5000-pixel-wide photograph when the largest version on your website is only 1000 pixels wide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resizing Images for Websites&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;One of the easiest image optimization mistakes to avoid is uploading the original camera file directly to a website.&lt;/p&gt;
&lt;p&gt;A phone might produce a 4000 or 5000-pixel-wide photograph, while the website might display it inside a 1000-pixel-wide content area.&lt;/p&gt;
&lt;p&gt;The browser can scale the image down visually, but the visitor may still have to download the larger file.&lt;/p&gt;
&lt;p&gt;A better approach is to resize the image before uploading it.&lt;/p&gt;
&lt;p&gt;You can then compress the resized version as well.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;p&gt;Original:&lt;br&gt;
4000 × 3000 pixels&lt;br&gt;
5 MB&lt;/p&gt;
&lt;p&gt;After resizing:&lt;br&gt;
1600 × 1200 pixels&lt;br&gt;
1.2 MB&lt;/p&gt;
&lt;p&gt;After compression:&lt;br&gt;
1600 × 1200 pixels&lt;br&gt;
500 KB&lt;/p&gt;
&lt;p&gt;The exact numbers will vary depending on the image, but the basic idea is important: resizing and compression can work together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Creating Smaller Thumbnails&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thumbnails are another good example.&lt;/p&gt;
&lt;p&gt;A thumbnail doesn't need to contain the same amount of information as the original image. If you're displaying a small preview in a blog listing or gallery, downloading a full-resolution photograph just to display a small box is wasteful.&lt;/p&gt;
&lt;p&gt;An online thumbnail maker can create smaller versions for these situations.&lt;/p&gt;
&lt;p&gt;You can use the Image Tools Kit thumbnail tools when you need consistent smaller versions of images without opening a full image editor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/tools/image-converter/&quot;&gt;Converting Images Between Formats&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sometimes the image isn't too large. It's simply in the wrong format.&lt;/p&gt;
&lt;p&gt;Maybe you've received a PNG but need JPG. Maybe you're preparing images for a website and want WebP. Or perhaps an application you're using only accepts a particular file type.&lt;/p&gt;
&lt;p&gt;An online image converter makes these jobs straightforward.&lt;/p&gt;
&lt;p&gt;Image Tools Kit includes conversion tools for common image formats, including JPG, PNG, WebP, AVIF, GIF, and BMP.&lt;/p&gt;
&lt;p&gt;There is one important thing to understand about image conversion: changing formats doesn't automatically make an image smaller.&lt;/p&gt;
&lt;p&gt;For example, converting a JPEG photograph to PNG can actually make the file considerably larger.&lt;/p&gt;
&lt;p&gt;The best format depends on what the image contains and what you're using it for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Converting JPG to PNG&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PNG can be useful when you need transparency or lossless image storage.&lt;/p&gt;
&lt;p&gt;If you have a JPG that needs to be converted, the Image Tools Kit JPG to PNG converter can handle the format change without requiring a desktop image editor.&lt;/p&gt;
&lt;p&gt;This is useful when a particular application or workflow requires PNG.&lt;/p&gt;
&lt;p&gt;But if you're converting a photograph simply because you think PNG will always be smaller or better, there's usually no reason to do it. For ordinary photographs, JPEG or WebP may be a more practical choice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Converting PNG to JPG&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reverse situation is also common.&lt;/p&gt;
&lt;p&gt;You might have a PNG photograph or graphic that doesn't need transparency and want to create a JPG version.&lt;/p&gt;
&lt;p&gt;The Image Tools Kit PNG to JPG converter can be used for this.&lt;/p&gt;
&lt;p&gt;Remember that JPG doesn't support transparent backgrounds. If the original PNG has transparency, you'll need to account for that during the conversion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Converting Images to WebP&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;WebP has become a popular choice for websites because it can provide good image quality at relatively small file sizes.&lt;/p&gt;
&lt;p&gt;If you're working on a website, converting suitable images to WebP can be one option for reducing the amount of data browsers need to download.&lt;/p&gt;
&lt;p&gt;The Image Tools Kit WebP converter can be used when you need to create WebP versions of existing images.&lt;/p&gt;
&lt;p&gt;Whether WebP is the right choice depends on your website and the image itself, so it's worth checking the final result rather than converting everything automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Is EXIF Data?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;EXIF is something many people don't notice until they start looking into image privacy.&lt;/p&gt;
&lt;p&gt;EXIF stands for Exchangeable Image File Format. It refers to metadata stored inside image files.&lt;/p&gt;
&lt;p&gt;Depending on the device and software that created the image, EXIF data can contain information such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Camera manufacturer&lt;/li&gt;
&lt;li&gt;Camera model&lt;/li&gt;
&lt;li&gt;Lens information&lt;/li&gt;
&lt;li&gt;Date and time&lt;/li&gt;
&lt;li&gt;Exposure settings&lt;/li&gt;
&lt;li&gt;Image orientation&lt;/li&gt;
&lt;li&gt;Software information&lt;/li&gt;
&lt;li&gt;GPS coordinates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of this information isn't visible when you simply look at the photograph.&lt;/p&gt;
&lt;p&gt;You can have a perfectly normal-looking photo that contains additional information inside the file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How to View EXIF Metadata&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before removing metadata, you may want to see what's actually there.&lt;/p&gt;
&lt;p&gt;An EXIF viewer lets you inspect the information stored inside an image.&lt;/p&gt;
&lt;p&gt;The Image Tools Kit EXIF viewer can be useful when you want to check a photograph before publishing or sharing it.&lt;/p&gt;
&lt;p&gt;This is also useful when troubleshooting images. Sometimes metadata such as orientation information explains why an image appears rotated differently in different applications.&lt;/p&gt;
&lt;p&gt;For photographers, EXIF can be useful because it can contain camera and exposure information. For people sharing personal photographs, some of that information may not be necessary.&lt;/p&gt;
&lt;p&gt;Removing EXIF Data From Images&lt;/p&gt;
&lt;p&gt;If you don't need the metadata, you can remove it from the copy of the image you're going to share.&lt;/p&gt;
&lt;p&gt;An EXIF remover removes metadata from the file while keeping the actual visual image.&lt;/p&gt;
&lt;p&gt;You can use the Image Tools Kit EXIF remover when preparing photographs for a website, social media, forums, or other public places.&lt;/p&gt;
&lt;p&gt;This is particularly worth considering with photographs taken on smartphones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GPS Metadata and Image Privacy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GPS metadata deserves special attention because of the location information it can contain.&lt;/p&gt;
&lt;p&gt;If a phone records GPS coordinates when a photograph is taken, those coordinates can become part of the image's metadata.&lt;/p&gt;
&lt;p&gt;The photograph itself might not reveal where it was taken, but software that reads EXIF information could potentially extract the coordinates.&lt;/p&gt;
&lt;p&gt;That doesn't mean every smartphone photograph contains GPS information. It depends on the device, camera application, and settings.&lt;/p&gt;
&lt;p&gt;Still, if you're publishing personal photographs publicly, checking the metadata first is a sensible habit.&lt;/p&gt;
&lt;p&gt;Image Tools Kit also includes tools for removing GPS-related metadata if that's specifically what you're concerned about.&lt;/p&gt;
&lt;p&gt;Should You Remove EXIF From Every Image?&lt;/p&gt;
&lt;p&gt;Not necessarily.&lt;/p&gt;
&lt;p&gt;EXIF data isn't automatically bad.&lt;/p&gt;
&lt;p&gt;A photographer may want to keep information about the camera, lens, ISO, shutter speed, aperture, or date. That information can be useful for organizing a photography library or understanding how a photograph was taken.&lt;/p&gt;
&lt;p&gt;The decision really depends on what you're doing with the image.&lt;/p&gt;
&lt;p&gt;If you're maintaining an original photography archive, keeping the metadata can be useful.&lt;/p&gt;
&lt;p&gt;If you're posting a personal photograph publicly and have no reason to share its metadata, removing it makes more sense.&lt;/p&gt;
&lt;p&gt;A simple approach is to keep the original file and remove metadata only from copies that you're going to publish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Practical Image Optimization Workflow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For most website images, you don't need to use every image tool available. A simple workflow works well.&lt;/p&gt;
&lt;p&gt;Start by checking the image dimensions.&lt;/p&gt;
&lt;p&gt;If the image is much larger than the size you actually need, resize it first.&lt;/p&gt;
&lt;p&gt;Next, choose an appropriate format. Photographs often work well as JPEG or WebP, while graphics requiring transparency may be better suited to PNG or another format that supports transparency.&lt;/p&gt;
&lt;p&gt;After that, compress the image.&lt;/p&gt;
&lt;p&gt;If you're publishing a personal photograph, check the EXIF data before uploading it. If you don't need the metadata, remove it.&lt;/p&gt;
&lt;p&gt;Then upload the optimized copy to your website.&lt;/p&gt;
&lt;p&gt;Keeping the original file is a good idea because you can always create another optimized version later. Once you've heavily compressed or resized an image, you can't recover the original quality simply by reversing the process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Use Multiple Image Tools in One Place?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are plenty of websites that can compress an image, convert a JPG, or remove EXIF data.&lt;/p&gt;
&lt;p&gt;The annoying part is finding a different site every time you have a different job.&lt;/p&gt;
&lt;p&gt;One site handles compression. Another handles resizing. Another converts WebP. Another lets you inspect metadata.&lt;/p&gt;
&lt;p&gt;That's where a larger image toolkit becomes useful.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;Image Tools Kit&lt;/a&gt; puts these types of utilities together, so you can move from one image task to another without installing a large desktop application or searching for another tool every time.&lt;/p&gt;
&lt;p&gt;It isn't about needing a complicated tool for every image. In many cases, the opposite is true. You just want to open the right utility, do one job, and move on.&lt;/p&gt;
&lt;p&gt;For someone working on a website, preparing images for articles, managing photographs, or dealing with different file formats, having those basic utilities in one place can save a surprising amount of time.&lt;/p&gt;
&lt;p&gt;The next time you have an image that's too large, too big in dimensions, in the wrong format, or carrying metadata you don't want to publish, you don't necessarily need a full image editor.&lt;/p&gt;
&lt;p&gt;You can use the specific tool you need, whether that's an &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;image compressor&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;image resizer&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;image converter&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;EXIF viewer&lt;/a&gt;, or &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagetoolskit.wasmer.app/&quot;&gt;EXIF remover&lt;/a&gt;, and get the file ready for whatever you're using it for.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/27649/how-to-compress-resize-convert-and-remove-exif-data-from-images-online</guid>
<pubDate>Fri, 18 Sep 2026 15:06:25 +0000</pubDate>
</item>
<item>
<title>From Book-Cover Illustrator to Indie Developer: Maxim Mitenkov’s Journey of Building for His Own Pai</title>
<link>https://coderlegion.com/26821/from-book-cover-illustrator-indie-developer-maxim-mitenkovs-journey-building-for-his-own</link>
<description>&lt;h2 id=&quot;from-book-cover-illustrator-to-indie-developer-maxim-mitenkov-s-journey-of-building-for-his-own-pain&quot;&gt;From Book-Cover Illustrator to Indie Developer: Maxim Mitenkov’s Journey of Building for His Own Pain&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A CoderLegion Developer Story featuring &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/Maxim+Mitenkov&quot;&gt;Maxim Mitenkov&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interview conducted and edited by Mehadi Hasan, Community &amp;amp; Editorial Team at CoderLegion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;What happens when an illustrator gets tired of doing the same task over and over?&lt;/p&gt;
&lt;p&gt;You build a tool.&lt;/p&gt;
&lt;p&gt;For Maxim Mitenkov, that meant turning years of experience as a book-cover illustrator into a growing journey as an indie developer.&lt;/p&gt;
&lt;p&gt;Maxim has spent more than fifteen years working in design, primarily creating book covers and illustrations. But processing dozens of images every month — resizing, cropping, compressing, and converting them for different destinations — became a problem he couldn't ignore.&lt;/p&gt;
&lt;p&gt;The obvious solutions weren't good enough.&lt;/p&gt;
&lt;p&gt;Photoshop Actions broke when the source changed. Scripts became difficult to maintain. Cloud-based image processors created a privacy problem when the files belonged to clients and hadn't been published yet.&lt;/p&gt;
&lt;p&gt;So Maxim started building.&lt;/p&gt;
&lt;p&gt;Today, he is the solo founder of &lt;strong&gt;Image Pipeline&lt;/strong&gt;, a batch image processor that runs entirely in the browser.&lt;/p&gt;
&lt;p&gt;His journey combines software engineering, illustration, product development, privacy, and the realities of building an indie product around a problem he personally understands.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;from-computer-science-to-illustration-and-back-to-code&quot;&gt;From Computer Science to Illustration — and Back to Code&lt;/h3&gt;
&lt;p&gt;Maxim's relationship with technology didn't actually begin recently.&lt;/p&gt;
&lt;p&gt;He studied &lt;strong&gt;Computer Science and Radioelectronics at Belarusian State University of Informatics and Radioelectronics (BSUIR)&lt;/strong&gt; from 1993 to 1998, graduating as an Engineer.&lt;/p&gt;
&lt;p&gt;Professionally, however, his career developed around design.&lt;/p&gt;
&lt;p&gt;For more than fifteen years, he has worked as a book-cover illustrator, along with illustration and some branding work.&lt;/p&gt;
&lt;p&gt;The tools were familiar:&lt;/p&gt;
&lt;p&gt;Photoshop.&lt;/p&gt;
&lt;p&gt;Illustrator.&lt;/p&gt;
&lt;p&gt;A drawing tablet.&lt;/p&gt;
&lt;p&gt;The creative side of the work was what mattered.&lt;/p&gt;
&lt;p&gt;But there was another side to the job that was much less interesting.&lt;/p&gt;
&lt;p&gt;Every month, Maxim would prepare 50 to 100 images for portfolios, clients, Behance, Pinterest, and other destinations.&lt;/p&gt;
&lt;p&gt;Resize.&lt;/p&gt;
&lt;p&gt;Crop.&lt;/p&gt;
&lt;p&gt;Compress.&lt;/p&gt;
&lt;p&gt;Convert.&lt;/p&gt;
&lt;p&gt;Repeat.&lt;/p&gt;
&lt;p&gt;Every hour spent repeating those tasks was an hour that wasn't spent drawing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-problem-that-started-everything&quot;&gt;The Problem That Started Everything&lt;/h3&gt;
&lt;p&gt;The repetitive image-processing work eventually became too obvious to ignore.&lt;/p&gt;
&lt;p&gt;Photoshop Actions seemed like a solution, but they fell apart when clients supplied images with different aspect ratios.&lt;/p&gt;
&lt;p&gt;ImageMagick scripts worked, but only as long as Maxim remembered how they worked months later.&lt;/p&gt;
&lt;p&gt;Cloud converters created an even bigger problem.&lt;/p&gt;
&lt;p&gt;Client artwork could be unpublished or covered by an NDA.&lt;/p&gt;
&lt;p&gt;Uploading it to someone else's server simply wasn't something Maxim wanted to do.&lt;/p&gt;
&lt;p&gt;The problem was specific enough that he already knew what the product should look like:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Open a link, drag files in, hit a button, get a ZIP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No account.&lt;/p&gt;
&lt;p&gt;No upload.&lt;/p&gt;
&lt;p&gt;No subscription.&lt;/p&gt;
&lt;p&gt;That simple specification became Image Pipeline.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;becoming-a-developer-because-there-was-a-problem&quot;&gt;Becoming a Developer Because There Was a Problem&lt;/h3&gt;
&lt;p&gt;Maxim didn't originally set out to become a software developer.&lt;/p&gt;
&lt;p&gt;Instead, he realized that the person who could write the script was also the person who could build the interface around it.&lt;/p&gt;
&lt;p&gt;He started learning JavaScript.&lt;/p&gt;
&lt;p&gt;Then he moved to React when plain JavaScript started becoming limiting for what he wanted to build.&lt;/p&gt;
&lt;p&gt;Eventually, the code became a product.&lt;/p&gt;
&lt;p&gt;His transition wasn't driven by a career plan.&lt;/p&gt;
&lt;p&gt;It was driven by necessity.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I did not become a developer on purpose. I became one because there was a problem and nobody else was going to fix it.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That idea captures much of Maxim's approach to development.&lt;/p&gt;
&lt;p&gt;He isn't building software simply because software is interesting.&lt;/p&gt;
&lt;p&gt;He's building because he sees something that could work better.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-image-pipeline-runs-entirely-in-the-browser&quot;&gt;Why Image Pipeline Runs Entirely in the Browser&lt;/h3&gt;
&lt;p&gt;One of the most important decisions in Image Pipeline was privacy.&lt;/p&gt;
&lt;p&gt;Rather than processing images on a backend, Maxim designed the application so the work happens inside the browser.&lt;/p&gt;
&lt;p&gt;Resize.&lt;/p&gt;
&lt;p&gt;Filters.&lt;/p&gt;
&lt;p&gt;Format conversion.&lt;/p&gt;
&lt;p&gt;ZIP creation.&lt;/p&gt;
&lt;p&gt;All of it happens on the user's machine.&lt;/p&gt;
&lt;p&gt;There is no server receiving the images.&lt;/p&gt;
&lt;p&gt;There is no image-processing queue.&lt;/p&gt;
&lt;p&gt;There is no server-side image storage.&lt;/p&gt;
&lt;p&gt;The result is a privacy model based on architecture rather than marketing.&lt;/p&gt;
&lt;p&gt;Maxim describes the claim simply:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;I can't see your images.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's a powerful difference.&lt;/p&gt;
&lt;p&gt;The product doesn't need to promise that someone won't access your files.&lt;/p&gt;
&lt;p&gt;The files don't need to reach the server in the first place.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;building-for-yourself-has-an-advantage&quot;&gt;Building for Yourself Has an Advantage&lt;/h3&gt;
&lt;p&gt;Maxim was his own first user.&lt;/p&gt;
&lt;p&gt;That changed the way he built the product.&lt;/p&gt;
&lt;p&gt;He didn't need to survey users to decide which features were important in the beginning.&lt;/p&gt;
&lt;p&gt;He already knew what he repeatedly needed.&lt;/p&gt;
&lt;p&gt;Resize.&lt;/p&gt;
&lt;p&gt;Crop.&lt;/p&gt;
&lt;p&gt;Compress.&lt;/p&gt;
&lt;p&gt;Export.&lt;/p&gt;
&lt;p&gt;Those were the operations he performed constantly.&lt;/p&gt;
&lt;p&gt;But building for yourself also creates blind spots.&lt;/p&gt;
&lt;p&gt;Maxim discovered this after launching.&lt;/p&gt;
&lt;p&gt;His first public review on AlternativeTo was only two stars.&lt;/p&gt;
&lt;p&gt;The reviewer wanted brightness, contrast, and exposure controls. The preview was too small, and multiple export wasn't working.&lt;/p&gt;
&lt;p&gt;Some of those requirements had never occurred to Maxim.&lt;/p&gt;
&lt;p&gt;But the criticism was useful.&lt;/p&gt;
&lt;p&gt;He fixed the problems.&lt;/p&gt;
&lt;p&gt;The next review was five stars.&lt;/p&gt;
&lt;p&gt;That experience led to one of the clearest lessons from the project:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Your pain gets you version one. Other people's pain gets you everything after.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;launching-before-everything-was-perfect&quot;&gt;Launching Before Everything Was Perfect&lt;/h3&gt;
&lt;p&gt;Image Pipeline launched with nine nodes.&lt;/p&gt;
&lt;p&gt;There was no elaborate onboarding system.&lt;/p&gt;
&lt;p&gt;No extensive FAQ.&lt;/p&gt;
&lt;p&gt;No attempt to build every possible feature before allowing people to use it.&lt;/p&gt;
&lt;p&gt;Maxim wanted to find out whether anyone actually wanted the product.&lt;/p&gt;
&lt;p&gt;That decision quickly exposed several lessons.&lt;/p&gt;
&lt;h4 id=&quot;minimum-isn-t-readiness&quot;&gt;Minimum Isn't Readiness&lt;/h4&gt;
&lt;p&gt;The features Maxim personally needed weren't necessarily all the features other users expected.&lt;/p&gt;
&lt;p&gt;An image-processing application naturally creates expectations around things like brightness, contrast, and exposure.&lt;/p&gt;
&lt;p&gt;His own workflow had created a blind spot.&lt;/p&gt;
&lt;h4 id=&quot;preview-is-trust&quot;&gt;Preview Is Trust&lt;/h4&gt;
&lt;p&gt;The original preview wasn't good enough.&lt;/p&gt;
&lt;p&gt;Users needed to see what was going to happen before processing their images.&lt;/p&gt;
&lt;p&gt;Maxim rebuilt it with a larger live image, zoom functionality, and a before/after slider.&lt;/p&gt;
&lt;p&gt;The preview eventually became one of the strongest parts of the product.&lt;/p&gt;
&lt;h4 id=&quot;feedback-beats-planning&quot;&gt;Feedback Beats Planning&lt;/h4&gt;
&lt;p&gt;Users also requested ways to change the mood and feeling of images.&lt;/p&gt;
&lt;p&gt;Instead of spending weeks planning the feature, Maxim built an emotion filter in a couple of days.&lt;/p&gt;
&lt;p&gt;The experience reinforced another principle:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Launch early. The only expensive failure is launching late and finding out nobody wanted it.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-technical-choice-he-didn-t-make&quot;&gt;The Technical Choice He Didn't Make&lt;/h3&gt;
&lt;p&gt;One of the most interesting technical decisions in Image Pipeline was choosing &lt;strong&gt;not&lt;/strong&gt; to use WebAssembly.&lt;/p&gt;
&lt;p&gt;WASM seemed like the obvious answer.&lt;/p&gt;
&lt;p&gt;It's fast.&lt;/p&gt;
&lt;p&gt;It's powerful.&lt;/p&gt;
&lt;p&gt;It's designed for exactly the kind of computational work browsers increasingly need to perform.&lt;/p&gt;
&lt;p&gt;But Maxim wasn't optimizing for benchmarks alone.&lt;/p&gt;
&lt;p&gt;He wanted the application to open quickly, including on mobile devices.&lt;/p&gt;
&lt;p&gt;WebAssembly would introduce additional download size, build complexity, and compatibility concerns.&lt;/p&gt;
&lt;p&gt;So the image-processing core remained plain HTML5 Canvas code.&lt;/p&gt;
&lt;p&gt;The application processes pixel buffers directly through browser APIs.&lt;/p&gt;
&lt;p&gt;It may not be the fastest possible solution for enormous images.&lt;/p&gt;
&lt;p&gt;But Maxim's goal wasn't to win an artificial benchmark.&lt;/p&gt;
&lt;p&gt;It was to build something that solved the real problem efficiently.&lt;/p&gt;
&lt;p&gt;The engine stayed small and relatively boring.&lt;/p&gt;
&lt;p&gt;And that was exactly the point.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-react-flow-was-the-right-engineering-decision&quot;&gt;Why React Flow Was the Right Engineering Decision&lt;/h3&gt;
&lt;p&gt;The visual pipeline required a node-based interface.&lt;/p&gt;
&lt;p&gt;Maxim could have built the node editor himself.&lt;/p&gt;
&lt;p&gt;But that would have meant spending significant time solving problems that another project had already solved.&lt;/p&gt;
&lt;p&gt;Instead, he chose React Flow.&lt;/p&gt;
&lt;p&gt;It provided capabilities such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Drag and drop&lt;/li&gt;
&lt;li&gt;Connections&lt;/li&gt;
&lt;li&gt;Connection validation&lt;/li&gt;
&lt;li&gt;Zooming&lt;/li&gt;
&lt;li&gt;Node-based interaction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That choice saved development time.&lt;/p&gt;
&lt;p&gt;Rather than spending a month building and debugging a custom node canvas, Maxim could spend that time improving the actual product.&lt;/p&gt;
&lt;p&gt;For him, that was the better engineering decision.&lt;/p&gt;
&lt;p&gt;You don't prove that you're a good developer by rebuilding everything yourself.&lt;/p&gt;
&lt;p&gt;Sometimes the better engineering decision is knowing what &lt;strong&gt;not&lt;/strong&gt; to build.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;from-nine-nodes-to-a-growing-product&quot;&gt;From Nine Nodes to a Growing Product&lt;/h3&gt;
&lt;p&gt;Image Pipeline has grown significantly since its initial launch.&lt;/p&gt;
&lt;p&gt;Maxim's profile notes that he shipped &lt;strong&gt;14 node types in six weeks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The product has expanded with functionality including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blur and sharpen&lt;/li&gt;
&lt;li&gt;Denoise&lt;/li&gt;
&lt;li&gt;Watermarking&lt;/li&gt;
&lt;li&gt;Rotation&lt;/li&gt;
&lt;li&gt;Color temperature&lt;/li&gt;
&lt;li&gt;HSL adjustments&lt;/li&gt;
&lt;li&gt;Emotion filtering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern behind many of these features remains simple.&lt;/p&gt;
&lt;p&gt;Someone asks for something.&lt;/p&gt;
&lt;p&gt;Maxim considers whether the request makes sense.&lt;/p&gt;
&lt;p&gt;Then he builds it.&lt;/p&gt;
&lt;p&gt;The product is evolving through actual usage rather than through a huge feature roadmap designed in isolation.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;privacy-isn-t-just-a-checkbox&quot;&gt;Privacy Isn't Just a Checkbox&lt;/h3&gt;
&lt;p&gt;Maxim sees privacy as more than a feature of Image Pipeline.&lt;/p&gt;
&lt;p&gt;He believes the broader web is moving toward more client-side processing because users are becoming increasingly uncomfortable with uploading their data everywhere.&lt;/p&gt;
&lt;p&gt;Every service wants an account.&lt;/p&gt;
&lt;p&gt;Every signup form wants an email address.&lt;/p&gt;
&lt;p&gt;Every cloud-based tool requires some level of trust.&lt;/p&gt;
&lt;p&gt;Image Pipeline takes a different approach.&lt;/p&gt;
&lt;p&gt;If the processing can happen locally, why send the user's files somewhere else?&lt;/p&gt;
&lt;p&gt;For Maxim, privacy isn't a promise added after the architecture.&lt;/p&gt;
&lt;p&gt;It's part of the architecture itself.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;building-as-a-solo-founder&quot;&gt;Building as a Solo Founder&lt;/h3&gt;
&lt;p&gt;Maxim's development schedule doesn't look like a traditional software job.&lt;/p&gt;
&lt;p&gt;He describes it as switching.&lt;/p&gt;
&lt;p&gt;Mornings are for illustration.&lt;/p&gt;
&lt;p&gt;Days are for code.&lt;/p&gt;
&lt;p&gt;Evenings are often for testing.&lt;/p&gt;
&lt;p&gt;Image Pipeline was built in the gaps between paid illustration projects.&lt;/p&gt;
&lt;p&gt;A client finishes early.&lt;/p&gt;
&lt;p&gt;A day becomes available.&lt;/p&gt;
&lt;p&gt;Instead of waiting for the perfect schedule, Maxim uses the time to build.&lt;/p&gt;
&lt;p&gt;The hardest part isn't necessarily finding the hours.&lt;/p&gt;
&lt;p&gt;It's switching between two very different mental modes.&lt;/p&gt;
&lt;p&gt;Illustration is about emotion, composition, color, and visual judgment.&lt;/p&gt;
&lt;p&gt;Programming is about logic, behavior, and systems.&lt;/p&gt;
&lt;p&gt;Moving between the two takes time.&lt;/p&gt;
&lt;p&gt;Sometimes that transition requires a coffee.&lt;/p&gt;
&lt;p&gt;Sometimes a walk.&lt;/p&gt;
&lt;p&gt;Then it's back to the other world.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;how-design-influenced-his-code&quot;&gt;How Design Influenced His Code&lt;/h3&gt;
&lt;p&gt;Maxim's background in illustration naturally influences how he builds software.&lt;/p&gt;
&lt;p&gt;After spending years thinking about composition, color, typography, and visual communication, he can't simply ignore the interface.&lt;/p&gt;
&lt;p&gt;The nodes need to look good.&lt;/p&gt;
&lt;p&gt;Typography needs to be readable.&lt;/p&gt;
&lt;p&gt;The preview needs to communicate trust.&lt;/p&gt;
&lt;p&gt;Design isn't something that gets added at the end.&lt;/p&gt;
&lt;p&gt;It is part of the product.&lt;/p&gt;
&lt;p&gt;But the influence works in the opposite direction too.&lt;/p&gt;
&lt;p&gt;Programming changed the way Maxim thinks about design.&lt;/p&gt;
&lt;p&gt;Once you understand how software works, you start seeing pipelines everywhere.&lt;/p&gt;
&lt;p&gt;Illustration itself is a pipeline.&lt;/p&gt;
&lt;p&gt;Sketch.&lt;/p&gt;
&lt;p&gt;Line.&lt;/p&gt;
&lt;p&gt;Color.&lt;/p&gt;
&lt;p&gt;Light.&lt;/p&gt;
&lt;p&gt;Detail.&lt;/p&gt;
&lt;p&gt;Each stage takes an input and produces an output.&lt;/p&gt;
&lt;p&gt;Building software around workflows made Maxim more conscious of his own creative process as well.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-he-s-building-next&quot;&gt;What He's Building Next&lt;/h3&gt;
&lt;p&gt;Image Pipeline continues to evolve.&lt;/p&gt;
&lt;p&gt;The emotion filter is planned for another version, this time driven by real data rather than matrices manually tuned until they looked right.&lt;/p&gt;
&lt;p&gt;Maxim is also exploring &lt;strong&gt;Web Workers for client-side heavy lifting&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Outside the core product, he's thinking about another problem from his own workflow.&lt;/p&gt;
&lt;p&gt;Processing images is only one part of preparing a portfolio.&lt;/p&gt;
&lt;p&gt;Organizing, tagging, and exporting those images for different platforms is another task that still takes manual work.&lt;/p&gt;
&lt;p&gt;That has led him toward the idea of a portfolio preparation tool.&lt;/p&gt;
&lt;p&gt;Typography is another area he is interested in.&lt;/p&gt;
&lt;p&gt;After fighting with fonts every day, he suspects other designers have similar frustrations.&lt;/p&gt;
&lt;p&gt;The pattern remains the same.&lt;/p&gt;
&lt;p&gt;Find a problem.&lt;/p&gt;
&lt;p&gt;Understand it.&lt;/p&gt;
&lt;p&gt;Build something.&lt;/p&gt;
&lt;p&gt;Use it yourself.&lt;/p&gt;
&lt;p&gt;Then see whether the problem exists for other people too.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;building-from-0-to-revenue&quot;&gt;Building From 0 to Revenue&lt;/h3&gt;
&lt;p&gt;Maxim's profile describes his current focus as growing Image Pipeline from &lt;strong&gt;0 to revenue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The product has already passed several milestones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launched on Product Hunt&lt;/li&gt;
&lt;li&gt;Received a 5★ review on AlternativeTo&lt;/li&gt;
&lt;li&gt;Listed on Launch Llama&lt;/li&gt;
&lt;li&gt;Shipped 14 node types in six weeks&lt;/li&gt;
&lt;li&gt;Reached 46 passing tests&lt;/li&gt;
&lt;li&gt;Maintained zero backend image processing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But the product is still evolving.&lt;/p&gt;
&lt;p&gt;That's important because Maxim isn't presenting the journey as finished.&lt;/p&gt;
&lt;p&gt;He's still experimenting.&lt;/p&gt;
&lt;p&gt;Still responding to users.&lt;/p&gt;
&lt;p&gt;Still adding features.&lt;/p&gt;
&lt;p&gt;Still questioning his technical decisions.&lt;/p&gt;
&lt;p&gt;And still building for himself.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-coding-changed-about-his-career&quot;&gt;What Coding Changed About His Career&lt;/h3&gt;
&lt;p&gt;Maxim's story doesn't fit the traditional idea of a developer journey.&lt;/p&gt;
&lt;p&gt;He has a formal engineering education.&lt;/p&gt;
&lt;p&gt;He built a career in illustration.&lt;/p&gt;
&lt;p&gt;Then he returned to software through a problem he personally experienced.&lt;/p&gt;
&lt;p&gt;Today, he sits between several worlds:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Design.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Illustration.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Programming.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Product development.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Indie entrepreneurship.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That combination is what makes his journey particularly interesting.&lt;/p&gt;
&lt;p&gt;His development experience didn't replace his creative background.&lt;/p&gt;
&lt;p&gt;It extended it.&lt;/p&gt;
&lt;p&gt;His design experience didn't disappear when he started coding.&lt;/p&gt;
&lt;p&gt;It became part of how he builds software.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-lesson-build-from-your-own-pain&quot;&gt;The Lesson: Build From Your Own Pain&lt;/h3&gt;
&lt;p&gt;There is a simple principle running through Maxim's entire journey.&lt;/p&gt;
&lt;p&gt;The best product idea may already be sitting inside your own frustration.&lt;/p&gt;
&lt;p&gt;For Maxim, it was processing hundreds of images.&lt;/p&gt;
&lt;p&gt;For someone else, it might be a workflow at work, a repetitive task, a missing tool, or a problem nobody has bothered to solve properly.&lt;/p&gt;
&lt;p&gt;You don't always need to start with a startup idea.&lt;/p&gt;
&lt;p&gt;Sometimes you just need to notice the thing you keep doing manually.&lt;/p&gt;
&lt;p&gt;Then ask:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why am I still doing this?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That question took Maxim from Photoshop and Illustrator to JavaScript, React, Canvas, and eventually a product used by designers beyond his own workflow.&lt;/p&gt;
&lt;p&gt;His own profile sums up the philosophy well:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&quot;Ship when it's embarrassing, not when it's perfect.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But there's an important second half to that idea:&lt;/p&gt;
&lt;p&gt;Fix the bugs users actually complain about.&lt;/p&gt;
&lt;p&gt;That's perhaps the most practical lesson from Maxim's journey.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build early. Listen carefully. Keep improving.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;about-maxim-mitenkov&quot;&gt;About Maxim Mitenkov&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/Maxim+Mitenkov&quot;&gt;Maxim Mitenkov&lt;/a&gt; is a &lt;strong&gt;book-cover illustrator, engineer, and indie developer&lt;/strong&gt; from Belarus.&lt;/p&gt;
&lt;p&gt;He studied Computer Science and Radioelectronics at &lt;strong&gt;Belarusian State University of Informatics and Radioelectronics (BSUIR)&lt;/strong&gt; from 1993 to 1998.&lt;/p&gt;
&lt;p&gt;Today, Maxim is the &lt;strong&gt;solo founder of Image Pipeline&lt;/strong&gt;, a browser-based batch image processor designed around privacy and client-side processing.&lt;/p&gt;
&lt;p&gt;His technology stack includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;HTML5 Canvas&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;Zustand&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Vercel&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;He is currently exploring Web Workers for client-side processing, emotion-driven image filters, and growing Image Pipeline from 0 to revenue.&lt;/p&gt;
&lt;p&gt;He has launched Image Pipeline on Product Hunt, earned a 5★ AlternativeTo review, shipped 14 node types in six weeks, and built the product with zero backend image processing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View Maxim's full CoderLegion profile:&lt;/strong&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/user/Maxim+Mitenkov&quot;&gt;https://coderlegion.com/user/Maxim Mitenkov&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;about-this-developer-story&quot;&gt;About This Developer Story&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Developer:&lt;/strong&gt; Maxim Mitenkov&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Series:&lt;/strong&gt; CoderLegion Developer Stories&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interview conducted and edited by:&lt;/strong&gt; Mehadi Hasan, Community &amp;amp; Editorial Team, CoderLegion&lt;/p&gt;
&lt;p&gt;This Developer Story is based on Maxim Mitenkov's interview responses and his experience building software alongside his professional career as an illustrator.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26821/from-book-cover-illustrator-indie-developer-maxim-mitenkovs-journey-building-for-his-own</guid>
<pubDate>Fri, 11 Sep 2026 09:22:00 +0000</pubDate>
</item>
<item>
<title>I Built a Batch Image Processor with Zero Backend — Here's How</title>
<link>https://coderlegion.com/24826/i-built-a-batch-image-processor-with-zero-backend-heres-how</link>
<description>&lt;hr&gt;
&lt;p&gt;title: &quot;I Built a Batch Image Processor with Zero Backend — Here's How&quot;&lt;/p&gt;
&lt;h3 id=&quot;canonical-url-https-imagepipeline-art&quot;&gt;canonical_url: &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagepipeline.art&quot;&gt;https://imagepipeline.art&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I process between 50 and 100 images every month. Portfolio pieces for Behance. Pinterest pins in three aspect ratios. Client deliverables that need to be web-ready, print-ready, and social-ready — all from the same source file.&lt;/p&gt;
&lt;p&gt;For years I had three options. All of them were bad.&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Photoshop Actions&lt;/strong&gt; worked once. Then a client sent vertical covers. The Action cropped them wrong. Then I needed PNGs for one project and WebPs for another. I ended up with twelve duplicated Actions, each with a slightly different suffix, and a folder full of files named &lt;code&gt;final_v3_actual_FINAL.jpg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ImageMagick scripts&lt;/strong&gt; were fast. But three months later I opened a script and had no idea what &lt;code&gt;^&lt;/code&gt; meant or why I chose &lt;code&gt;center&lt;/code&gt; gravity. I needed to add a watermark. I needed to skip images smaller than 800px. I needed to &lt;em&gt;see&lt;/em&gt; if the crop looked right before processing a hundred files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud converters&lt;/strong&gt; were convenient. They also required me to upload client artwork — sometimes unpublished book covers under NDA — to someone else's server. &quot;Theoretical risk&quot; is not a phrase I want in the same sentence as &quot;client contract.&quot;&lt;/p&gt;
&lt;h3 id=&quot;the-realization&quot;&gt;The Realization&lt;/h3&gt;
&lt;p&gt;I didn't need a faster Photoshop. I didn't need a simpler ImageMagick. I needed a tool that combined three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Privacy.&lt;/strong&gt; My files stay on my machine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual feedback.&lt;/strong&gt; I see what the pipeline does before I run it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero setup.&lt;/strong&gt; I open a link and start working.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Nothing I tried offered all three. So I built it.&lt;/p&gt;
&lt;h3 id=&quot;what-i-built&quot;&gt;What I Built&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Image Pipeline&lt;/strong&gt; is a node-based batch image processor that runs entirely in your browser.&lt;/p&gt;
&lt;p&gt;You drag images in. You build a pipeline by connecting nodes: Load → Resize → Crop → Compress → Export. You click &lt;strong&gt;Process&lt;/strong&gt;. Everything happens via Canvas API in your browser tab. Images never touch a server. You download a ZIP.&lt;/p&gt;
&lt;p&gt;No signup. No installation. No credit card to &quot;try it free.&quot;&lt;/p&gt;
&lt;h3 id=&quot;the-technical-stack&quot;&gt;The Technical Stack&lt;/h3&gt;
&lt;p&gt;When I say &quot;zero backend for image processing,&quot; I mean it. The entire image manipulation layer is client-side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Image decoding:&lt;/strong&gt; Native &lt;code&gt;FileReader&lt;/code&gt; + &lt;code&gt;Image&lt;/code&gt; constructor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manipulation:&lt;/strong&gt; HTML5 Canvas API (&lt;code&gt;drawImage&lt;/code&gt;, &lt;code&gt;toBlob&lt;/code&gt;, &lt;code&gt;getImageData&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression:&lt;/strong&gt; Canvas &lt;code&gt;toBlob&lt;/code&gt; with quality parameter&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZIP generation:&lt;/strong&gt; JSZip, entirely client-side&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hosting:&lt;/strong&gt; Static HTML/JS on Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;backend&quot; that exists is minimal: 16 Vercel Edge Functions for rate limiting, payment verification (USDT on Tron), and email receipts. None of them touch your images.&lt;/p&gt;
&lt;h4 id=&quot;why-no-webassembly-&quot;&gt;Why No WebAssembly?&lt;/h4&gt;
&lt;p&gt;I intentionally avoided WebAssembly and heavy libraries. The app loads fast, works on old devices, and doesn't require users to download 5MB of WASM binaries just to resize a JPEG.&lt;/p&gt;
&lt;h4 id=&quot;why-react-flow-&quot;&gt;Why React Flow?&lt;/h4&gt;
&lt;p&gt;The node editor is built with &lt;code&gt;@xyflow/react&lt;/code&gt;. It gives me drag-and-drop nodes, connection validation, and a clean API — without building a canvas renderer from scratch. The visual pipeline is the core UX, not a gimmick.&lt;/p&gt;
&lt;h3 id=&quot;the-node-system&quot;&gt;The Node System&lt;/h3&gt;
&lt;p&gt;Currently 14 node types:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Node &lt;/th&gt;&lt;th&gt;What It Does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Load&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Accepts input images&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Resize&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Changes dimensions, fit modes, algorithms&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Crop&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Crops to region with position presets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Compress&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Reduces file size with quality slider&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Format&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Converts between JPG, PNG, WebP&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Watermark&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Adds text overlay&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Denoise&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Reduces image noise&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Brightness&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Adjusts luminance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Contrast&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Adjusts tonal range&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Exposure&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Adjusts light intensity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Saturation&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Adjusts color intensity&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Emotion Filter&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Applies mood-based color grading (Joy, Sadness, Calm, Tension)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Rename&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Batch renaming with patterns&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Export&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Output settings, ZIP generation&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each node has a live preview. Click a node, see before/after. Adjust settings, see changes in real time. The preview processes only a thumbnail (200px), so it's instant — the full batch runs only when you hit &lt;strong&gt;Process&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-monetization-model&quot;&gt;The Monetization Model&lt;/h3&gt;
&lt;p&gt;I didn't want subscriptions. As a user, I hate discovering a tool, liking it, then hitting a paywall that demands my credit card every month.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free:&lt;/strong&gt; 10 files/day, all nodes, all features&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pro ($10 one-time):&lt;/strong&gt; Unlimited files, unlimited nodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifetime ($30 one-time):&lt;/strong&gt; Pro forever&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Payments in USDT (TRC-20). No Stripe, no PayPal, no recurring charges. Verification happens via TronScan API with a Trongrid fallback. If the API is down, the client falls back to localStorage counters — the app never breaks.&lt;/p&gt;
&lt;h3 id=&quot;what-i-learned&quot;&gt;What I Learned&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Shipping beats perfection.&lt;/strong&gt; I launched with 9 nodes, a basic landing page, and no onboarding. The first user on AlternativeTo gave me 2 stars and a list of complaints: &quot;missing brightness, contrast, exposure,&quot; &quot;preview is tiny,&quot; &quot;multiple export broken.&quot;&lt;/p&gt;
&lt;p&gt;Five days later I shipped Brightness, Contrast, Exposure, fixed the preview (300px + compare modal), fixed Multiple Export, and added Emotion Filter + Saturation as bonuses. The next review was 5 stars.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Users will tell you what to build.&lt;/strong&gt; I never planned an Emotion Filter node. Someone asked about &quot;applying mood to images&quot; in a comment. I researched color matrices, built 5 emotion presets, and shipped it in two days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Privacy is a feature, not a footnote.&lt;/strong&gt; Every third comment mentions &quot;images never leave the device&quot; as the primary reason to try Image Pipeline. In a world of cloud-everything, client-side processing is a differentiator.&lt;/p&gt;
&lt;h3 id=&quot;try-it&quot;&gt;Try It&lt;/h3&gt;
&lt;p&gt;If you batch-process images regularly and none of the existing tools fit your workflow cleanly:&lt;/p&gt;
&lt;p&gt;👉 &lt;a rel=&quot;nofollow&quot; href=&quot;https://imagepipeline.art&quot;&gt;imagepipeline.art&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Free tier: 10 files per day. One-time purchase for unlimited.&lt;/p&gt;
&lt;p&gt;If you're a developer and prefer CLI — honestly, stick with ImageMagick. It's unbeatable for automation. This tool is for everyone else who got tired of the trade-offs.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Maxim Mitenkov is a book cover illustrator and indie developer. He built Image Pipeline because he was tired of uploading client artwork to cloud services just to resize a batch of images.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/24826/i-built-a-batch-image-processor-with-zero-backend-heres-how</guid>
<pubDate>Tue, 18 Aug 2026 10:40:50 +0000</pubDate>
</item>
</channel>
</rss>