How to use setUvRange properly for CardMaker?

I’ve been struggling to understand how Cardmaker generates its UV ranges, but I’m completely baffled! Can somebody explain to me how this math is suppose to work?

I want to create a pixel-accurate .png file loader that automatically corrects for textures that are not powers of 2. I use PNMImage to fit a png file into a padded PNMImage that is powers of 2.
     newImage.copySubImage(origImage, 0, 0, 0, 0)
The old and new img sizes are  oldsize_x, oldsize_y, newsize_x, newsize_y.  Thus the factional size of the old image/new image is 
   fU = oldsize_x/newsize_x 
   fV = oldsize_y/newsize_y

Using CardMaker, I make a new frame of size:

   sx = oldsize_x/ScreenResolutionX()
   sy = oldsize_y/ScreenResolutionY()
   card.setFrame(-sx,  sx, -sy, sy)

So I thought it would be simple to set the UV’s using

    card.setUvRange(Point2(0, fU), Point2(1-fV, 1))

(This is the standard OpenGl reference system right? Tex coordinates is
0,0 at the bottom left of the texture. )

But that doesn’t work. After many hours of screwing around, the
thing that looks right, but I’m not sure if its really working is to set
the UV range as

    card.setUvRange(Point2(fU, 0), Point2(0, fV))
   
    nodepath_temp = NodePath("t").attachNewNode(card.generate())
    nodepath_temp.setTexOffset(TextureStage.getDefault(), 0, 1-fV)
    nodepath_temp.setSx(-1)

So basically, invert the U-range during the Uv setup, invert it back during actual rendering. Samething for the V offset.

Can somebody explain to me what is going on before I get so frustrated that I beat my dog?

Working code as follows:

import direct.directbase.DirectStart
from pandac.PandaModules import PNMImage, PNMImageHeader, Texture, Point2, TextureStage, CardMaker, NodePath
from math import log, ceil
from direct.gui.DirectGui import *

def GetScreenResX():
	return 1.*base.win.getXSize()
	
def GetScreenResY():
	return 1.*base.win.getYSize()

def ScaleToNextPower2(aInt):
	return 2**int(ceil(log(aInt)/log(2.)))

origImage = PNMImage()
assert origImage.read("/c/pandastuff/test.jpg")

oldsize_x = origImage.getXSize()
oldsize_y = origImage.getYSize()

newsize_x = ScaleToNextPower2(oldsize_x)
newsize_y = ScaleToNextPower2(oldsize_y)

newImage = PNMImage(newsize_x, newsize_y)
newImage.copySubImage(origImage, 0, 0, 0, 0)

size =1.0
card = CardMaker('testname')
sx = 1.*oldsize_x/GetScreenResX()
sy = 1.*oldsize_y/GetScreenResY()

card.setFrame(-sx,  sx, -sy, sy)

fU = 1.*oldsize_x/newsize_x
fV = 1.*oldsize_y/newsize_y

card.setHasUvs(True)
card.setUvRange(Point2(fU, 0), Point2(0, fV))

node = NodePath("Sprite2d" ) 
nptemp = node.attachNewNode(card.generate())

tex = Texture()
tex.load(newImage)
nptemp.setTexture(tex)
nptemp.setTexOffset(TextureStage.getDefault(), 0, 1-fV)

tf = DirectFrame(geom = nptemp)
tf.setSx(-1)

run()

Note that you can pass a texture to setUvRange as well:
file:///home/rdb/panda3d/built_doc/python/html/classpanda3d_1_1core_1_1CardMaker.html#a9e0cd524de780ec39b61aeab4685b4ea