2026年1月19日 星期一

UPC-A(Universal Product Code)

 UPC-A(Universal Product Code)

UPC-A(Universal Product Code)是常見的需求,主要用於北美市場。

UPC-A 與 EAN-13 的主要差異:

  • 長度:UPC-A 是 12 位數(EAN-13 是 13 位數)。

  • 國家代碼:UPC-A 不像 EAN 有明顯的 3 位國碼,但實際上 EAN-13 的 0 開頭即等同於 UPC-A。

  • 結構:1 位系統符號 + 5 位廠商碼 + 5 位商品碼 + 1 位檢查碼。



UPC-A 的特點重點:

  1. 檢查碼邏輯:UPC-A 的檢查碼計算公式與 EAN-13 略有不同,但 python-barcode 套件會自動處理,確保您產生的 12 位碼是合法可掃描的。

  2. 視覺差異:UPC-A 的數字通常會分開在條碼下方,左邊 1 位、中間 10 位、右邊 1 位。

  3. 相容性:所有能掃描 EAN-13 的設備都能掃描 UPC-A,但 UPC-A 通常不包含國家代碼資訊(除非轉成 EAN-13 並補 0)。


import tkinter as tk

from tkinter import ttk, Label, Button, Entry, messagebox, filedialog

import barcode

from barcode.writer import ImageWriter

from PIL import Image, ImageTk

import random

import io

import os


class UPCBarcodeApp:

    def __init__(self, root):

        self.root = root

        self.root.title("UPC-A 批量產生工具 (12位)")

        self.root.geometry("750x650")


        # 1. UPC 廠商資料庫範例 (北美常見)

        self.mfg_data = {

            "自定義輸入": "",

            "Apple (190198)": "190198",

            "Coca-Cola (049000)": "049000",

            "Nestle (050000)": "050000",

            "Walmart (681131)": "681131",

            "Nike (886066)": "886066"

        }


        main_frame = tk.Frame(self.root, padx=20, pady=10)

        main_frame.pack(fill="both", expand=True)


        Label(main_frame, text="UPC-A 12-Digit Barcode Generator", font=("Arial", 16, "bold")).pack(pady=10)


        # 設定區域

        config_frame = tk.LabelFrame(main_frame, text=" 參數設定 ", padx=10, pady=10)

        config_frame.pack(fill="x", pady=5)


        Label(config_frame, text="選擇廠商/前綴:").grid(row=0, column=0, sticky="w")

        self.combo_mfg = ttk.Combobox(config_frame, values=list(self.mfg_data.keys()), state="readonly")

        self.combo_mfg.current(0)

        self.combo_mfg.grid(row=0, column=1, padx=5, pady=5)

        self.combo_mfg.bind("<<ComboboxSelected>>", self.on_mfg_select)


        Label(config_frame, text="廠商代碼(建議6位):").grid(row=1, column=0, sticky="w")

        self.entry_mfg = Entry(config_frame)

        self.entry_mfg.grid(row=1, column=1, padx=5, pady=5)


        Label(config_frame, text="產生數量:").grid(row=2, column=0, sticky="w")

        self.entry_count = Entry(config_frame)

        self.entry_count.insert(0, "5")

        self.entry_count.grid(row=2, column=1, padx=5, pady=5)


        # 按鈕區

        btn_frame = tk.Frame(main_frame)

        btn_frame.pack(pady=10)

        Button(btn_frame, text="批量產生 UPC", command=self.batch_generate, bg="#E91E63", fg="white", width=15).pack(side="left", padx=5)

        Button(btn_frame, text="全部儲存 PNG", command=self.save_all, bg="#2196F3", fg="white", width=15).pack(side="left", padx=5)


        # 介面配置:左側清單小,右側預覽大

        list_preview_frame = tk.Frame(main_frame)

        list_preview_frame.pack(fill="both", expand=True, pady=10)


        # 左側清單寬度縮小

        self.tree_frame = tk.Frame(list_preview_frame, width=180)

        self.tree_frame.pack(side="left", fill="y", padx=(0, 10))

        self.tree_frame.pack_propagate(False)


        self.tree = ttk.Treeview(self.tree_frame, columns=("code"), show="headings")

        self.tree.heading("code", text="UPC 清單")

        self.tree.column("code", width=150, anchor="center")

        self.tree.pack(fill="both", expand=True)

        self.tree.bind("<<TreeviewSelect>>", self.on_tree_select)


        # 右側大型預覽

        self.preview_container = tk.LabelFrame(list_preview_frame, text=" UPC 大型預覽 (12位) ", bg="#f9f9f9")

        self.preview_container.pack(side="right", fill="both", expand=True)


        self.preview_label = Label(self.preview_container, bg="white")

        self.preview_label.pack(padx=15, pady=15, fill="both", expand=True)


        self.generated_barcodes = {}


    def on_mfg_select(self, event):

        selected = self.combo_mfg.get()

        code = self.mfg_data[selected]

        self.entry_mfg.delete(0, tk.END)

        self.entry_mfg.insert(0, code)


    def generate_single_upc(self, mfg_code):

        # UPC-A 需要 11 位(+1位自動生成的檢查碼 = 12位)

        rem_len = 11 - len(mfg_code)

        product_part = "".join([str(random.randint(0, 9)) for _ in range(rem_len)])

        full_payload = mfg_code + product_part

        

        # 使用 python-barcode 的 upca 模式

        upc = barcode.get('upca', full_payload, writer=ImageWriter())

        

        buffer = io.BytesIO()

        upc.write(buffer)

        buffer.seek(0)

        return upc.get_fullcode(), Image.open(buffer)


    def batch_generate(self):

        mfg = self.entry_mfg.get().strip()

        try:

            count = int(self.entry_count.get())

            if not mfg.isdigit() or len(mfg) > 11: raise ValueError()

        except:

            messagebox.showerror("錯誤", "請輸入有效的數字碼(1-11位)與產生數量")

            return


        for i in self.tree.get_children(): self.tree.delete(i)

        self.generated_barcodes.clear()


        for _ in range(count):

            code, img = self.generate_single_upc(mfg)

            self.generated_barcodes[str(code)] = img

            self.tree.insert("", "end", values=(code,))

        

        if self.tree.get_children():

            self.tree.selection_set(self.tree.get_children()[0])


    def on_tree_select(self, event):

        selection = self.tree.selection()

        if selection:

            code = self.tree.item(selection[0])['values'][0]

            # 強制轉為字串搜尋(處理 0 開頭問題)

            code_str = str(code).zfill(12)

            pil_img = self.generated_barcodes.get(code_str)

            

            if pil_img:

                self.root.update_idletasks()

                view_w = self.preview_label.winfo_width()

                

                # 放大條碼預覽

                target_w = max(view_w - 30, 400)

                w, h = pil_img.size

                scale = target_w / w

                display_img = pil_img.resize((int(w * scale), int(h * scale)), Image.Resampling.LANCZOS)

                

                tk_img = ImageTk.PhotoImage(display_img)

                self.preview_label.config(image=tk_img)

                self.preview_label.image = tk_img


    def save_all(self):

        if not self.generated_barcodes: return

        folder = filedialog.askdirectory(title="選擇儲存資料夾")

        if folder:

            for code, img in self.generated_barcodes.items():

                img.save(os.path.join(folder, f"UPCA_{code}.png"))

            messagebox.showinfo("成功", f"批量儲存完成!")


if __name__ == "__main__":

    root = tk.Tk()

    app = UPCBarcodeApp(root)

    root.mainloop()


沒有留言:

張貼留言

Dynamic Framed Slotted ALOHA (DFSA) 防撞方法

 Dynamic Framed Slotted ALOHA (DFSA)防撞方法 DFSA 的核心邏輯: 動態框長 (Dynamic Frame Size) :閱讀器會根據上一輪的結果(碰撞次數、空閒次數)來 動態調整 下一輪的時槽數(框長 $L$ )。 效率優化 :當標籤很多時...