AttributeError: ‘PngImageFile’ Object Has No Attribute ‘Shape’ | Fast, Reliable Fixes

The error means you’re calling .shape on a Pillow image; convert to a NumPy array or use Pillow’s size/width/height instead.

Pillow’s Image object doesn’t expose .shape. That attribute belongs to NumPy arrays and to images loaded by OpenCV. With PNG files you’ll often hit this when mixing Pillow and NumPy or switching between OpenCV and Pillow APIs in the same script. The fix is simple: either convert the image to a NumPy array before asking for .shape, or use Pillow’s size, width, and height properties.

Why This AttributeError Pops Up

Quick check: If you opened the file with PIL.Image.open(...), you have a Pillow Image, not a NumPy array. Pillow uses size and the convenience fields width/height, while .shape lives on NumPy arrays. The Pillow docs list these fields on the Image class and do not mention .shape.

  • Pillow image: img.size(width, height); also img.width, img.height.
  • NumPy/OpenCV image: arr.shape(rows, cols, channels). OpenCV returns a NumPy array from cv2.imread.

One more gotcha: Pillow reports size as (W, H)shape as (H, W, C)

AttributeError: 'PngImageFile' Object Has No Attribute 'Shape' — Safe Patterns That Work

Pick the pattern that matches your stack. Each one avoids the trap by using the right attribute on the right object.

Use Pillow Only (No NumPy Needed)

from PIL import Image

img = Image.open("image.png")
w, h = img.size        # or: w, h = img.width, img.height
print(w, h)

Why it works: size, width, and height are the supported ways to read dimensions on a Pillow Image.

Convert Pillow Image To NumPy Before Using .shape

from PIL import Image
import numpy as np

img = Image.open("image.png")
arr = np.array(img)    # or: np.asarray(img)
print(arr.shape)       # (H, W, C) for RGB/RGBA

Why it works: np.array(img) turns the Pillow image into a NumPy array, which exposes .shape.

Load With OpenCV When You Want Arrays From The Start

import cv2

arr = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)  # arr is a NumPy array
print(arr.shape)   # (H, W, C)

Why it works: cv2.imread returns a NumPy array, so .shape is valid immediately.

PNG Quirks You Should Handle Up Front

PNG files often carry transparency. That means you might get RGBA rather than RGB. If you’re moving data between libraries, match channel layout first.

  • Remove alpha in Pillow: img = img.convert("RGB") before conversion to an array.
  • Beware of background after drop: removing alpha will flatten to a background color; plan your pipeline accordingly.
from PIL import Image
import numpy as np

img = Image.open("logo.png").convert("RGB")  # drop alpha
arr = np.array(img)                          # safe .shape next
print(arr.shape)

Common Mix-Ups And Exact Fixes

Use these quick swaps to kill the error without rewiring your project.

  1. Reading size on a Pillow image? Replace img.shape with img.size or (img.width, img.height).
  2. Running NumPy code after Image.open? Insert arr = np.array(img) before any .shape calls.
  3. Working in OpenCV land? Load with cv2.imread so you start with a NumPy array.
  4. Seeing swapped width/height? Remember: Pillow uses (W, H); arrays use (H, W, C). Adjust the order when converting.
  5. Alpha channel tripping code? Standardize to RGB with .convert("RGB") before np.array if your pipeline expects 3 channels.

Reference Table: Symptoms To Fix In One Glance

Symptom Likely Cause Direct Fix
AttributeError on .shape after Image.open Pillow Image lacks .shape w,h = img.size or arr = np.array(img)
shape shows three values; code expects two Color image array includes channels h,w = arr.shape[:2]
Width/height seem flipped Confusing (W,H) vs (H,W) Switch order when moving between APIs
Downstream step fails on RGBA Alpha channel present in PNG img = img.convert("RGB") or handle 4 channels
Want NumPy ops from the start Loaded with Pillow by habit Load with cv2.imread; get array directly

Dimension Reads That Never Break

These patterns keep width/height logic tidy across stacks and prevent the attributeerror: 'pngimagefile' object has no attribute 'shape' from resurfacing later.

Pillow-Only Dimension Reads

from PIL import Image

img = Image.open("frame.png")
w, h = img.size          # or: img.width, img.height
print(f"{w=} {h=}")

Unified Helper When Mixing Pillow And NumPy

from typing import Tuple
from PIL import Image
import numpy as np

def get_wh(x) -> Tuple[int, int]:
    # Pillow Image
    if isinstance(x, Image.Image):
        return x.width, x.height
    # NumPy-like (OpenCV, etc.)
    if hasattr(x, "shape"):
        h, w = x.shape[:2]
        return w, h
    raise TypeError("Unsupported image type")

# Usage
img = Image.open("scene.png")
print(get_wh(img))           # Pillow branch
arr = np.array(img)
print(get_wh(arr))           # NumPy branch

Why it works: The helper inspects the object and extracts dimensions with the correct field for each library. OpenCV tutorials reinforce that image data is a NumPy array with .shape.

Alpha, Modes, And Channel Counts

PNG transparency leads to mode RGBA. Some models, augmentation code, or encoders expect RGB. Standardize early to keep pipelines stable.

  • Drop alpha in Pillow: img = img.convert("RGB").
  • Working with arrays: after np.array(img), check arr.shape and slice channels or convert with Pillow first.
from PIL import Image
import numpy as np

img = Image.open("badge.png")
if img.mode == "RGBA":
    img = img.convert("RGB")
arr = np.array(img)  # safe: now shape[-1] == 3

End-To-End Examples You Can Paste In

Case A — Keep Pillow, No NumPy

from PIL import Image

img = Image.open("tile.png")
w, h = img.size
print("W×H:", w, h)
# downstream Pillow ops here

Case B — Convert To Array, Stay In NumPy/OpenCV Style

from PIL import Image
import numpy as np

img = Image.open("tile.png").convert("RGB")
arr = np.array(img)
h, w = arr.shape[:2]
print("H×W×C:", arr.shape)
# downstream NumPy ops here

Case C — Start In OpenCV

import cv2

arr = cv2.imread("tile.png", cv2.IMREAD_COLOR)  # BGR array
h, w = arr.shape[:2]
print("H×W×C:", arr.shape)

OpenCV’s tutorials and guides make clear that arrays carry the pixel data and expose .shape.

Pitfall Roundup So You Don’t See The Error Again

  • Pick one dimension API per object type: Pillow → size; NumPy/OpenCV → shape.
  • Normalize channel layout early: convert RGBA to RGB if downstream code expects three channels.
  • Keep width/height order straight: Pillow reports (W, H), arrays store (H, W).

FAQ-Free Cheatsheet For Dimension And Loading

  • Read size with Pillow only: w, h = Image.open(path).size.
  • Switch to array for math: arr = np.array(Image.open(path)), then arr.shape.
  • OpenCV path: arr = cv2.imread(path), then arr.shape.
  • Handle alpha: img.convert("RGB") when needed.

Use these patterns and the attributeerror: 'pngimagefile' object has no attribute 'shape' disappears for good while your dimension math stays correct across Pillow, NumPy, and OpenCV.