Certainly! Below is an HTML code that implements the functionality you've described. The code includes an image import button, a canvas for displaying and interacting with the image, zooming and panning functionality, selection of rectangles for each face, and a list of faces with controls to add, delete, or edit selections.


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Box Packaging Design Selector</title>
<style>
    body, html {
        margin: 0;
        overflow: hidden;
        height: 100%;
        display: flex;
        flex-direction: column;
    }
    #toolbar {
        display: flex;
        align-items: center;
        padding: 5px;
        background-color: #f0f0f0;
    }
    #importImageButton {
        margin-right: 10px;
    }
    #faceList {
        display: flex;
        gap: 10px;
    }
    .face-item {
        display: flex;
        align-items: center;
        gap: 5px;
    }
    .face-label {
        width: 50px;
    }
    #canvasContainer {
        flex: 1;
        position: relative;
    }
    #imageCanvas {
        width: 100%;
        height: 100%;
        background-color: #ccc;
        cursor: crosshair;
    }
    .handle {
        position: absolute;
        width: 10px;
        height: 10px;
        background: red;
        border: 1px solid #fff;
        border-radius: 50%;
        cursor: pointer;
    }
    .selection-label {
        position: absolute;
        background-color: rgba(255, 255, 255, 0.5);
        padding: 2px 5px;
        border-radius: 3px;
        pointer-events: none;
        font-weight: bold;
    }
</style>
</head>
<body>

<div id="toolbar">
    <button id="importImageButton">Import Image</button>
    <input type="file" id="imageLoader" accept="image/*" style="display:none"/>
    <div id="faceList">
        <!-- Faces will be dynamically added here -->
    </div>
</div>

<div id="canvasContainer">
    <canvas id="imageCanvas"></canvas>
</div>

<script>
    // JavaScript code

    // Get references to DOM elements
    const importImageButton = document.getElementById('importImageButton');
    const imageLoader = document.getElementById('imageLoader');
    const canvas = document.getElementById('imageCanvas');
    const faceList = document.getElementById('faceList');
    const canvasContainer = document.getElementById('canvasContainer');
    const ctx = canvas.getContext('2d');

    // Variables for canvas manipulation
    let image = new Image();
    let imgScale = 1;
    let imgPos = { x: 0, y: 0 };
    let isPanning = false;
    let panStart = { x: 0, y: 0 };
    let mouseStart = { x: 0, y: 0 };

    // Variables for selection
    let faces = ['front', 'back', 'right', 'left', 'top', 'bottom'];
    let selections = {};
    let currentFace = null;
    let isDrawing = false;
    let isEditing = false;
    let editHandle = null;
    let hoverHandle = null;
    let handles = [];
    const handleSize = 10;

    // Initialize canvas size
    function resizeCanvas() {
        canvas.width = canvasContainer.clientWidth;
        canvas.height = canvasContainer.clientHeight;
        draw();
    }
    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();

    // Import image button click
    importImageButton.addEventListener('click', () => {
        imageLoader.click();
    });

    // Load selected image
    imageLoader.addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = (event) => {
            image.src = event.target.result;
            image.onload = () => {
                imgScale = 1;
                imgPos = { x: (canvas.width - image.width) / 2, y: (canvas.height - image.height) / 2 };
                draw();
            };
        };
        reader.readAsDataURL(file);
    });

    // Set up faces list
    faces.forEach(faceName => {
        // Create face item
        const faceItem = document.createElement('div');
        faceItem.className = 'face-item';

        // Add elements to face item
        const faceLabel = document.createElement('span');
        faceLabel.textContent = faceName;
        faceLabel.className = 'face-label';

        const addButton = document.createElement('button');
        addButton.textContent = 'Add';
        addButton.disabled = false;

        const deleteButton = document.createElement('button');
        deleteButton.textContent = 'Delete';
        deleteButton.disabled = true;

        const editButton = document.createElement('button');
        editButton.textContent = 'Edit';
        editButton.disabled = true;

        faceItem.appendChild(faceLabel);
        faceItem.appendChild(addButton);
        faceItem.appendChild(deleteButton);
        faceItem.appendChild(editButton);
        faceList.appendChild(faceItem);

        // Event listeners for buttons
        addButton.addEventListener('click', () => {
            currentFace = faceName;
            isDrawing = true;
            addButton.disabled = true;
            deleteButton.disabled = false;
            editButton.disabled = false;
        });

        deleteButton.addEventListener('click', () => {
            delete selections[faceName];
            addButton.disabled = false;
            deleteButton.disabled = true;
            editButton.disabled = true;
            draw();
        });

        editButton.addEventListener('click', () => {
            currentFace = faceName;
            isEditing = !isEditing;
            editButton.textContent = isEditing ? 'Done' : 'Edit';
            draw();
        });
    });

    // Canvas event handlers
    canvas.addEventListener('mousedown', (e) => {
        const rect = canvas.getBoundingClientRect();
        const mouseX = (e.clientX - rect.left);
        const mouseY = (e.clientY - rect.top);

        const imgMouseX = (mouseX - imgPos.x) / imgScale;
        const imgMouseY = (mouseY - imgPos.y) / imgScale;

        if (e.button === 1) {
            // Middle mouse button for panning
            isPanning = true;
            panStart = { x: imgPos.x, y: imgPos.y };
            mouseStart = { x: e.clientX, y: e.clientY };
        } else if (isDrawing && currentFace) {
            // Start drawing selection rectangle
            selections[currentFace] = {
                x: imgMouseX,
                y: imgMouseY,
                width: 0,
                height: 0
            };
            isDrawing = true;
        } else if (isEditing && selections[currentFace]) {
            // Check if clicked on handle
            const handle = getHandleUnderMouse(mouseX, mouseY);
            if (handle) {
                editHandle = handle;
            } else {
                // Start moving the selection
                editHandle = 'move';
                panStart = { x: selections[currentFace].x, y: selections[currentFace].y };
                mouseStart = { x: imgMouseX, y: imgMouseY };
            }
        }
    });

    canvas.addEventListener('mousemove', (e) => {
        const rect = canvas.getBoundingClientRect();
        const mouseX = (e.clientX - rect.left);
        const mouseY = (e.clientY - rect.top);

        const imgMouseX = (mouseX - imgPos.x) / imgScale;
        const imgMouseY = (mouseY - imgPos.y) / imgScale;

        if (isPanning) {
            // Panning
            imgPos.x = panStart.x + (e.clientX - mouseStart.x);
            imgPos.y = panStart.y + (e.clientY - mouseStart.y);
            draw();
        } else if (isDrawing && selections[currentFace]) {
            // Update selection rectangle size
            const sel = selections[currentFace];
            sel.width = imgMouseX - sel.x;
            sel.height = imgMouseY - sel.y;
            draw();
        } else if (isEditing && editHandle && selections[currentFace]) {
            // Edit selection rectangle
            const sel = selections[currentFace];
            if (editHandle === 'move') {
                sel.x = panStart.x + (imgMouseX - mouseStart.x);
                sel.y = panStart.y + (imgMouseY - mouseStart.y);
            } else {
                // Adjust selection based on handle
                adjustSelection(sel, editHandle, imgMouseX, imgMouseY);
            }
            draw();
        } else {
            // Update hover state for handles
            hoverHandle = getHandleUnderMouse(mouseX, mouseY);
            canvas.style.cursor = hoverHandle ? 'pointer' : 'default';
        }
    });

    canvas.addEventListener('mouseup', (e) => {
        isPanning = false;
        isDrawing = false;
        editHandle = null;
    });

    canvas.addEventListener('wheel', (e) => {
        // Zooming
        e.preventDefault();
        const delta = e.deltaY < 0 ? 1.1 : 0.9;
        const rect = canvas.getBoundingClientRect();
        const mouseX = (e.clientX - rect.left);
        const mouseY = (e.clientY - rect.top);

        const imgMouseX = (mouseX - imgPos.x) / imgScale;
        const imgMouseY = (mouseY - imgPos.y) / imgScale;

        imgScale *= delta;
        imgPos.x = mouseX - imgMouseX * imgScale;
        imgPos.y = mouseY - imgMouseY * imgScale;

        draw();
    });

    canvas.addEventListener('contextmenu', (e) => {
        e.preventDefault();
    });

    function draw() {
        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Draw image
        if (image.src) {
            ctx.drawImage(image, imgPos.x, imgPos.y, image.width * imgScale, image.height * imgScale);
        }

        // Draw selections
        for (const faceName in selections) {
            const sel = selections[faceName];
            drawSelection(sel, faceName, faceName === currentFace && isEditing);
        }
    }

    function drawSelection(sel, label, showHandles) {
        ctx.save();
        ctx.strokeStyle = 'red';
        ctx.lineWidth = 2;
        ctx.strokeRect(
            sel.x * imgScale + imgPos.x,
            sel.y * imgScale + imgPos.y,
            sel.width * imgScale,
            sel.height * imgScale
        );

        // Draw label
        ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
        ctx.font = 'bold 14px Arial';
        const textWidth = ctx.measureText(label).width;
        ctx.fillRect(
            (sel.x + sel.width / 2) * imgScale + imgPos.x - textWidth / 2 - 5,
            (sel.y + sel.height / 2) * imgScale + imgPos.y - 15,
            textWidth + 10,
            20
        );
        ctx.fillStyle = 'black';
        ctx.fillText(
            label,
            (sel.x + sel.width / 2) * imgScale + imgPos.x - textWidth / 2,
            (sel.y + sel.height / 2) * imgScale + imgPos.y
        );

        // Draw handles if editing
        if (showHandles) {
            updateHandles(sel);
            handles.forEach(handle => {
                ctx.fillStyle = 'red';
                ctx.fillRect(handle.x - handleSize / 2, handle.y - handleSize / 2, handleSize, handleSize);
            });
        }

        ctx.restore();
    }

    function updateHandles(sel) {
        handles = [];
        const points = [
            { x: sel.x, y: sel.y }, // Top-left
            { x: sel.x + sel.width, y: sel.y }, // Top-right
            { x: sel.x, y: sel.y + sel.height }, // Bottom-left
            { x: sel.x + sel.width, y: sel.y + sel.height } // Bottom-right
        ];
        points.forEach((pt, idx) => {
            handles.push({
                x: pt.x * imgScale + imgPos.x,
                y: pt.y * imgScale + imgPos.y,
                pos: ['nw', 'ne', 'sw', 'se'][idx]
            });
        });
    }

    function getHandleUnderMouse(mouseX, mouseY) {
        return handles.find(handle => {
            return (
                mouseX >= handle.x - handleSize / 2 &&
                mouseX <= handle.x + handleSize / 2 &&
                mouseY >= handle.y - handleSize / 2 &&
                mouseY <= handle.y + handleSize / 2
            );
        })?.pos;
    }

    function adjustSelection(sel, handlePos, imgMouseX, imgMouseY) {
        switch (handlePos) {
            case 'nw':
                sel.width += sel.x - imgMouseX;
                sel.height += sel.y - imgMouseY;
                sel.x = imgMouseX;
                sel.y = imgMouseY;
                break;
            case 'ne':
                sel.width = imgMouseX - sel.x;
                sel.height += sel.y - imgMouseY;
                sel.y = imgMouseY;
                break;
            case 'sw':
                sel.width += sel.x - imgMouseX;
                sel.x = imgMouseX;
                sel.height = imgMouseY - sel.y;
                break;
            case 'se':
                sel.width = imgMouseX - sel.x;
                sel.height = imgMouseY - sel.y;
                break;
        }
    }

</script>

</body>
</html>


Explanation of the Code:

- HTML Structure:
- A toolbar at the top with the "Import Image" button and the list of faces with their controls.
- A canvas inside a container that takes up the remaining space of the page. The canvas will display the image and handle user interactions.

- CSS Styles:
- Styles to ensure the canvas fills the available space and the toolbar and face list are properly aligned.
- Styles for the selection handles and labels to make them visible and interactive.

- JavaScript Functionality:
- Image Importing:
- When the user clicks "Import Image," it triggers a hidden file input to select an image.
- The selected image is loaded and displayed on the canvas.

- Zooming and Panning:
- The user can zoom in and out using the mouse wheel. The zoom focuses on the cursor position.
- Panning is done using the middle mouse button (button 1). Pressing it allows dragging the image around.

- Selection of Faces:
- Each face in the list (front, back, right, left, top, bottom) has associated buttons:
- Add: Allows the user to start drawing a selection rectangle for that face.
- Delete: Removes the selection rectangle for that face.
- Edit: Toggles edit mode, enabling handles for resizing and moving the selection.
- When adding a face, the user clicks and drags on the canvas to draw a rectangle. The rectangle sticks to the image and scales/moves with it.
- The selection rectangles are stored in the selections object, keyed by face name.

- Editing Selections:
- In edit mode, handles appear at the corners of the selection rectangle.
- The user can drag these handles to resize the rectangle.
- If the user clicks inside the rectangle but not on a handle, they can move the entire rectangle.

- Drawing Function (draw):
- Clears the canvas and redraws the image and all selection rectangles.
- Selection rectangles are drawn with red borders and have labels at their centers.

- Event Handlers:
- Mouse Events:
- mousedown, mousemove, and mouseup handle drawing, panning, and editing interactions.
- Wheel Event:
- wheel handles zooming in and out.
- Resize Event:
- Adjusts the canvas size when the window is resized.

Notes:

- The code uses plain JavaScript and canvas APIs to handle all interactions.
- The selection rectangles are implemented in such a way that they stick to the image when zooming and panning.
- The handles for editing are only visible when the user is in edit mode for a particular face.
- The code assumes that the middle mouse button is used for panning, which may not be available on all devices (e.g., certain touchpads). You may want to adapt the code to support other input methods if necessary.


I want to add those featurs:
- add some css style on the ui
- make every rect face in defrent color
- add import .uv1 file button
the .uv1 is text file that contain data for every face and its destination emplacement to make the final texture for the 3d box and its UV map
the .uv1 template is like so:
first line is the result image size by pixel
the other 6 line tell the new placement of the selected faces for the new texture that we need to make formatted line so:
face_name,  rect_x_cordinate, rect_y_cordinate, rect_x_size, rect_y_size

for example the .uv1 file should be:
size,1000,1000
front,452.000,139.000,568.000,752.000
back,1034.000,161.000,252.000,572.000
right,286.000,165.000,205.000,426.000
left,338.000,263.000,156.000,355.000
top,470.000,310.000,631.000,599.000
bottom,218.000,652.000,597.000,196.000

- add the option to mark the face as rotate (90°, -90°, 180°) and flip (horizontal, vertical) so we can implement those transform when converting the emplacement of the selected faces on the new placement on the result texture

so every face selected on the texture will be