مثال کامل قابل اجرا در گیت‌هاب موجود است:
read-and-write-xmp-in-psd-ai-files-java

روش قبلی دردناک بود

تصور کنید پاک‌سازی آرشیوی که هیچ‌کس داوطلب آن نیست. یک پوشه حاوی فایل‌های اصلی PSD و منابع AI قبل از ورود به DAM نیاز به اعلان‌های حقوقی و کلیدواژه‌ها دارد. روتین این است: یک فایل را در Photoshop باز کنید، File Info را باز کنید، حق کپی‌رایت را تایپ کنید، کلیدواژه‌ها را تایپ کنید، ذخیره کنید، ببندید، فایل بعدی. هر بار ذخیره، یک فایل لایه‌ای را دوباره رندر می‌کند فقط برای تغییر چند رشته متادیتای XMP. آرشیوی که این درس را به من داد، یک پوشه از فایل‌های Illustrator بدون برچسب بود که هیچ‌کس نمی‌توانست جستجو کند؛ ما آن را با یک حلقه حل کردیم، نه با صبر بیشتر.

اگر این روتین را در مقیاس یک آرشیو ضرب کنید، دیگر یک کار ساده نیست و به یک پروژه تبدیل می‌شود. بدتر از آن، غیرقابل حسابرسی است: هیچ‌کس نمی‌تواند بعداً ثابت کند کدام فایل‌ها پردازش شده‌اند و فایل‌های نادیده‌گرفته‌شده تا زمانی که سؤال مجوزی آن‌ها را پیدا کند، یکسان به نظر می‌رسند. مسیر پنل همچنین به‌صورت ساکت داده‌ورودی را به ابزارهای طراحی وصل می‌کند. هر کسی که متادیتا را اصلاح می‌کند، به یک لایسنس Adobe، یک ایستگاه کاری که بتواند مستندات لایه‌ای را به‌راحتی باز کند و صبر برای انتظار ذخیره‌هایی که برای تغییر رشته‌ها کل آثار را دوباره رندر می‌کند، نیاز دارد.

هزینه واقعی انجام کار به‌صورت دستی: متادیتایی که به‌دست اصلاح می‌شود، متادیتایی است که بعداً هیچ‌کس نمی‌تواند آن را تأیید کند؛ این فرآیند هیچ ردپایی به‌جز طراحان خسته‌دل باقی نمی‌گذارد.

یک راه بهتر وجود دارد

GroupDocs.Metadata برای Java بسته XMP را به‌صورت مستقیم می‌خواند و می‌نویسد. getRootPackage() را به IXmp تبدیل کنید و بسته، طرح‌ها و آرایه‌های آن تبدیل به اشیای عادی Java می‌شوند، برای کانتینرهای PSD و AI یکسان هستند و نیازی به نرم‌افزار Adobe نیست. مستندات بیش از ۱۷۰ فرمت را پشت همان API فهرست می‌کند.

قبل از شروع، به موارد زیر نیاز دارید:

پکیج وابستگی و مخزن GroupDocs را به pom.xml خود اضافه کنید:

mvn dependency:get -Dartifact=com.groupdocs:groupdocs-metadata:24.7

مخزن همراه یک pom.xml آماده به‌همراه نمونه‌های هر دو فرمت ارائه می‌دهد و هر گام زیر را تأیید می‌کند.

راه جدید: چهار عملیات در جاوا

مرحله ۱ – ببینید یک فایل چه چیزی حمل می‌کند

// Snapshot the packet, then sweep for anything the schemes missed
Map<String, String> result = new LinkedHashMap<>();
try (Metadata metadata = new Metadata(adobeFilePath)) {
    IXmp root = (IXmp) metadata.getRootPackage();
    if (root != null && root.getXmpPackage() != null) {
        for (MetadataProperty p : root.getXmpPackage()) {
            put(result, p);
        }
        XmpSchemes schemes = root.getXmpPackage().getSchemes();
        collect(result, schemes.getDublinCore());
        collect(result, schemes.getPhotoshop());
        collect(result, schemes.getXmpBasic());
        collect(result, schemes.getCameraRaw());
    }
    for (MetadataProperty p : metadata.findProperties(new NamedPropertySpec())) {
        if (!result.containsKey(p.getName())) put(result, p);
    }
}
return result;

کمک‌کننده‌های کوچک put و collect ترجیحاً getInterpretedValue() را استفاده می‌کنند تا تاریخ‌ها به‌صورت قابل خواندن برگردند و جستجوی مبتنی بر Specification بسته‌های فروشنده را نیز می‌گیرد. نسخه مخزن هفت طرح را می‌پیماید؛ شکل کلی همان‌جا می‌ماند.

مرحله ۲ – فیلدهایی که به سؤالات پاسخ می‌دهند را بخوانید

// dc:* only - the interoperability fields DAM systems agree on
XmpDublinCorePackage dc = root.getXmpPackage().getSchemes().getDublinCore();
if (dc == null) return result;
for (MetadataProperty p : dc) {
    String value = "";
    if (p.getInterpretedValue() != null
            && p.getInterpretedValue().getRawValue() != null) {
        value = String.valueOf(p.getInterpretedValue().getRawValue());
    } else if (p.getValue() != null && p.getValue().getRawValue() != null) {
        value = String.valueOf(p.getValue().getRawValue());
    }
    result.put(p.getName(), value);
}

طرح Photoshop به‌همین شکل از طریق گترهای تایپ‌شده (getCity(), getCredit(), getColorMode() و پنج مورد دیگر) کار می‌کند و فیلدهای متادیتای PSD که فیلترهای Bridge و Lightroom می‌خوانند را پوشش می‌دهد. در مخزن این خواننده هر گتر را با یک کمک‌کننده ایمن در برابر null می‌پیچد، بنابراین فایلی که به‌صورت پراکنده پر شده است، رشته‌های خالی برمی‌گرداند نه مقادیر ناخواسته. این جزئیات بیشتر از آنچه به نظر می‌رسد مهم است: هدف اصلی خودکارسازی یک آرشیو این است که فایل‌های عجیب و غریب عبور کنند به‌جای اینکه حلقه را متوقف کنند.

هر دو خواندن محدوده‌دار یک پروفیل هزینه‌ای دارند که ارزش ذکر دارد. یک بار باز کردن فایل، یک طرح، بدون پیمایش درخت. آن‌ها را در هندلرهای درخواست و گیت‌ها قرار دهید؛ اسنپ‌شات کامل را برای کارهای جذب که همه چیز را ذخیره می‌کنند، نگه دارید.

مرحله ۳ – بدون باز کردن Adobe، مهر و برچسب بزنید

// Create missing layers, then write rights, creator, and CreatorTool
if (root.getXmpPackage() == null) {
    root.setXmpPackage(new XmpPacketWrapper());
}
if (root.getXmpPackage().getSchemes().getDublinCore() == null) {
    root.getXmpPackage().getSchemes().setDublinCore(new XmpDublinCorePackage());
}
XmpDublinCorePackage dc = root.getXmpPackage().getSchemes().getDublinCore();
dc.setRights(copyright);
dc.set("dc:creator", XmpArray.from(new String[]{creator}, XmpArrayType.Ordered));

if (root.getXmpPackage().getSchemes().getXmpBasic() == null) {
    root.getXmpPackage().getSchemes().setXmpBasic(new XmpBasicPackage());
}
root.getXmpPackage().getSchemes().getXmpBasic().setCreatorTool(creator);

metadata.save(outputPath);

کلیدواژه‌ها با همان الگو و یک فراخوانی، کل کیف را به‌صورت آرایهٔ Unordered می‌نویسند:

// Replace the dc:subject bag - merge in Java first for additive tagging
root.getXmpPackage().getSchemes().getDublinCore().set(
        "dc:subject", XmpArray.from(keywords, XmpArrayType.Unordered));
metadata.save(outputPath);

Main.java حلقه را می‌بندد: خروجی‌ها را دوباره می‌خواند و تأیید می‌کند که رشتهٔ حق کپی‌رایت و اولین کلیدواژه واقعاً پس از ذخیره باقی مانده‌اند.

این تأیید نهایی شایستگی یک جمله تبلیغی دارد. نوشتن متادیتا به‌صورت ساکت شکست می‌خورد؛ فایل ذخیره می‌شود، بایت‌ها تغییر می‌کنند و مقداری که قصد نوشتن آن را داشتید به‌دلیل قدیمی بودن شیء طرح یا مسیر اشاره به نسخهٔ اصلی، وجود ندارد. خواندن‑باز پس از هر نوشتن یک باز کردن اضافی برای هر فایل هزینه دارد و «اسکریپت تمام شد» را به «مقدارها موجود هستند» تبدیل می‌کند؛ این همان بیانیه‌ای است که صاحب آرشیو واقعاً می‌خواهد. این کار را در محیط تولید نگه دارید، نه فقط در دموی نمونه.

چگونه کلیدواژه‌ها واقعاً دارایی‌ها را قابل جستجو می‌کنند؟

ابزارهای جستجو پیکسل‌ها را نمی‌خوانند؛ آن‌ها dc:subject را می‌خوانند. Bridge، ایندکس‌کننده‌های DAM و پلتفرم‌های استوک این کیف را به‌عنوان واژگان دارایی در نظر می‌گیرند، بنابراین فایلی بدون کلیدواژه هرگز با یک پرس‌وجو مطابقت نمی‌کند. نوشتن کیف به‌صورت Unordered XmpArray، همان‌طور که AddKeywords انجام می‌دهد، دارایی را از حالت نامرئی به قابل یافتن می‌برد و این نوشتن تنها یک ذخیره هزینه دارد.

مقایسه‌ای: قبل در مقابل بعد

قبل (ویرایش پنل) بعد (خط لوله جاوا)
ابزارها فوتوشاپ یا بریج برای هر فایل یک پروژه Maven، بدون نیاز به لایسنس Adobe
پوشش فیلدهایی که پنل نمایش می‌دهد هر طرح به‌اضافه بسته‌های فروشنده
قابلیت تکرار به این بستگی دارد که چه کسی کلیک کرده است همان حلقه، همان نتیجه، قابل حسابرسی
فایل‌های بدون XMP رفتار پنل متفاوت است محافظ‌ها بسته و طرح‌ها را ایجاد می‌کنند
تأیید اعتماد خواندن‑باز تأیید شده برای هر فایل

سطر تأیید برای آرشیوها تصمیم‌گیرنده است: اسکریپتی که نوشتن‌های خود را ثابت می‌کند، تفاوت بین «ما فایل‌ها را برچسب زدیم» و «می‌توانیم به شما نشان دهیم» را ایجاد می‌کند.

مثال واقعی: تحویل از طرف آژانس

یک استودیو تحویل‌های ترکیبی PSD و AI را از سه آژانس دریافت می‌کند که هر کدام روش متادیتای خود را دارند. کار ورود داده اکنون اسنپ‌شات را هنگام ورود اجرا می‌کند، فایل‌هایی که dc:rights آن‌ها خالی است را پرچم می‌زند، با خط حقوق قراردادی مهر می‌زند و مجموعهٔ کلیدواژه‌های کمپین را می‌نویسد. همان حلقه برای هر دو فرمت کار می‌کند چون در کد هیچ اشاره‌ای به نوع کانتینر نیست و متادیتای Illustrator که خالی می‌آید، ورودی را برچسب‌دار و قابل جستجو می‌گذارد.

اثر پس‌از این، بخشی است که استودیو پیش‌بینی نکرد: کارت‌های امتیازدهی آژانس‌ها. چون کار ورود لاگ می‌کند که کدام تحویل‌ها با فیلدهای حقوق خالی آمده‌اند، بخش خرید حالا می‌بیند کدام تأمین‌کنندگان متادیتای تمیزی می‌فرستند و کدام به مشتری برای اصلاح آن تکیه می‌کنند. گفت‌وگو با بدترین تخلف‌کننده تنها یک نمودار طول کشید.

دیگر چه کاری می‌توانید با GroupDocs.Metadata انجام دهید؟

  • EXIF و IPTC در همان فایل‌ها: فایل‌های PSD سه استاندارد متادیتا را حمل می‌کنند؛ همان کتابخانه دو استاندارد دیگر را از طریق بسته‌های خود می‌خواند، بنابراین یک پروفایل کامل دارایی تنها دو خواندن دیگر فاصله دارد.
  • بیش از ۱۷۰ فرمت دیگر: نقطهٔ ورودی یکسان Metadata برای Office، PDF، فایل‌های صوتی و ویدئویی نیز کار می‌کند؛ به همین دلیل یک کار ورود می‌تواند کل یک آرشیو ترکیبی را پوشش دهد.
  • جستجوی ویژگی: findProperties همراه با یک Specification هر فایلی را برای هر پیش‌شرطی که تعریف کنید، از بررسی حقوق تا جستجوی فیلدهای سفارشی، اسکن می‌کند.

نتیجه‌گیری

آنچه قبلاً یک روتین پنلی برای هر فایل بود، اکنون چهار عملیات جاوا است: اسنپ‌شات، خواندن محدوده‌دار، مهر مالکیت، نوشتن کلیدواژه. همان کد برای فایل‌های PSD و AI کار می‌کند، محافظ‌ها صادرات خالی را ایمن می‌سازند و پروژهٔ نمونهٔ تأیید شده تمام مجموعه را قبل از اعمال روی آرشیو واقعی نشان می‌دهد.

آماده‌اید تا پنل File Info را کنار بگذارید؟

منابع اضافی