좌표와 경계 상자

좌표와 경계 상자 (Coordinates and bounding boxes)

Claude는 이미지의 영역을 찾고 라벨을 붙일 수 있어요(예: 표, 폼 필드, 차트 요소, UI 컴포넌트에 대한 경계 상자 반환). 이 가이드는 Claude가 처리 전에 이미지를 크기 조정하는 방식과, 반환하는 픽셀 좌표로 작업하는 방법을 다뤄서, 상자와 점이 원본 이미지와 맞도록 해줘요.

출처: 문서

본문

Claude는 이미지의 영역을 찾고 라벨을 붙일 수 있어요(예: 표, 폼 필드, 차트 요소, UI 컴포넌트에 대한 경계 상자 반환). 이 가이드는 Claude가 처리 전에 이미지를 크기 조정하는 방식과, 반환하는 픽셀 좌표로 작업하는 방법을 다뤄서, 상자와 점이 원본 이미지와 맞도록 해줘요.

이것은 OCR 파이프라인, 폼 추출, 차트 파싱, UI 요소 위치, 그리고 이미지의 특정 영역에 대해 행동하는 모든 과제에 필요해요. 이미지 보내기, 지원 형식, 모델별 해상도 한계는 Vision을 보세요.

**Claude는 절대 픽셀 좌표로 가장 잘 작동해요.** 프롬프트에서 명시적으로 요청하세요. 예: *"Return the bounding box of each table as `[x1, y1, x2, y2]` (top-left and bottom-right corners) in pixel coordinates."* Claude는 정규화된 좌표를 요청하면 잘 작동하지 않아요. 예: *"Return bounding box coordinates between `0` and `1000`."* 항상 픽셀 좌표를 요청하고, 필요하면 자신의 코드에서 정규화하세요. 산문 대신 기계가 읽을 수 있는 JSON으로 좌표를 얻으려면 [구조화된 출력](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)으로 스키마를 정의하세요. 예를 들어 감지된 요소마다 `[x1, y1, x2, y2]` 배열을 가진 객체처럼요.

좌표는 표준 이미지 규칙을 따라요: 원점 (0, 0)은 이미지의 왼쪽 위 모서리이고, x는 오른쪽으로, y는 아래로 증가해요. Claude가 반환하는 좌표는 Claude가 보는 이미지의 픽셀 위치예요: Claude가 모델의 네이티브 해상도에 맞게 크기 조정한 뒤의 여러분 이미지예요(Claude가 이미지를 크기 조정하고 패딩하는 방식 참고). 직접 쓸 수 있는 좌표를 얻으려면, 좌표가 가진 이미지에 일대일로 매핑되도록 이미지를 미리 조정하거나(업로드 전에 이미지 크기 조정), Claude가 반환한 좌표를 다시 조정하세요(미리 조정할 수 없을 때 좌표 다시 조정).

Claude의 공간 추론에는 한계가 있어요([한계](https://platform.claude.com/docs/en/build-with-claude/vision#limitations) 참고). 좌표 정확도는 프롬프트에서 기대 좌표 형식을 명시하고, 대규모로 처리하기 전에 결과를 시각적으로 스팟 체크할 때 가장 좋아요. 작은 요소는 이미지가 축소되면 정밀도를 잃어요. 미세한 대상을 위해서는 관심 영역을 잘라내고 그 잘라낸 부분을 보내거나(잘라낸 원점만큼 반환 좌표를 오프셋), 고해상도 계층 모델을 쓰세요. [PDF 지원](https://platform.claude.com/docs/en/build-with-claude/pdf-support)에서는 페이지가 여러분이 제어하지 않는 크기로 서버 측에서 이미지로 래스터화되므로, 반환된 좌표를 페이지에 안정적으로 매핑할 수 없어요. PDF 콘텐츠에서 좌표로 작업하려면 페이지를 직접 이미지로 래스터화하고 미리 조정 접근을 쓰세요.

Claude가 이미지를 크기 조정하고 패딩하는 방식

Claude는 모델의 두 이미지 한계를 모두 만족하는 가장 큰 종횡비 보존 크기를 찾아요:

  1. 변 한계: 어느 변도 최대 변 길이(표준 계층 1568 px, 고해상도 계층 2576 px)를 초과하지 않아요.
  2. 시각 토큰 한계: 이미지의 토큰 비용 ⌈width / 28⌉ × ⌈height / 28⌉이 모델의 시각 토큰 예산(표준 계층 1568 토큰, 고해상도 계층 4784)을 초과하지 않아요.

어떤 모델이 어느 계층인지 해상도와 토큰 비용을 보세요.

거의 모든 사진과 스크린샷에서 시각 토큰 한계가 최종 크기를 결정해요. 변 한계는 파노라마나 긴 폰 스크린샷 같은 길쭉한 이미지에서만 작동해요. 크기를 손으로 변 길이로 조정하지 말고 참조 구현으로 계산하세요: 1920×1080 스크린샷은 1456×819로 조정되지, 1568×882로 조정되지 않아요. 변 한계를 가정하면 모든 좌표가 눈에 띄게 벗어나요.

토큰 한계는 어느 변도 변 한계를 초과하지 않을 때도 크기 조정을 촉발할 수 있어요. 이걸 간과하는 것이 좌표 불일치의 가장 흔한 원인이에요. 예를 들어 130 DPI로 스캔한 A4 페이지는 1075×1520 픽셀인데: 두 변 모두 1568 px 미만이지만 39 × 55 = 2145 시각 토큰이 들어서, Claude는 그것을 924×1307로 조정해요.

이 예시는 표준 해상도 계층의 모델을 가정해요. 고해상도 계층 모델은 같은 스캔을 조정하지 않아요: 2145 토큰은 4784 토큰 예산 안이므로, 반환하는 좌표가 1075×1520 원본에 직접 매핑돼요. 모델 계층은 [해상도와 토큰 비용](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size)에 나열돼 있어요.

Claude는 그다음 조정 여부와 무관하게 모든 이미지를 아래쪽과 오른쪽 변에서 28픽셀의 다음 배수까지 패딩해요(예시에서 924×1307이 924×1316이 돼요). 패딩에는 콘텐츠가 없어요: Claude는 패딩된 이미지를 인식하지만, 페이지 콘텐츠는 항상 패딩되지 않은 조정된 영역만 차지해요. 항상 패딩된 크기가 아니라 조정된 크기로 정규화하거나 다시 조정하세요. 패딩된 크기로 나누면 모든 좌표가 작은 양만큼 축소돼요.

업로드 전에 이미지 크기 조정하기

가장 안정적인 접근은 업로드 전에 이미지 크기를 직접 조정해서, 가진 이미지가 정확히 Claude가 보는 이미지가 되고 반환 좌표가 변환을 필요로 하지 않게 하는 거예요.

먼저 모델이 어느 해상도 계층에 있는지 확인하고(해상도와 토큰 비용 참고), 일치하는 변·토큰 한계를 전달하세요. 다음 참조 구현은 Claude가 이미지를 조정하는 정확한 크기를 계산해요:

```bash cURL # This reference implementation is local math that makes no API request, so # there's nothing to show for cURL. See the SDK tabs. ```
# This reference implementation is local math that makes no API request, so
# there's nothing to show for the CLI. See the SDK tabs.
import math


def count_image_tokens(width: int, height: int) -> int:
    """Visual tokens consumed by an image: one token per 28x28 pixel patch."""
    return math.ceil(width / 28) * math.ceil(height / 28)


def resized_size(
    width: int,
    height: int,
    max_edge: int = 1568,
    max_tokens: int = 1568,
) -> tuple[int, int]:
    """The size Claude resizes an image to before padding.

    Defaults are for the standard resolution tier. For high-resolution-tier
    models, use max_edge=2576 and max_tokens=4784. Returns (width, height).
    Images that already fit within the limits are returned unchanged.
    """

    def fits(w: int, h: int) -> bool:
        return (
            math.ceil(w / 28) * 28 <= max_edge
            and math.ceil(h / 28) * 28 <= max_edge
            and count_image_tokens(w, h) <= max_tokens
        )

    if fits(width, height):
        return (width, height)
    if height > width:
        resized_h, resized_w = resized_size(height, width, max_edge, max_tokens)
        return (resized_w, resized_h)

    # Binary search along the long edge for the largest aspect-preserving
    # size that fits.
    aspect_ratio = width / height
    lo, hi = 1, width  # lo always fits; hi never fits
    while lo + 1 < hi:
        mid = (lo + hi) // 2
        if fits(mid, max(round(mid / aspect_ratio), 1)):
            lo = mid
        else:
            hi = mid
    return (lo, max(round(lo / aspect_ratio), 1))


# The A4 example from "How Claude resizes and pads images":
print(resized_size(1075, 1520))  # (924, 1307)

# To apply the resize, use your image library, for example Pillow:
# image.resize(resized_size(*image.size))
/** Visual tokens consumed by an image: one token per 28x28 pixel patch. */
function countImageTokens(width: number, height: number): number {
  return Math.ceil(width / 28) * Math.ceil(height / 28);
}

/**
 * Round half to even (banker's rounding), matching Python's round(). The
 * live API resolves exact .5 ties toward the even neighbor, so Math.round
 * (which rounds halves up) would compute a different size for some images.
 */
function roundTiesToEven(value: number): number {
  const floor = Math.floor(value);
  if (value - floor !== 0.5) return Math.round(value);
  return floor % 2 === 0 ? floor : floor + 1;
}

/**
 * The size Claude resizes an image to before padding.
 *
 * Defaults are for the standard resolution tier. For high-resolution-tier
 * models, use maxEdge = 2576 and maxTokens = 4784. Returns [width, height].
 * Images that already fit within the limits are returned unchanged.
 */
function resizedSize(
  width: number,
  height: number,
  maxEdge = 1568,
  maxTokens = 1568
): [number, number] {
  const fits = (w: number, h: number): boolean =>
    Math.ceil(w / 28) * 28 <= maxEdge &&
    Math.ceil(h / 28) * 28 <= maxEdge &&
    countImageTokens(w, h) <= maxTokens;

  if (fits(width, height)) return [width, height];
  if (height > width) {
    const [resizedH, resizedW] = resizedSize(height, width, maxEdge, maxTokens);
    return [resizedW, resizedH];
  }

  // Binary search along the long edge for the largest aspect-preserving
  // size that fits.
  const aspectRatio = width / height;
  let lo = 1; // lo always fits
  let hi = width; // hi never fits
  while (lo + 1 < hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (fits(mid, Math.max(roundTiesToEven(mid / aspectRatio), 1))) {
      lo = mid;
    } else {
      hi = mid;
    }
  }
  return [lo, Math.max(roundTiesToEven(lo / aspectRatio), 1)];
}

// The A4 example from "How Claude resizes and pads images":
console.log(resizedSize(1075, 1520)); // [ 924, 1307 ]

// To apply the resize, use your image library, for example sharp:
// await sharp(input).resize(width, height).toBuffer()
// Visual tokens consumed by an image: one token per 28x28 pixel patch.
static int CountImageTokens(int width, int height)
{
    return (width + 27) / 28 * ((height + 27) / 28); // ceil(w/28) * ceil(h/28)
}

// The size Claude resizes an image to before padding. Defaults are for the
// standard resolution tier; for high-resolution-tier models, pass
// maxEdge: 2576, maxTokens: 4784. Images that already fit within the limits
// are returned unchanged.
static (int Width, int Height) ResizedSize(
    int width, int height, int maxEdge = 1568, int maxTokens = 1568)
{
    bool Fits(int w, int h) =>
        (w + 27) / 28 * 28 <= maxEdge
        && (h + 27) / 28 * 28 <= maxEdge
        && CountImageTokens(w, h) <= maxTokens;

    if (Fits(width, height))
    {
        return (width, height);
    }
    if (height > width)
    {
        (int resizedH, int resizedW) = ResizedSize(height, width, maxEdge, maxTokens);
        return (resizedW, resizedH);
    }

    // Binary search along the long edge for the largest aspect-preserving
    // size that fits. The short edge rounds half to even, matching the live
    // API at exact .5 ties (MidpointRounding.ToEven, Math.Round's default).
    double aspectRatio = (double)width / height;
    int lo = 1; // lo always fits
    int hi = width; // hi never fits
    while (lo + 1 < hi)
    {
        int mid = (lo + hi) / 2;
        if (Fits(mid, ShortEdge(mid)))
        {
            lo = mid;
        }
        else
        {
            hi = mid;
        }
    }
    return (lo, ShortEdge(lo));

    int ShortEdge(int longEdge) =>
        Math.Max((int)Math.Round(longEdge / aspectRatio, MidpointRounding.ToEven), 1);
}

// The A4 example from "How Claude resizes and pads images":
Console.WriteLine(ResizedSize(1075, 1520)); // (924, 1307)
// countImageTokens is the visual tokens consumed by an image: one token per
// 28x28 pixel patch.
func countImageTokens(width, height int) int {
	return ((width + 27) / 28) * ((height + 27) / 28) // ceil(w/28) * ceil(h/28)
}

// resizedSize is the size Claude resizes an image to before padding, as
// (width, height). Pass maxEdge 1568 and maxTokens 1568 for the standard
// resolution tier, or 2576 and 4784 for the high-resolution tier. Images
// that already fit within the limits are returned unchanged.
// The A4 example from "How Claude resizes and pads images":
// resizedSize(1075, 1520, 1568, 1568) returns (924, 1307).
func resizedSize(width, height, maxEdge, maxTokens int) (int, int) {
	fits := func(w, h int) bool {
		return ((w+27)/28)*28 <= maxEdge &&
			((h+27)/28)*28 <= maxEdge &&
			countImageTokens(w, h) <= maxTokens
	}

	if fits(width, height) {
		return width, height
	}
	if height > width {
		resizedH, resizedW := resizedSize(height, width, maxEdge, maxTokens)
		return resizedW, resizedH
	}

	// Binary search along the long edge for the largest aspect-preserving
	// size that fits. The short edge rounds half to even (math.RoundToEven),
	// matching the live API at exact .5 ties; math.Round would round them up.
	aspectRatio := float64(width) / float64(height)
	lo, hi := 1, width // lo always fits; hi never fits
	for lo+1 < hi {
		mid := (lo + hi) / 2
		short := max(int(math.RoundToEven(float64(mid)/aspectRatio)), 1)
		if fits(mid, short) {
			lo = mid
		} else {
			hi = mid
		}
	}
	return lo, max(int(math.RoundToEven(float64(lo)/aspectRatio)), 1)
}

/** A resized image size, as returned by resizedSize. */
record Size(int width, int height) {}

/** Visual tokens consumed by an image: one token per 28x28 pixel patch. */
static int countImageTokens(int width, int height) {
    return Math.ceilDiv(width, 28) * Math.ceilDiv(height, 28);
}

/**
 * The size Claude resizes an image to before padding.
 *
 * <p>Pass maxEdge 1568 and maxTokens 1568 for the standard resolution tier,
 * or 2576 and 4784 for the high-resolution tier. Images that already fit
 * within the limits are returned unchanged.
 *
 * <p>The A4 example from "How Claude resizes and pads images":
 * resizedSize(1075, 1520, 1568, 1568) returns new Size(924, 1307).
 */
static Size resizedSize(int width, int height, int maxEdge, int maxTokens) {
    if (fits(width, height, maxEdge, maxTokens)) {
        return new Size(width, height);
    }
    if (height > width) {
        Size rotated = resizedSize(height, width, maxEdge, maxTokens);
        return new Size(rotated.height(), rotated.width());
    }

    // Binary search along the long edge for the largest aspect-preserving
    // size that fits. The short edge rounds half to even (Math.rint),
    // matching the live API at exact .5 ties; Math.round would round them up.
    double aspectRatio = (double) width / height;
    int lo = 1; // lo always fits
    int hi = width; // hi never fits
    while (lo + 1 < hi) {
        int mid = (lo + hi) / 2;
        if (fits(mid, shortEdge(mid, aspectRatio), maxEdge, maxTokens)) {
            lo = mid;
        } else {
            hi = mid;
        }
    }
    return new Size(lo, shortEdge(lo, aspectRatio));
}

private static boolean fits(int width, int height, int maxEdge, int maxTokens) {
    return Math.ceilDiv(width, 28) * 28 <= maxEdge
            && Math.ceilDiv(height, 28) * 28 <= maxEdge
            && countImageTokens(width, height) <= maxTokens;
}

private static int shortEdge(int longEdge, double aspectRatio) {
    return Math.max((int) Math.rint(longEdge / aspectRatio), 1);
}
// Visual tokens consumed by an image: one token per 28x28 pixel patch.
function countImageTokens(int $width, int $height): int
{
    return intdiv($width + 27, 28) * intdiv($height + 27, 28);
}

/**
 * The size Claude resizes an image to before padding, as [width, height].
 *
 * Defaults are for the standard resolution tier. For high-resolution-tier
 * models, pass maxEdge: 2576, maxTokens: 4784. Images that already fit
 * within the limits are returned unchanged.
 */
function resizedSize(int $width, int $height, int $maxEdge = 1568, int $maxTokens = 1568): array
{
    $fits = fn (int $w, int $h): bool =>
        intdiv($w + 27, 28) * 28 <= $maxEdge
        && intdiv($h + 27, 28) * 28 <= $maxEdge
        && countImageTokens($w, $h) <= $maxTokens;

    if ($fits($width, $height)) {
        return [$width, $height];
    }
    if ($height > $width) {
        [$resizedH, $resizedW] = resizedSize($height, $width, $maxEdge, $maxTokens);
        return [$resizedW, $resizedH];
    }

    // Binary search along the long edge for the largest aspect-preserving
    // size that fits. The short edge rounds half to even
    // (PHP_ROUND_HALF_EVEN), matching the live API at exact .5 ties.
    $aspectRatio = $width / $height;
    $lo = 1; // lo always fits
    $hi = $width; // hi never fits
    while ($lo + 1 < $hi) {
        $mid = intdiv($lo + $hi, 2);
        $short = max((int) round($mid / $aspectRatio, 0, PHP_ROUND_HALF_EVEN), 1);
        if ($fits($mid, $short)) {
            $lo = $mid;
        } else {
            $hi = $mid;
        }
    }

    return [$lo, max((int) round($lo / $aspectRatio, 0, PHP_ROUND_HALF_EVEN), 1)];
}

// The A4 example from "How Claude resizes and pads images":
[$resizedWidth, $resizedHeight] = resizedSize(1075, 1520);
echo "({$resizedWidth}, {$resizedHeight})\n"; // (924, 1307)
# Visual tokens consumed by an image: one token per 28x28 pixel patch.
def count_image_tokens(width, height)
  width.ceildiv(28) * height.ceildiv(28)
end

# The size Claude resizes an image to before padding, as [width, height].
#
# Defaults are for the standard resolution tier. For high-resolution-tier
# models, pass max_edge: 2576, max_tokens: 4784. Images that already fit
# within the limits are returned unchanged.
def resized_size(width, height, max_edge = 1568, max_tokens = 1568)
  fits = lambda do |w, h|
    w.ceildiv(28) * 28 <= max_edge &&
      h.ceildiv(28) * 28 <= max_edge &&
      count_image_tokens(w, h) <= max_tokens
  end

  return [width, height] if fits.call(width, height)

  if height > width
    resized_h, resized_w = resized_size(height, width, max_edge, max_tokens)
    return [resized_w, resized_h]
  end

  # Binary search along the long edge for the largest aspect-preserving
  # size that fits. The short edge rounds half to even (round(half: :even)),
  # matching the live API at exact .5 ties.
  aspect_ratio = width.fdiv(height)
  lo = 1      # lo always fits
  hi = width  # hi never fits
  while lo + 1 < hi
    mid = (lo + hi) / 2
    short = [(mid / aspect_ratio).round(half: :even), 1].max
    if fits.call(mid, short)
      lo = mid
    else
      hi = mid
    end
  end

  [lo, [(lo / aspect_ratio).round(half: :even), 1].max]
end

# The A4 example from "How Claude resizes and pads images":
p resized_size(1075, 1520) # => [924, 1307]
  1. 이미지를 크기 조정 헬퍼가 반환한 크기로 조정하세요. 이미지가 이미 모델의 한계 안에 있으면, 헬퍼가 크기를 그대로 반환하고 조정이 필요 없어요.
  2. 조정된 이미지를 API에 보내세요. 직접 패딩하지 마세요. Claude가 패딩을 처리하고, 패딩은 좌표 원점을 이동시키지 않아요.
  3. 프롬프트에서 픽셀 좌표를 명시적으로 요청하세요. 예: "Return the click point for the Submit button as [x, y] in pixel coordinates."
  4. 보낸 이미지에 대해 반환 좌표를 직접 쓰세요. 정규화된 좌표가 필요하면, 보낸 이미지의 크기로 나누세요. 원본 이미지의 크기로도, 패딩된 크기로도 나누지 마세요.
[토큰 계산](https://platform.claude.com/docs/en/build-with-claude/token-counting) 엔드포인트는 이미지를 완전히 처리하지 않고 크기에서 토큰 비용을 추정하므로, 성공적인 계산이 이미지가 Messages API의 [요청 한계](https://platform.claude.com/docs/en/build-with-claude/vision#request-limits) 안에 있다는 뜻은 아니에요. 이미지가 계산에 성공했어도 보낼 때 거부될 수 있어요.

transformations로 크기 조정을 오류로 바꾸기

미리 조정은 파이프라인이 올바른 크기를 계속 만들어내는 동안만 좌표를 보호해요. 새 이미지 소스나 다른 해상도 계층의 모델 전환은 서버 측 크기 조정을 조용히 다시 유발할 수 있어요. 그 조용한 드리프트를 눈에 보이는 오류로 바꾸려면 Messages 요청의 이미지 콘텐츠 블록에 선택적 transformations 필드를 설정하세요:

{
  "type": "image",
  "source": { "type": "base64", "media_type": "image/png", "data": "..." },
  "transformations": { "oversized_image": "error" }
}

표시된 이미지("oversized_image": "error"를 설정한 어떤 블록)가 조정될 요청은 이미지의 크기와 맞는 가장 큰 크기를 밝히는 400 invalid_request_error로 거부돼요. 이미지가 거부를 촉발하는지 여부는 요청이 명명하는 모든 모델의 한계에 달려 있어요: 아래 1920×1080 예시는 표준 계층 모델이 거부하지만 고해상도 계층 안에는 맞아요:

messages.0.content.0: image dimensions 1920x1080 exceed the maximum image size of a model named on this request and would be downsized to 1456x819; scale the image to at most 1456x819 or set the image's oversized_image setting to "downsize"

보고된 대상으로 다시 조정하고 재전송하세요: 대상은 요청이 명명하는 모든 모델이 받아들이는, 여러분 이미지 종횡비의 가장 큰 크기예요. 표시된 이미지가 서버 측 폴백 베타와 어떻게 상호작용하는지는 그 기능과 함께 설명돼요. 모든 모드에서 표시된 이미지는 절대 조정된 채로 서빙되지 않아요.

설정은 이미지별이에요. "oversized_image": "downsize"(필드 생략 시 기본)는 이 페이지에 설명된 대로 자동 크기 조정을 유지해요. 각 이미지 블록은 자신의 설정에만 대해 검사되므로, 한 요청이 크기가 중요한 이미지(클릭할 스크린샷)와 크기 조정이 무해한 이미지(로고)를 섞을 수 있어요. 설정이 바꾸는 것과 바꾸지 않는 것:

  • 패딩(절대 콘텐츠를 버리지 않는 것), 형식 변환, 방향 보정은 평소처럼 진행돼요.
  • 하드 한계(가장 긴 변 8000 px, many-image 요청의 더 엄격한 이미지당 한계)는 별개의 거부예요. 이 설정이 이미지를 그걸 넘게 통과시키지는 않아요.
  • URL이나 파일 ID로 제공된 이미지는 바이트를 가져온 뒤 검사돼요. 그 거부는 앞의 위치 없이 같은 메시지를 담아 어떤 이미지가 실패했는지 식별하지 못해요. 임베디드 base64 이미지만 오류에서 위치로 이름이 붙어요.
  • PDF 페이지는 여러분이 제어하지 않는 크기로 서버 측에서 래스터화돼요. document 블록은 필드를 받지 않아요(문서 콘텐츠 안에 중첩된 이미지 블록은 다른 것처럼 받아요).
  • 크기를 결정할 수 없는 표시 이미지는 통과시키는 대신 거부돼요: 그 거부는 위에 인용된 크기 조정 메시지가 아니라 이미지의 소스 크기를 결정할 수 없다고 보고해요. "error"를 설정한 이미지는 조정된 채로 모델에 도달하지 않아요.

토큰 계산 엔드포인트 역시 transformations를 존중해서, 임베디드 이미지를 Messages API가 거부하는 것과 똑같이 거부해요. 따라서 추론을 실행하기 전에 임베디드 이미지가 조정되지 않고 맞는지 확인할 수 있어요. 계산은 URL이나 파일 ID로 제공된 이미지를 가져오지 않고 거부하므로, 그 소스의 표시 이미지는 Messages 시점에만 검사돼요.

미리 조정할 수 없을 때 좌표 다시 조정하기

미리 조정할 수 없다면(예: 수정할 수 없는 업스트림 시스템에서 이미지가 올 때), 업로드 전에 이미지 크기 조정의 크기 조정 헬퍼를 사용해 Claude가 본 크기를 복구하고, Claude가 반환한 좌표를 정규화된 좌표나 원본 이미지로 매핑하세요. 이미지가 대신 오류를 선택하지 않는 한, Claude는 거대한 이미지를 거부하지 않고 축소해요. API의 요청 한계까지요. 그 한계를 넘으면 요청이 검증 오류로 실패해요. 호출한 모델과 일치하는 계층 한계를 전달하세요: 틀린 계층의 한계는 틀린 조정 크기를 복구하고 모든 좌표를 조용히 이동시켜요. 이 접근은 업로드한 이미지의 픽셀 크기를 알아야 하므로 PDF 업로드에는 적용되지 않아요.

computer usebrowser use 도구셋에 반환하는 스크린샷과 줌 이미지는 자동 크기 조정의 예외예요. API는 모델 한계를 초과하는 tool_result 이미지를 조정하지 않고 검증 오류로 거부해요. 그런 이미지는 반환하기 전에 애플리케이션에서 크기를 조정한 뒤, Claude가 반환한 좌표를 화면 크기로 다시 조정하세요.

```bash cURL # This local coordinate conversion makes no API request, so there's nothing # to show for cURL. See the SDK tabs. ```
# This local coordinate conversion makes no API request, so there's nothing
# to show for the CLI. See the SDK tabs.
# This helper calls resized_size from the resize example on this page.
def to_relative_coordinates(
    x: float,
    y: float,
    original_width: int,
    original_height: int,
    max_edge: int = 1568,
    max_tokens: int = 1568,
) -> tuple[float, float]:
    """Map a pixel coordinate returned by Claude to relative coordinates in [0, 1].

    Pass the dimensions of the image you uploaded. For high-resolution-tier
    models, use max_edge=2576 and max_tokens=4784.
    """
    resized_w, resized_h = resized_size(
        original_width, original_height, max_edge, max_tokens
    )
    return (x / resized_w, y / resized_h)


# A table corner Claude returns at (462, 653.5) on the resized A4 page maps
# back onto the 1075x1520 original like this:
rel_x, rel_y = to_relative_coordinates(462, 653.5, 1075, 1520)
print((rel_x * 1075, rel_y * 1520))  # (537.5, 760.0)
// This helper calls resizedSize from the resize example on this page.
/**
 * Map a pixel coordinate returned by Claude to relative coordinates in [0, 1].
 *
 * Pass the dimensions of the image you uploaded. For high-resolution-tier
 * models, use maxEdge = 2576 and maxTokens = 4784.
 */
function toRelativeCoordinates(
  x: number,
  y: number,
  originalWidth: number,
  originalHeight: number,
  maxEdge = 1568,
  maxTokens = 1568
): [number, number] {
  const [resizedW, resizedH] = resizedSize(
    originalWidth,
    originalHeight,
    maxEdge,
    maxTokens
  );
  return [x / resizedW, y / resizedH];
}

// A table corner Claude returns at (462, 653.5) on the resized A4 page maps
// back onto the 1075x1520 original like this:
const [relX, relY] = toRelativeCoordinates(462, 653.5, 1075, 1520);
console.log([relX * 1075, relY * 1520]); // [ 537.5, 760 ]
// This helper calls ResizedSize from the resize example on this page.
// Map a pixel coordinate returned by Claude to relative coordinates in
// [0, 1]. Pass the dimensions of the image you uploaded, and the same tier
// limits used for ResizedSize.
static (double X, double Y) ToRelativeCoordinates(
    double x, double y, int originalWidth, int originalHeight,
    int maxEdge = 1568, int maxTokens = 1568)
{
    (int resizedW, int resizedH) =
        ResizedSize(originalWidth, originalHeight, maxEdge, maxTokens);
    return (x / resizedW, y / resizedH);
}

// A table corner Claude returns at (462, 653.5) on the resized A4 page maps
// back onto the 1075x1520 original like this:
(double relX, double relY) = ToRelativeCoordinates(462, 653.5, 1075, 1520);
Console.WriteLine((relX * 1075, relY * 1520)); // (537.5, 760)
// This helper calls resizedSize from the resize example on this page.

// toRelativeCoordinates maps a pixel coordinate returned by Claude to
// relative coordinates in [0, 1]. Pass the dimensions of the image you
// uploaded, and the same tier limits used for resizedSize.
func toRelativeCoordinates(
	x, y float64,
	originalWidth, originalHeight, maxEdge, maxTokens int,
) (float64, float64) {
	resizedW, resizedH := resizedSize(originalWidth, originalHeight, maxEdge, maxTokens)
	return x / float64(resizedW), y / float64(resizedH)
}

// To map back to your original image's pixel space, multiply by the original
// dimensions: a table corner returned at (462, 653.5) on the resized A4 page
// is (relX*1075, relY*1520) = (537.5, 760) on the 1075x1520 original.
// This helper calls resizedSize from the resize example on this page.
/** A coordinate scaled into the [0, 1] range on both axes. */
record RelativeCoordinate(double x, double y) {}

/**
 * Map a pixel coordinate returned by Claude to relative coordinates in
 * [0, 1]. Pass the dimensions of the image you uploaded, and the same tier
 * limits used for resizedSize.
 */
static RelativeCoordinate toRelativeCoordinates(
        double x, double y, int originalWidth, int originalHeight, int maxEdge, int maxTokens) {
    Size resized = resizedSize(originalWidth, originalHeight, maxEdge, maxTokens);
    return new RelativeCoordinate(x / resized.width(), y / resized.height());
}

// To map back to your original image's pixel space, multiply by the original
// dimensions: a table corner returned at (462, 653.5) on the resized A4 page
// is (relative.x() * 1075, relative.y() * 1520) = (537.5, 760) on the
// 1075x1520 original.
// This helper calls resizedSize() from the resize example on this page.
/**
 * Map a pixel coordinate returned by Claude to relative coordinates in
 * [0, 1], as [x, y]. Pass the dimensions of the image you uploaded, and the
 * same tier limits used for resizedSize.
 */
function toRelativeCoordinates(
    float $x,
    float $y,
    int $originalWidth,
    int $originalHeight,
    int $maxEdge = 1568,
    int $maxTokens = 1568,
): array {
    [$resizedW, $resizedH] = resizedSize($originalWidth, $originalHeight, $maxEdge, $maxTokens);

    return [$x / $resizedW, $y / $resizedH];
}

// A table corner Claude returns at (462, 653.5) on the resized A4 page maps
// back onto the 1075x1520 original like this:
[$relX, $relY] = toRelativeCoordinates(462, 653.5, 1075, 1520);
echo '(' . $relX * 1075 . ', ' . $relY * 1520 . ")\n"; // (537.5, 760)
# This helper calls resized_size from the resize example on this page.
# Map a pixel coordinate returned by Claude to relative coordinates in
# [0, 1], as [x, y]. Pass the dimensions of the image you uploaded, and the
# same tier limits used for resized_size.
def to_relative_coordinates(
  x, y, original_width, original_height, max_edge = 1568, max_tokens = 1568
)
  resized_w, resized_h = resized_size(original_width, original_height, max_edge, max_tokens)
  [x.fdiv(resized_w), y.fdiv(resized_h)]
end

# A table corner Claude returns at (462, 653.5) on the resized A4 page maps
# back onto the 1075x1520 original like this:
rel_x, rel_y = to_relative_coordinates(462, 653.5, 1075, 1520)
p [rel_x * 1075, rel_y * 1520] # => [537.5, 760.0]

패딩은 아래쪽과 오른쪽 변에만 적용되므로 원점이 이동하지 않고, 축별 선형 재조정으로 충분해요. 재조정 전에 반환된 좌표를 조정된 크기로 클램프해서, 이미지 밖으로 약간 벗어난 점이 원본 밖으로 매핑되지 않게 하세요.

상대 좌표는 행동하는 어떤 표면에든 곱해져요: 원본 이미지, 전체 해상도 스캔, 화면. 화면에서 행동하고 스크린샷 픽셀이 논리 좌표와 다를 때(HiDPI 디스플레이)는 디스플레이 배율 계수로도 나누세요. Computer use 도구의 배율 지침이 그 패턴을 다뤄요.

다음 단계

Agent Skills are modular capabilities that extend Claude's functionality. Each Skill packages instructions, metadata, and optional resources (scripts, templates) that Claude uses automatically when relevant. Give Claude screenshot, mouse, and keyboard control of a desktop environment with the computer use tool. Process PDFs with Claude. Extract text, analyze charts, and understand visual content from your documents. Count the tokens in a message before you send it to Claude. Use token counts to manage rate limits and costs, make model routing decisions, and fit prompts to a target length.

더 알아보기 (Learn more)