Procedurally generated objects of paintings
I'm not sure if I understand the requirement correctly. But here is one way... The following code will create an extruded planes per image from the given directory. One of the faces of the plane will have the image texture (you can randomize the array of image files using random.shuffle).

This is rather quick and dirty :), so maybe buggy and quite slow.  To improve the performance, (and if the functionality broadly corresponds to your requirement) you'd need to replace the ops calls with the low level equivalents. Also, the space between the planes may be required to be properly worked out. 

import bpy
import os
import glob

def getOverride():
    for area in bpy.context.window.screen.areas:
        if area.type == 'VIEW_3D':
            v3d = area.spaces[0]
            rv3d = v3d.region_3d
            for region in area.regions:
                if region.type == 'WINDOW':
                    override = {
                        'scene'  : bpy.context.scene,
                        'region' : region,
                        'area'   : area,
                        'space'  : v3d
                    }
                    #~ return region, rv3d, v3d, area
                    return override
    return None


types = ["*.png", "*.jpg"]
srcDir = '/tmp/'
imageToCanvasRatio = .8
canvasThickness = .08
canvasColor = [.120,.109,0.02,1]
canvasWidth = 1
canvasOffset = .2
image_files = [os.path.basename(x) for t in types for x in glob.glob(srcDir + t)]
maxImgs = 15
maxHeight = 0
imgsPerRow = 5
cumulHeight = 0

bpy.context.scene.render.engine = 'CYCLES'

defaultMat = bpy.data.materials.new('Background')
defaultMat.use_nodes = True
node_tree = defaultMat.node_tree        
node_tree.nodes.get("Diffuse BSDF").inputs["Color"].default_value = canvasColor
for i in range(0, len(image_files), imgsPerRow):
    imgs = [bpy.data.images.load(srcDir + image_files[i + k]) for k in range(0, imgsPerRow) if (i + k) &lt; len(image_files)]
    maxHeight = max(canvasWidth * img.size[1] / img.size[0] for img in imgs)
    for j, img in enumerate(imgs):
        print(i, j, maxImgs)
        if(i + j &gt;= maxImgs):
            break

        canvasHeight = canvasWidth * img.size[1] / img.size[0]

        bpy.ops.mesh.primitive_plane_add(location=(2 * j * (canvasWidth + canvasOffset), cumulHeight + maxHeight/2, 0))

        obj = bpy.context.object
        obj.dimensions[0] = canvasWidth
        obj.dimensions[1] = canvasHeight

        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"mirror":False}, TRANSFORM_OT_translate={"value":(0, 0, canvasThickness), "constraint_axis":(False, False, True)})

        bpy.ops.mesh.loopcut_slide(getOverride(), MESH_OT_loopcut={"number_cuts":1, "edge_index":5}, TRANSFORM_OT_edge_slide={"value":imageToCanvasRatio})
        bpy.ops.mesh.loopcut_slide(getOverride(), MESH_OT_loopcut={"number_cuts":1, "edge_index":5}, TRANSFORM_OT_edge_slide={"value":-imageToCanvasRatio})
        bpy.ops.mesh.loopcut_slide(getOverride(), MESH_OT_loopcut={"number_cuts":1, "edge_index":4}, TRANSFORM_OT_edge_slide={"value":-imageToCanvasRatio})
        bpy.ops.mesh.loopcut_slide(getOverride(), MESH_OT_loopcut={"number_cuts":1, "edge_index":6}, TRANSFORM_OT_edge_slide={"value":-imageToCanvasRatio})
        bpy.ops.object.mode_set(mode='OBJECT')

        obj.data.materials.append(defaultMat)

        for faceIdx in range(0, len(obj.data.polygons)) :
            if(faceIdx != 24):
                obj.data.polygons[faceIdx].material_index = 0

        mat = bpy.data.materials.new('mat')
        mat.use_nodes = True
        node_tree = mat.node_tree
        node_texture = node_tree.nodes.new("ShaderNodeTexImage")
        node_texture.image = img
        links = mat.node_tree.links
        links.new(node_texture.outputs['Color'], node_tree.nodes.get("Diffuse BSDF").inputs['Color'])
        obj.data.materials.append(mat)
        obj.data.polygons[24].material_index=1
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_all(action='SELECT')
        obj.data.uv_textures.new()
        bpy.ops.object.mode_set(mode='OBJECT')
    if(i + j &gt;= maxImgs):
        break
    cumulHeight += (maxHeight)+ canvasOffset