# ข้อมูลอ้างอิงลายน้ำภาพถ่ายท้องถิ่น API

เครื่องมือถ่ายภาพท้องถิ่นฟรี: ชุดลายน้ำ ป้ายชื่อไฟล์ และการประทับวันที่

## เลือกพื้นผิวการดำเนินการ

การค้นพบ API เป็นแบบสาธารณะ ฟรี อ่านอย่างเดียว และไม่ต้องใช้คีย์ API อธิบายเครื่องมือและการตั้งค่า มันไม่เคยยอมรับภาพ ไม่มี POST /ลายน้ำ บริการประมวลผลบนคลาวด์ หรือปลายทาง MCP ที่โฮสต์อยู่

ใช้เบราว์เซอร์ SDK สำหรับไฟล์ที่เลือกอย่างชัดเจนในต้นทางนี้ สำหรับผู้ช่วยที่มีสิทธิ์เข้าถึงระบบไฟล์ในเครื่อง ให้เชื่อมต่อเซิร์ฟเวอร์ stdio MCP ของที่เก็บอย่างชัดเจน และให้สิทธิ์ไดเร็กทอรีราก โมเดลที่ค้นหาเอกสารนี้ไม่สามารถเข้าถึงอุปกรณ์หรือไฟล์ของอุปกรณ์ได้



| พื้นผิว | วัตถุประสงค์ |
| --- | --- |
| รับ JSON / มาร์กดาวน์ | ค้นพบความสามารถ สูตรอาหาร ข้อจำกัด และลายเซ็นต์ของเครื่องมือในเครื่อง |
| เบราว์เซอร์ ESM SDK | ถอดรหัสและเรนเดอร์ไฟล์ในเครื่อง ต้องใช้ Canvas, DOM, createImageBitmap และ File/Blob ไม่ใช่ Node หรือการประมวลผล HTTP ระยะไกล API |
| CLI ท้องถิ่น / stdio MCP | เชื่อมต่อระบบอัตโนมัติภายในอย่างชัดเจนโดยใช้ Google Chrome ที่ติดตั้งและการพึ่งพาที่เก็บข้อมูล |


## ทรัพยากรสาธารณะ

GET และ HEAD ส่งคืนทรัพยากรแบบคงที่ ไม่มีการตรวจสอบสิทธิ์ เนื้อหาคำขอ พารามิเตอร์การค้นหา หรือข้อมูลผู้ใช้ เส้นทางทรัพยากรที่ไม่รู้จักส่งคืน 404 ถือว่าเวอร์ชัน 1 เป็นเวอร์ชันสัญญา บุ๊กมาร์กเส้นทางตามรูปแบบบัญญัติแทนที่จะแฮช build chunks การเข้าถึงเบราว์เซอร์แบบข้ามต้นทางไม่ได้ถูกสัญญาไว้ ใช้การนำเข้า SDK ที่มีต้นกำเนิดเดียวกัน

- [แค็ตตาล็อกความสามารถ](/api/v1/capabilities.json)
- [กรอกสูตรอาหารเริ่มต้นและตัวแปรข้อความที่รองรับ](/api/v1/templates.json)
- [สูตร JSON Schema (2020-12)](/api/v1/recipe.schema.json)
- [สกีมาอินพุต MCP โลคัล](/api/v1/mcp-tools.json)
- [ข้อมูลจำเพาะการค้นพบ OpenAPI 3.1](/openapi.json)
- [ไดเร็กทอรีการค้นพบทางเลือก](/llms.txt)

```
curl https://watermark.noxxxx.com/api/v1/capabilities.json
curl https://watermark.noxxxx.com/api/v1/recipes/filename.json
```


## เบราว์เซอร์ SDK

นำเข้า /sdk/watermark.js จากที่มาของไซต์นี้ นี่คือ URL รายการ ESM ที่เสถียร ชิ้นส่วนการใช้งานสามารถเปลี่ยนแปลงได้ ตัวอย่างต่อไปนี้คาดว่าจะมีอินพุตหลายไฟล์และทำงานหลังจากที่ผู้ใช้เลือกไฟล์ในเครื่อง โดยจะสร้าง ZIP ของสำเนาที่สำเร็จ ผู้เรียกจะต้องตรวจสอบ failures และ cancelled แทนที่จะถือว่าการส่งออกบางส่วนเสร็จสมบูรณ์



```
import { createRecipe, validateRecipe, inspectImage, processBatch, packageResults }
  from '/sdk/watermark.js';

// Run on this site's origin in a modern browser, after explicit file selection.
const files = [...document.querySelector('input[type="file"]').files];
const recipe = createRecipe('filename'); // watermark | filename | date | frame
const errors = validateRecipe(recipe);
if (errors.length) throw new Error(errors.join('; '));
const records = [];
try {
  for (const file of files) records.push(await inspectImage(file));
  const result = await processBatch(records, recipe);
  if (result.failures.length || result.cancelled) {
    console.warn('Check partial results before downloading', result);
  }
  if (result.entries.length) {
    const zip = await packageResults(result.entries);
    const url = URL.createObjectURL(zip);
    const link = document.createElement('a');
    link.href = url; link.download = 'labeled-photos.zip'; link.click();
    setTimeout(() => URL.revokeObjectURL(url), 30000);
  }
} finally {
  records.forEach(record => URL.revokeObjectURL(record.thumbnail));
}
```

| ฟังก์ชั่น | อินพุต → ผลลัพธ์ |
| --- | --- |
| createRecipe(mode) | watermark \| filename \| date \| frame → สูตร v1 อิสระ |
| validateRecipe(recipe) | ข้อผิดพลาดของสูตร → สตริง[]; ว่างเปล่าหมายถึงการกำหนดค่าถูกต้อง การตรวจสอบความหมายยังตรวจสอบ ID ที่ไม่ซ้ำกันและขอบเขตการครอบตัดอีกด้วย |
| inspectImage(file) | File → Promise<Record> พร้อมด้วย id, ชื่อ, ไฟล์, ความกว้าง, ความสูง, URL วัตถุรูปขนาดย่อ, การแทนที่, ข้อมูลเมตา, ข้อมูลเมตาคำเตือน เพิกถอนภาพขนาดย่อเมื่อเสร็จสิ้น `{id,name,file,width,height,thumbnail,overrides,metadata,metadataWarning}` |
| renderImage(record, recipe, options?) | → Promise<{blob, geometry}>; preview:true ส่งคืน {canvas, geometry} ตัวเลือก: สินทรัพย์:Map<assetId,ImageBitmap\|Canvas>, ดัชนี:หมายเลข, maxDimension:number, แคนวาส:Canvas missingMetadataText?:string. `{blob,geometry} \| {canvas,geometry}` |
| processBatch(records, recipe, options?) | → Promise<{entries,failures,cancelled}> รายการ: {name,blob,width,height,sourceId}; ความล้มเหลว: {id,name,longEdge,message} ตัวเลือก: สินทรัพย์, สัญญาณ:AbortSignal, onProgress({done,total,failed}), onResult(รายการ) missingMetadataText?:string. `{entries:[{name,blob,width,height,sourceId}],failures:[{id,name,longEdge,message}],cancelled}` |
| packageResults(entries) | → Promise<Blob> ZIP; ปฏิเสธเมื่อเอาต์พุตรวมเกิน 450 MiB |
| decodeImage(blob) | → Promise<ImageBitmap>; close() เมื่อเสร็จแล้ว HEIC ใช้อิมเมจที่ถอดรหัสครั้งแรก |
| parseLabelCsv(text) | filename,text CSV → Map<สตริง,สตริง>; ตรงกันทุกประการ ชื่อซ้ำปฏิเสธ ตั้งค่า record.label ด้วยตัวเองก่อนประมวลผล |
| imageRecipe(recipe, record) | ผสาน record.overrides.image และ record.overrides.layers[id] โดยไม่ต้องเปลี่ยนสูตรที่แชร์ |
| renderStudioImage / cleanLogo | ตัวช่วย Canvas ระดับต่ำ; ดูแพ็คเกจพื้นที่เก็บข้อมูล/watermark-core/src/studio.js สำหรับลายเซ็น ต้องการ renderImage สำหรับเอาต์พุตที่เข้ารหัส |


## กฎและข้อผิดพลาดของสูตร

ดาวน์โหลดสูตรอาหารแบบเต็มจาก /api/v1/recipes/watermark.json, filename.json, date.json หรือ frame.json ตรวจสอบความถูกต้องของ JSON Schema ก่อน จากนั้นจึงตรวจสอบ validateRecipe สำหรับการตรวจสอบความหมาย รหัสเลเยอร์ต้องไม่ซ้ำกัน ครอบตัด x + ความกว้าง และ y + ความสูงจะต้องอยู่ภายในรูปภาพ ขนาด ระยะขอบ เส้นขอบ และส่วนท้ายใช้เปอร์เซ็นต์ของขอบสั้นของรูปภาพที่ครอบตัดและหมุน เอาต์พุต longEdge:0 เก็บขนาด; การปรับขนาดไม่เคยเพิ่มขนาด image.crop.aspectRatio เป็นตัวเลือกอัตราส่วนความกว้าง/สูงของเนื้อหาหลังหมุน แต่ละภาพจะถูกครอบตรงกลางพื้นที่เลือกที่ปรับเป็นสัดส่วน แม้ขนาดภาพต่างกัน จากนั้นจึงเพิ่มกรอบและส่วนท้าย การแก้เปอร์เซ็นต์ด้วยตนเองจะยกเลิกกฎอัตราส่วน

ตัวแปรข้อความ: {filename} ไม่รวมส่วนขยาย; {fullname} รวมไว้ด้วย; {index} ใช้ sequence.start และช่องว่างภายใน {label} ใช้ record.label ตัวแปรกล้องคือ {camera}, {lens}, {aperture}, {iso}, {shutter}, {focal} CSV จะไม่เติมบันทึก SDK โดยอัตโนมัติ

วันที่ที่ตั้งไว้ล่วงหน้าจะใช้ DateTimeOriginal หรือ CreateDate ของแต่ละภาพ ไม่มีการทดแทนวันที่แก้ไขไฟล์ วันที่ที่หายไปจะเป็นค่าเริ่มต้นสำหรับป้ายกำกับวันที่ว่างเปล่า missing:error ทำให้อิมเมจนั้นล้มเหลว missing:custom จะใช้ date.custom หากแยกวิเคราะห์ได้ source:custom ใช้วันที่ที่ให้มาโดยตรง วันที่ที่กำหนดเองไม่ได้รับการรับรองการประทับเวลา วันที่ที่ไม่ถูกต้องอาจทำให้ป้ายกำกับว่างเปล่าหรือมีข้อผิดพลาดตามนโยบายนี้

สูตรอาหารประกอบด้วยการตั้งค่า ไม่ใช่ไบต์ของโลโก้หรือแบบอักษรที่กำหนดเอง จัดหาโลโก้ผ่าน options.assets ที่คีย์โดย layer.assetId และปิดบิตแมปโลโก้ที่ถอดรหัสหลังการใช้งาน ต้องโหลดแบบอักษรที่กำหนดเองลงใน document.fonts ภายใต้ตระกูล LocalFont ทรัพยากรที่หายไปล้มเหลวอย่างชัดเจน

SDK ส่งหาสูตรที่ไม่ถูกต้องก่อนดำเนินการแบบแบตช์ ข้อผิดพลาดในการถอดรหัส การเรนเดอร์ ข้อมูลเมตา หรือการเข้ารหัสต่อภาพปรากฏใน failures ในขณะที่ entries ที่สำเร็จยังคงอยู่ ข้อผิดพลาดในปัจจุบันประกอบด้วยข้อความภาษาจีนที่มนุษย์สามารถอ่านได้ ผู้บริโภคไม่ควรแตกแยกจากข้อความของพวกเขา มีการตรวจสอบการยกเลิกระหว่างเอาต์พุต การเรนเดอร์ปัจจุบันจะไม่ถูกขัดจังหวะ ด้วย onResult นั้น entries จะถูกส่งไปยังการโทรกลับ และจะไม่ถูกเก็บไว้ในอาร์เรย์ entries ที่ส่งคืน




## ข้อจำกัดและความเป็นส่วนตัว

ไม่มีโควต้าการนับรูปภาพ, บัญชี, คีย์ API, การสมัครสมาชิก หรือการเพิ่มแบรนด์ไซต์ แต่ละอินพุตจำกัดอยู่ที่ 150 MiB และ 120 ล้านพิกเซล เอาต์พุต ZIP ถูกจำกัดไว้ที่ 450 MiB สูงสุด 30 เลเยอร์, ​​ขนาดเอาต์พุตเพิ่มเติม 6 ขนาด, ขอบยาวสูงสุด 32768 เบราว์เซอร์ Canvas, หน่วยความจำ, ตัวถอดรหัส และระบบไฟล์สามารถลดขีดจำกัดลงได้ แบ่งชุดใหญ่

เอาต์พุตเป็น JPEG, PNG หรือ WebP JPEG และ WebP ที่สูญหายได้รับการเข้ารหัสใหม่ โหมดข้อมูลเมตาเริ่มต้นคือ strip โหมด "safe" และ "all" ต้องใช้เอาต์พุต JPEG โหมด safe ไม่รวม GPS; โหมด all สามารถเก็บข้อมูลเมตาของตำแหน่งได้ โปรไฟล์ ICC, HDR และลายเซ็นจะไม่ถูกรักษาไว้ ไฟล์ต้นฉบับจะไม่มีการเปลี่ยนแปลง

เฉพาะทรัพยากรของโปรแกรมเท่านั้นที่จะสามารถเลือกแคชสำหรับการใช้งานออฟไลน์ใน /studio/. หน้าสาธารณะใหม่จำเป็นต้องมีการเชื่อมต่อเครือข่ายจึงจะโหลดได้ในตอนแรก รูปภาพและชื่อไฟล์ของผู้ใช้จะไม่ถูกส่งไปยัง API สาธารณะหรือจัดเก็บไว้ในค่าที่ตั้งล่วงหน้า บันทึก/แชร์เฉพาะสูตรอาหารที่ไม่มีข้อความส่วนตัว




## MCP ท้องถิ่น

ความสามารถนี้มาจากพื้นที่เก็บข้อมูล ไม่ใช่จุดสิ้นสุดอินเทอร์เน็ต ข้อกำหนดเบื้องต้น: ติดตั้ง Node.js, pnpm ในพื้นที่เก็บข้อมูล และติดตั้ง Google Chrome รันเซิร์ฟเวอร์จากพื้นที่เก็บข้อมูล โดยมีไดเร็กทอรีที่อนุญาตอย่างชัดเจน อย่าอนุมานเส้นทางระบบไฟล์ส่วนตัวจากผลการค้นหาเว็บ



```
node scripts/watermark-mcp.mjs --root /absolute/authorized/photo-folder
```

| เครื่องมือ | อินพุตและผลลัพธ์ |
| --- | --- |
| validate_recipe | {recipe} → {errors:string[]} ไม่อ่านภาพ |
| inspect_images | {files:string[]} → {images:[{id,name,width,height,metadata,metadataWarning}],failures:[{id,name,index,stage,message}]}. |
| preview_watermark | {files,recipe,output?,logos?} → {files:[{path,width,height}],failures,cancelled} เขียนเฉพาะภาพแรก ขอบที่ยาวที่สุด ≤1400 |
| batch_watermark | {files,recipe,output?,logos?} → {files:[{path,width,height}],failures,cancelled} เขียนแต่ละภาพ ไม่ใช่ ZIP |
เส้นทางอินพุตใน files ได้รับการแก้ไขภายใน --root แผนที่ logos เชื่อมโยงรหัสสินทรัพย์กับเส้นทางภายในรูทเดียวกัน ค่าเริ่มต้น output คือ watermark-output ภายในรูท เส้นทางที่แน่นอนจะต้องอยู่ภายในรูทนี้ด้วย การหลีกลิงก์สัญลักษณ์จะถูกปฏิเสธ ไฟล์ที่มีอยู่จะถูกเก็บรักษาไว้โดยการเลือกชื่อไฟล์เอาต์พุตใหม่ สคีมาแสดงตัวอย่างและประมวลผลชุดกำหนดให้มี recipe ส่วน inspect_images รับเฉพาะ files ภาพที่เสียจะอยู่ใน failures และภาพที่ใช้ได้จะประมวลผลต่อ index เริ่มจาก 0 ในอาร์เรย์ files เดิม และ stage เป็น inspect หรือ render ตัวอย่างจะประมวลผลเฉพาะ files[0] โดยไม่แทนด้วยภาพอื่น คำขอที่ไม่ถูกต้องส่งคืน isError พร้อมข้อความ ข้อผิดพลาดในการประมวลผลแต่ละรายการยังคงอยู่ใน failures การโทรเป็นการร้องขอ/ตอบกลับ และไม่มีเครื่องมือในการยกเลิก

MCP ส่งคืน JSON ที่ทำให้เป็นอนุกรมภายใน content[0].text ไม่ใช่ structuredContent การตรวจสอบและตรวจสอบเป็นแบบอ่านอย่างเดียว ดูตัวอย่างและเขียนสำเนาเป็นชุด ไม่มีเครื่องมืออัพโหลดรูปภาพ ไคลเอ็นต์ต้องกำหนดค่าคำสั่ง stdio ในเครื่องนี้อย่างชัดเจนก่อนที่จะใช้เครื่องมือ