# Get texture image dpi

I'm trying to get the dpi of the material textures via scripting, but I could not find any information on this.

You can assume that my UV-mapping is un-stretched, each polygon will be covered by the same amount of pixels in relation to the polygon area.

Do I need to use external library?

• I don't think there is such a thing as dpi in this context: dpi is always a ratio between size in phsyical dimensions and resolution of the texture. The physical size can't be known from the texture itself. – Mörkö Oct 21 '15 at 9:29
• The dpi is the way of geting real size from resolution. So with the resolution and dpi, we can get the real size of the texture. BTW, no dpi in context.. let's have a look on Pillow... – Ange_blond Oct 21 '15 at 9:31
• But (afaik.) as far as there is no dpi-info and no info about the physical size (which a texture file doesn't carry), you can't get it. – Mörkö Oct 21 '15 at 9:38
• (Apart from maybe metadata from pictures taken with a camera. Is that what you are speaking about?) – Mörkö Oct 21 '15 at 9:39
• Sorry if I don't fully understand what you mean. – Mörkö Oct 21 '15 at 9:43

DPI of a texture/image will depend on how many pixels are mapped onto a polygon and the real-world area of that polygon. Now your question is more exact (homogeneous uv - no stretching), some parts of this answer aren't directed at you but hope to describe the notion of DPI and that it won't always be a single figure per model.

The following only works if your image-texture is square. width px is the same as height px

### factors that decide DPI

You can use the same texture on large polygons and on small polygons, you can also scale the uv coordinates so a small polygon could contain many pixels (effectively high 'dpi'). The DPI therefor is not a property of the texture, but of each polygon and uv mapping.

If you have no such stretching going on and each uvmapped face is covered by the same amount of pixels relative to its real-world area, then you can calculate the DPI once.

### Variable DPI vs Homogeneous DPI

The effective DPI of a texture is often variable, but not always. Indeed for certain kinds of texturing it is desirable to have no stretching at all. In either scenario the formula is the same, but when you speak of homogeneous uv-mapping you only need to calculate it once.

### Finding UV coordinates

Code to help with this can be found in TextEditor -> Templates -> Python -> Operator Mesh UV. Below i've stripped out the template to make sure it just prints the 2d coordinates of each .uv (a 2D .uv corresponds to a 3D vertex.co). This would give you the 2d coordinate in the UVmap of each vertex per polygon:

import bpy
import bmesh

obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()
bm.faces.layers.tex.verify()

for f in bm.faces:
for l in f.loops:
luv = l[uv_layer]
print(luv.uv)


Here's the formula used to calculate the area given a list of coordinates, here's the same formula stated in Python. From the Area you can extract a hypothetical side length.

import math

import bpy
import bmesh
from mathutils import Vector

def texture_dpi(polygon_area, uv_area, image_dim):
"""
polygon_area:   in (meters or BU)
uv_area:        in ratio (0..1)
image_dim:      either width or height of image, this assumes
square images anyway, else none of this makes sense
"""

l1 = math.sqrt(polygon_area)
l2 = math.sqrt(uv_area)

# assume the units are BU or meter.
inches = l1 * 39.3701
pixels = int(l2 * image_dim)
return int(pixels / inches)

def calc_area_from_2d_vectorlist(v):
# http://www.mathopenref.com/coordpolygonarea.html
sum = 0
n = len(v)
for i in range(n - 1):
sum += ((v[i].x * v[i + 1].y) - (v[i].y * v[i + 1].x))
sum += ((v[n - 1].x * v[0].y) - (v[n - 1].y * v[0].x))
return abs(sum / 2)

def get_bm_from_edit_object(image_name):
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()
bm.faces.layers.tex.verify()

totals = []
for f in bm.faces:
vl = [l[uv_layer].uv for l in f.loops]
fa = calc_area_from_2d_vectorlist(vl)  # 2d area of uv loop
totals.append([f.calc_area(), fa])     # 2d area of face (local size)
break  # if homogeneous  , else comment it out.

image_dim = bpy.data.images[image_name].size[0]
for polygon_area, uv_area in totals:
dpi = texture_dpi(polygon_area, uv_area, image_dim)
print(dpi)

get_bm_from_edit_object('some_texture.png')

• Considering the UV map using a 0-1 range, considering the object sized in real-word units and considering the texture/image with a dpi, I can change the UV scale to make all this match the same real-world units. – Ange_blond Oct 21 '15 at 13:34
• Great! Upvoted 7 hours ago, unfortunately I can't upvote again :D – p2or Oct 21 '15 at 17:42
• Nice answer, thanks a lot. This is out of the topic because I'm not trying to change UVs coordinate but just to scale the UV map. I consider the UV has been scaled the same for each face, and using the total length of the UV map from 0 to 1. Then, knowing the DPI of the texture (converted into real world size) and knowing (asking the user) the total lenght of the UV map (in real world size too) I can make them match via UV scale. Thanks again for the effort :) – Ange_blond Oct 22 '15 at 7:22
• Yes, my question is not enought precise. I'm begginer here, sorry. – Ange_blond Oct 22 '15 at 7:39
• That's OK. @Ange_blond If I can give advice it is to take more time to formulate precise questions, give us your list of knowns. -- and edit your question to include information asked for by our comments. (less information should be in comments...) – zeffii Oct 22 '15 at 9:19