from typing import List, Tuple
import Instruction_Block as ib
import Parser as p
import Parse_File as pf
import DFG_Node as dfgn
import Block_DFG as b_dfg
import Special_Nodes as sdfgn
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import lines
from networkx.drawing.nx_agraph import graphviz_layout

"""
The naming may be a bit weird, because I decided halfway through that 'node' is a better
descriptor than 'variable', so they are used somewhat interchangeably
"""
class Data_Flow_Graph:
    """
    The data flow graph for the file
    """
    def __init__(self, fileName, do_init=True, do_conv = True):
        print('*****dfg creation*****')
        self.par_file : pf.Parsed_File = pf.Parsed_File(fileName)
        self.variables : List[dfgn.DFG_Node] = []        #holds all variables (includes global)
        self.global_variables : List[dfgn.DFG_Node] = [] #holds only global variables
        self.branch_variables : List[dfgn.DFG_Node] = [] #holds nodes created with branch instructions
        self.phi_variables : List[dfgn.DFG_Node] = []    #holds all nodes created with phi
        self.block_dfgs : List[b_dfg.Block_DFG] = []         #list of dfgs for each block
        self.graph = nx.DiGraph()
        self.graphNodes = []

        if do_init:
            self.Init_DFG()
        if do_conv:
            self.Convert_DFG()

    def Init_DFG(self):
        """
        creates dfg from parsed file blocks
        """
        self.Get_All_Variables()
        self.Create_Branch_Nodes()
        self.Get_Uses()
        self.Get_Dependencies()
        self.Create_Other_Nodes()
        self.Get_Immediates()
        self.Get_All_Block_DFGs()
        self.Fill_All_Node_Lists()
        self.Get_Total_Iters()
        self.Get_All_Strides()
        self.Fill_All_Loop_Depths()
        self.Fill_All_Block_Nums()

    def Convert_DFG(self):
        """
        Converts dfg to one with vle and macc
        instructions
        """
        self.Identify_Maccs()
        self.Identify_Load_Loops()
        self.Convert_All_Br_To_Bne()
        self.Cleanup_All_Old_Nodes(True)

    def Get_All_Variables(self):
        """
        Finds all the variables in the file
        """
        #first get the global variables
        self.Get_Global_Variables()
        for b_idx in range(len(self.par_file.blocks)):
            block = self.par_file.Get_Order_Idx(b_idx)
            ord_idx = block.block_order
            for instr in block.instructions:
                if(instr.args == None):
                    continue
                if(instr.args.result != "DEFAULT" \
                    or instr.args.instr == "ret"):
                    #if the variable is not in the list
                    if(self.Get_Var_Idx(instr.args.result) == -1):
                        if (instr.args.instr == "phi"):
                            node = sdfgn.Phi_Node(instr)
                            self.phi_variables.append(node)
                        else:
                            node = dfgn.DFG_Node(instr)
                        if(instr.block_offset == -1):
                            print("Error, block offset == -1")
                        node.assignment = (ord_idx, instr.block_offset)

                        self.variables.append(node)

    def Get_Global_Variables(self):
        """
        Easier to just handle the global variables seperately
        """
        for instr in self.par_file.Instructions:
            if(instr.args == None):
                continue
            if(instr.args.result[0] == '@'):
                #if this isnt in the variable list yet
                if(self.Get_Var_Idx(instr.args.result) == -1):
                    node = dfgn.DFG_Node(instr)
                    node.assignment = (-1, instr.instr_num) #-1 to indicate that it is a global variable
                    node.is_global = True
                    self.variables.append(node)
                    self.global_variables.append(node)

    def Create_Branch_Nodes(self):
        """
        This could have been added to Get_All_Variables, but I
        Think breaking the function up makes more sense, and easier to
        debug
        """
        for b_idx in range(len(self.par_file.blocks)):
            block = self.par_file.Get_Order_Idx(b_idx)
            ord_idx = block.block_order
            for instr in block.instructions:
                if(instr.args == None):
                    continue
                if(instr.args.instr != "br"):
                    continue
                node = dfgn.DFG_Node(instr)
                node.name = "%" + block.name
                node.assignment = ((ord_idx, instr.block_offset))
                #loop to get all the phi blocks that this branch statement targets
                for var in self.phi_variables:
                    if node.name in var.instruction.args.pred_names:
                        node.uses.append(var.assignment)
                self.branch_variables.append(node)
                self.variables.append(node)

    def Create_Other_Nodes(self):
        """
        Creates nodes used in store, some calls.  These need to be handled specially, since they are the only instructions
        That use variables without writing to anything.  They still need to be tracked as dependencies for the instructions though
        so we create 'fake' nodes that have no uses, but do have dependencies
        """
        num_new = 0
        for var in self.variables:
            for use in var.uses:
                block = self.par_file.Get_Order_Idx(use[0])
                instr = block.instructions[use[1]]
                use_node = self.Get_Node_Block_Offset(use)
                if(use_node == None or len(use_node.uses) == 0):
                    if(instr.args.instr not in ['call', 'store']):
                        print("Error, expected call or store, got: " + instr.args.instr + ", " + str(instr.line_num))
                        continue
                    if(use_node == None):
                        use_node = dfgn.DFG_Node(instr)
                        #num_new ensures that we get unique names
                        use_node.name = "%" + instr.args.instr + "_" + str(num_new) + "_s"
                        num_new += 1
                        use_node.assignment = use
                        self.variables.append(use_node)
                    use_node.dependencies.append(var.assignment)

    def Get_Var_Idx(self, name):
        """
        Gets index of variable by name
        returns -1 if a variable with that name is not in the list
        """
        for idx in range(len(self.variables)):
            if(self.variables[idx].name == name):
                return idx
        return -1

    def Get_Node_By_Name(self, name):
        """
        Gets a node by its name
        """
        for node in self.variables:
            if node.name == name:
                return node
        return None

    def Get_Node_Block_Offset(self, pos:Tuple[int, int]):
        """
        returns the Node that was assigned at (block, block offset)
        """
        for node in self.variables:
            if node.assignment == pos:
                return node
        return None

    def Get_Instruction_Block_Offset(self, pos:Tuple[int, int]):
        """
        returns the instruction at ((ordered) block, offset)
        """
        #if it is assigned outside a block (ie global variable)
        if(pos[0] == -1):
            instr = self.par_file.Instructions[pos[1]]
            if(instr.args.result[0] != '@'):
                print("Error: block -1, but not global variable")
            return instr

        block = self.par_file.Get_Order_Idx(pos[0])
        return block.instructions[pos[1]]

    #this assumes all uses of a variable are within blocks
    #ie, no global assignments use other variables
    def Get_Uses(self):
        """
        Get all the uses of the variables (discluding the assignment)
        If I had planned a bit better, this could maybe
        have been done in the same function as Get_All_Variables,
        but this works fine too and is simpler
        """
        for idx in range(len(self.par_file.blocks)):
            block = self.par_file.Get_Order_Idx(idx)
            ord_idx = block.block_order
            for instr in block.instructions:
                if(instr.args == None):
                    continue
                for var in instr.args.vars_used:
                    var_idx = self.Get_Var_Idx(var)
                    if(var_idx == -1):
                        if(var[0] in ["%", "@"]):
                            print("Error, variable: " + str(var) + ", not in list of variables")
                        continue
                    var_loc = (ord_idx, instr.block_offset)
                    if(self.variables[var_idx].assignment != var_loc):
                        self.variables[var_idx].uses.append(var_loc)

    def Get_Dependencies(self):
        """
        Similar to Get_Uses, but goes the other direction in the graph
        Could have also been done in dependencies, but I think splitting it up makes reading/debugging
        easier
        """
        for var in self.variables:
            for use in var.uses:
                use_var = self.Get_Node_Block_Offset(use)
                if(use_var == None):
                    if(self.Get_Instruction_Block_Offset(use).args.instr not in ["call", "br", "store"]):
                        print("Error, use_var shouldn't be None, " + str(var.name) + ", " + str(use))
                    continue
                use_var.dependencies.append(var.assignment)

    def Get_Immediates(self):
        """
        Gets immidiate values used in assignment of each variable
        This also error checks uses and dependencies
        """
        for var in self.variables:
            for used in var.instruction.args.vars_used:
                if(used[0] in ['%', '@']):
                    used_node_idx = self.Get_Var_Idx(used)
                    if(used_node_idx == -1):
                        print("Error, " + used + ", not in variables")
                        continue
                    used_node = self.variables[used_node_idx]
                    if((used_node.assignment not in var.dependencies) and (used != var.name)):
                        print("Error, " + used + ", should be in dependencies")
                elif(used.isnumeric() == False):
                    print("Error, " + used + ", should be a number \
                        (may cause error if its a float, just fix this error check if thats the case)")
                    print("\tVar: " + var.name + ", line: " + str(var.instruction.line_num))
                else:
                    var.immediates.append(used)

    def Get_All_Block_DFGs(self):
        """
        Gets all the basic block DFGs
        """
        for b_idx in range(len(self.par_file.blocks)):
            block = self.par_file.Get_Order_Idx(b_idx)
            block_dfg = b_dfg.Block_DFG(block)
            block_dfg.Get_Inner_Vars(self)
            block_dfg.Get_Outer_Vars(self)
            block_dfg.Get_Vector_Len()
            self.block_dfgs.append(block_dfg)

        for block in self.block_dfgs:
            block.Get_Self_Iters(self)

    def Get_Use_Path(self, start:dfgn.DFG_Node, target:dfgn.DFG_Node, node_list:List[dfgn.DFG_Node], do_dep=False):
        """
        Wrapper to call Do_Use_Path_DFG, just adds the visited array

        Populates a list of the nodes on (a) path from start to target.
        There could theoretically be more paths ig, but this is mostly meant
        for loop counting.

        do_dep is true if you are searching using the dependency list
        (backwards search)
        """
        visited = []
        self.Do_Use_Path_DFG(start, target, node_list, visited, do_dep)

    def Do_Use_Path_DFG(self, start:dfgn.DFG_Node, target:dfgn.DFG_Node, node_list:List[dfgn.DFG_Node], visited, do_dep):
        #called by Get_Use_Path
        if(start in visited):
            return False
        visited.append(start)
        node_list.append(start)
        if(start == target):
            return True
        if(do_dep == False):
            nodes = start.uses
            exclude = start.psuedo_uses
        else:
            nodes = start.dependencies
            exclude = start.psuedo_dependencies
        for use in nodes:
            if(use in exclude):
                continue
            node = self.Get_Node_Block_Offset(use)
            ret_val = self.Do_Use_Path_DFG(node, target, node_list, visited, do_dep)
            if(ret_val == True):
                return True
        node_list.pop()
        return False

    def Get_Use_Path_Graph(self, start:dfgn.DFG_Node, target:dfgn.DFG_Node, nodeList:List[dfgn.DFG_Node], visited = None, do_dep=False, findPhi=False, depth=5):
        """
        Same functionality as the above Get_Use_Path, but this uses the node pointers
        to traverse the graph, which is better than using the block references
        findPhi is true if we don't know for sure the target were searching for, but just want the first phi that assigns to this node.  If it is true, set target to false
        depth counts down to 0 to prevent the search from getting too long, initialize at a larger number to search deeper
        """
        if (depth == 0):
            return False

        if visited == None:
            visited = []

        if(start in visited):
            return False

        visited.append(start)
        nodeList.append(start)

        if(start == target):
            return True
        if((findPhi == True) and (start.is_phi == True)):
            return True

        if(do_dep == False):
            nodes = start.use_nodes
        else:
            nodes = start.dep_nodes
        exclude = start.psuedo_nodes

        for node in nodes:
            ret_val = self.Get_Use_Path_Graph(node, target, nodeList, visited, do_dep, findPhi, depth=depth-1)
            if(ret_val == True):
                return True
        nodeList.pop()
        return False

    def Get_Total_Iters(self):
        """
        Gets the total number of iterations that a for loop will do. Must have had
        Get_Self_Iters() done on every block in the cfg (this gets done normall on __init__ tho)
        """
        prev_iters = 1
        for block in self.block_dfgs:
            if block.self_iters == -1:
                block.self_iters = 1

            #if we are a block that isn't a loop exit, then multiply the previous blocks iterations
            #by the number of iterations we do ourself.  If we are a self loop, then we also need to
            #do the multiplication, even though we are technically also an exit block
            if block.block.is_loop_exit == False:
                block.num_iters = block.self_iters * prev_iters
                prev_iters = block.num_iters
            elif (block.block.is_loop_exit == True and block.block.is_loop_entry == True):
                block.num_iters = block.self_iters * prev_iters
                #dont update prev iters in this case
            else:
                entry_idx = block.block.entry_idx
                entry_order_idx = self.par_file.blocks[entry_idx].block_order
                entry_block = self.block_dfgs[entry_order_idx]
                block.num_iters = entry_block.num_iters
                prev_iters = block.num_iters

    def Identify_Maccs(self):
        for block in self.block_dfgs:
            block.Identify_Macc(self)

    def Fill_All_Loop_Depths(self):
        for block in self.block_dfgs:
            block.Fill_Loop_Depths()

    def Get_Pointer_Node(self, data_node:dfgn.DFG_Node, max_search_depth=5):
        """
        Gets the node where the pointer to this element was created.
        Assumes a data flow of
            getElementPtr (or alloca) -> (optionally) bitcast -> load
        """
        ret_node:dfgn.DFG_Node = None
        for node in data_node.dep_nodes:
            if(ret_node != None):
                break
            if(node.instruction.args.instr in ["getelementptr", "alloca", "zeroinitializer"]):
                ret_node = node
            elif(len(node.dependencies) > 1):
                #if any node we find on the path has more than one dependency, then
                #we have searched too far
                print("searched too far (definitely shouldn't happen in gcn")
                return None
            else:
                ret_node = self.Get_Pointer_Node(node, max_search_depth-1)

        return ret_node

    def Get_Store_Node(self, data_node:dfgn.DFG_Node, max_search_depth=5):
        """
        Finds the node where the address that we are storing the data in gets created.
        As in we assume data_node gets stored (could have some bitcasts), then from the
        store instruction we find the getelementptr where we create the
        """
        ret_node:dfgn.DFG_Node = None
        store_node:dfgn.DFG_Node = None
        for node in data_node.use_nodes:
            if(node.instruction.args.instr == "store"):
                if(store_node == None):
                    store_node = node
                else:
                    print("Error already have a store node")
        if store_node == None:
            print("Didnt find store node.  May be bc a bitcast or something")

        store_var_name = store_node.instruction.args.pointer
        store_pointer_node = self.Get_Node_By_Name(store_var_name)
        ret_node = self.Get_Pointer_Node(store_pointer_node, max_search_depth)

        return (ret_node, store_node)

    def Fill_All_Node_Lists(self):
        for var in self.variables:
            var.Fill_Pointer_Lists(self)

    def Identify_Load_Loops(self):
        for block in self.block_dfgs:
            block.Identify_Load_Loop(self)
        for block in self.block_dfgs:
            block.CleanupOldNodes(self)
        return

    def Get_All_Strides(self):
        for block in self.block_dfgs:
            block.Get_Stride(self)

    def Fill_All_Block_Nums(self):
        for block in self.block_dfgs:
            block.Fill_Block_Nums()

    def ReLinkNodes(self, source:dfgn.DFG_Node, dest:dfgn.DFG_Node, newDest:dfgn.DFG_Node, doBackWardSearch=False):

        """
        Changes the link from source->firstOnPath to source->newDest

        Used for converting several llvm instructions to 1 compiled
        Instruction.  As in conversion of memcpy to vle32.v

        ***********************************************************
        ****    AFTER DOING THIS, node.uses IS NOT VALID, ONLY ****
        ****    THE node.use_nodes IS A FULLY VALID UPDATED DFG ***
        ****    ANY FUNCTIONS THAT USE THIS AFTER THIS FUNCTION ***
        ****    IS CALLED MAY BE INVALID                       ****
        ***********************************************************
        """

        if source == None:
            return
        source.Remove_Duplicates()
        nodes:List[dfgn.DFG_Node] = []
        self.Get_Use_Path(source, dest, nodes, doBackWardSearch)

        for idx in reversed(range(len(nodes)-1)):
            node = nodes[idx]
            node.Remove_Duplicates()
            nodeUses = node.use_nodes.copy()

            for ps in node.psuedo_nodes:
                if ps in nodeUses:
                    nodeUses.remove(ps)

            # So if this node has already been unlinked, just
            # break.  This can happen bc the search algorithm
            # doesn't use the correct links... should change
            # that...
            if node not in nodes[idx + 1].dep_nodes:
                break

            nodes[idx+1].dep_nodes.remove(node)
            node.use_nodes.remove(nodes[idx + 1])
            for ps in node.psuedo_nodes:
                ps.psuedo_nodes.remove(node)
                node.psuedo_nodes.remove(ps)
                if node in ps.dep_nodes:
                    ps.dep_nodes.remove(node)
                    node.use_nodes.remove(ps)
                else:
                    ps.use_nodes.remove(node)
                    node.dep_nodes.remove(ps)

            if len(nodeUses) > 1:
                break

        source.use_nodes.append(newDest)
        newDest.dep_nodes.append(source)

        return

    def Cleanup_All_Old_Nodes(self, removePhiBranch=False):
        """
        potentially slow, as its worst case n^3 in the number
        of nodes, but likely will finish much quicker, and don't
        expect large dfgs
        """
        removedNode = True
        while(removedNode):
            removedNode = False
            for block in self.block_dfgs:
                thisRemove = block.CleanupOldNodes(self, removePhiBranch)
                removedNode = (thisRemove or removedNode)

    def Make_Graph(self, show_imm=True):
        """
        Just makes a graph of the entire thing
        """
        self.graphNodes = []
        for block in self.block_dfgs:
            nodeList = block.inner_vars.copy()
            nodeList.extend(block.createdNodes.copy())
            nodeList.extend(block.outer_vars.copy())
            for node in nodeList:
                if node not in self.graphNodes:
                    self.graphNodes.append(node)
        self.graph = nx.DiGraph()
        imm_num = 0
        for node in self.graphNodes:
            for use in node.use_nodes:
                if(node in self.branch_variables):
                    suffix_1 = "_b"
                else:
                    suffix_1 = "_v"
                if(use in self.branch_variables):
                    suffix_2 = "_b"
                else:
                    suffix_2 = "_v"
                self.graph.add_edge(node.name[1:] + suffix_1 ,use.name[1:] + suffix_2)
            if(show_imm):
                for imm in node.immediates:
                    self.graph.add_edge(str(imm) + "_i" + str(imm_num),node.name[1:] + "_v")
                    imm_num += 1

    def Show_Graph(self):
        color_array = []
        graphNodes = []
        for block in self.block_dfgs:
            for node in block.inner_vars:
                if node not in graphNodes:
                    graphNodes.append(node)
        for node in self.graph.nodes:
            if("_s" in node):
                color_array.append((0,1,1))
            elif(("_b" in node)):
                color_array.append((.75, .25, .75))
            elif("$" + node[:-2] in [var.name for var in graphNodes]):
                color_array.append((.25, 1, .5))
            elif(("%" + node[:-2]) in [var.name for var in graphNodes]):
                color_array.append((0,1,0))
            elif("@" + node[:-2] in [var.name for var in graphNodes]):
                color_array.append((1,.25,1))
            elif("_i" in node):
                color_array.append((1,0,0))
            else:
                color_array.append((1, 1, 0))
        plt.title("DFG")

        no_uses = lines.Line2D([], [], color=(0,1,1), marker='o', markersize=10, label='no use (call, br, store)')
        branch = lines.Line2D([],[], color = (.75,.25,.75), marker = 'o', markersize=10, label = "branch node")
        def_in = lines.Line2D([], [], color=(0,1,0), marker='o', markersize=10, label='defined inside')
        def_out = lines.Line2D([], [], color=(0,0,1), marker='o', markersize=10, label='defined outside')
        def_glob = lines.Line2D([], [], color=(1,.25,1), marker='o', markersize=10, label='defined globally')
        imm = lines.Line2D([], [], color=(1,0,0), marker='o', markersize=10, label='immediate')
        use_out = lines.Line2D([], [], color=(1,1,0), marker='o', markersize=10, label='used outside')

        plt.legend(handles=[no_uses, branch, def_in, def_out, def_glob,imm, use_out], bbox_to_anchor=(1, 1), bbox_transform=plt.gcf().transFigure)

        pos = graphviz_layout(self.graph, prog='dot')

        nx.draw(self.graph, pos, with_labels=True, font_size=6, node_color=color_array)
        plt.show()

    def Convert_All_Br_To_Bne(self):
        for block in self.block_dfgs:
            block.Convert_Br_To_Bne(self)


import os
import sys

SVG_FOLDER_NAME = "SVGs"
NESTED_FOLDER_NAME = "_moreSVGs_"

def read_file(file_path):
    with open(file_path, "r") as f:
        return f.read()

def write_file(file_path, data):
    with open(file_path, "w") as f:
        f.write(data)

def get_font_format(font_file_path):
    with open(font_file_path, "rb") as f:
        head = f.read(4).decode()

    if head == "OTTO":
        return "OTF"
    elif head in ("\x00\x01\x00\x00", "true"):
        return "TTF"
    elif head == "wOFF":
        return "WOFF"
    elif head == "wOF2":
        return "WOFF2"
    return None

def validate_font_paths(paths_list):
    validated_paths_list = []
    for path in paths_list:
        path = os.path.realpath(path)
        if (os.path.isfile(path) and get_font_format(path) in
                ['OTF', 'TTF', 'WOFF', 'WOFF2']):
            validated_paths_list.append(path)
        else:
            print("ERROR: {} is not a valid font file path.".format(path),
                  file=sys.stderr)
    return validated_paths_list

def split_comma_sequence(comma_str):
    return [item.strip() for item in comma_str.split(',')]

def final_message(num_files_saved):
    if not num_files_saved:
        num_files_saved = 'No'
    plural = 's' if num_files_saved != 1 else ''
    print("{} SVG file{} saved.".format(num_files_saved, plural),
          file=sys.stdout)

def create_folder(folder_path):
    try:
        os.makedirs(folder_path)
    except OSError:
        if not os.path.isdir(folder_path):
            raise

def create_nested_folder(nested_folder_path, main_folder_path):
    """
    Creates a nested folder and returns its path.
    This additional folder is created when file names conflict.
    """
    if not nested_folder_path:
        nested_folder_path = os.path.join(main_folder_path, NESTED_FOLDER_NAME)
        create_folder(nested_folder_path)
    return nested_folder_path

def validate_folder_path(folder_path):
    """
    Validates that the path is a folder.
    Returns the complete path.
    """
    path = os.path.realpath(folder_path)
    if os.path.isdir(path):
        return path
    else:
        print("ERROR: {} is not a valid folder path.".format(path),
              file=sys.stderr)
        sys.exit(1)

def get_output_folder_path(provided_folder_path, first_font_path):
    """
    If the path to the output folder was NOT provided, create
    a folder in the same directory where the first font is.
    If the path was provided, validate it.
    Returns a valid output folder.
    """
    if provided_folder_path:
        return validate_folder_path(provided_folder_path)
    return os.path.join(os.path.dirname(first_font_path), SVG_FOLDER_NAME)

def get_gnames_to_save_in_nested_folder(gnames_list):
    """
    On case-insensitive systems the SVG files cannot be all saved to the
    same folder otherwise a.svg and A.svg would be written over each other,
    for example. So, pre-process the list of glyph names to find which ones
    step on each other, and save half of them in a nested folder. This
    approach won't handle the case where a.svg and A.svg are NOT generated
    on the same run, but that's fine; the user will have to handle that.
    Also, the process below assumes that there are no more than 2 conflicts
    per name, i.e. it will handle "the/The" but not "the/The/THE/...";
    this shouldn't be a problem in 99% of the time.
    Returns list of glyph names that need to be saved in a nested folder.
    """
    unique_names_set = set()
    gnames_to_save_in_nested_folder = []
    for gname in gnames_list:
        if gname.lower() in unique_names_set:
            gnames_to_save_in_nested_folder.append(gname)
        unique_names_set.add(gname.lower())
    return gnames_to_save_in_nested_folder


"""
    General pipeline for EmoPlay
"""

import glob

# Custom classes
import play
import senticnet
import vizualisation

def main():
    """ Main function of EmoPlay.

    pipeline:

        (1) Loads senticnet [mandatory for emotions' search]

        (2) Finds all xml files

        (3) Makes the whole process for each xml file [takes a long time]

        (4) Loads the play into a new object

        (5) Loops through each speech of each character to get
            the emotions for each speech of the play

        (6) Exports the data to CSV, for later reuse

        (7) If needed, reimports everything from the csv
    """

    # (1) Loads senticnet [mandatory for emotions' search]
    stcnet = senticnet.Senticnet()

    # (2) Finds all xml files
    plays = glob.glob("theater/*.xml")

    # (3) Makes the whole process for each xml file [takes a long time]
    for path in plays:

        # (4) Loads the play into a new object
        p = play.Play(path)

        # Avoids processing not found plays
        if p.speech_amount > 0:
            # (5) Loops through each speech of each character to get
            # the emotions for each speech of the play
            for character in p.characters:
                for speech in character.speeches:
                    # Compute overall emotions of each speech
                    speech.getEmotions(stcnet)

            # (6) Exports the data to CSV, for later reuse
            p.to_csv()

            # (7) If needed, reimports everything from the csv
            #path_csv = "path/to/csv"
            #p.from_csv(path_csv)

            # (8) Generates and saves plots

            # Bar plot for speeches
            barPlotSpeeches = vizualisation.Vizualisation(p, "bps")
            barPlotSpeeches.plot(True)

            # Bar plot for words
            barPlotWords = vizualisation.Vizualisation(p, "bpw")
            barPlotWords.plot(True)

            # Emotions by character
            emotionByCharacter = vizualisation.Vizualisation(p, "ebc")
            emotionByCharacter.plot(True)

            # Emotions by act
            emotionByAct = vizualisation.Vizualisation(p, "eba")
            emotionByAct.plot(True)

if __name__ == '__main__':
    main()


# แม่สูตรคูณ

# แสดงแม่สูตรคูณ 2,3,4,5......
    #2x1....2x12....,3x1....,3x12,....

# 2,3

for x in range(2,13):
    print("แม่ = ",x)
    for y in range(1,13):
        print(x,'x',y," = ",(x*y))

#อยากป้อนแม่สูตรคูณที่คูณกับ 1-12 โดยระบุเอง
start=int(input("ป้อนมแม่สูตรเริ่มต้น = "))
stop=int(input("ป้อนแม่สูตรสุดท้าย = "))

for x in range(start,stop+1):
    print("แม่ = ",x)
    for y in range(1,13):
        print(x,'x',y," = ",(x*y))

PYTHON TUTORAIL/Tutorail/Ep29 Assignment8 แม่สูตรคูณ.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 10 14:29:33 2020

@author: lxmera
"""

def DownloadAAL3(PATH):
    import os
    from nilearn import datasets

    if os.path.isfile(PATH+'/AAL3_for_SPM12.tar.gz'):
        print('Done')
    else:
        os.system('wget https://www.oxcns.org/AAL3_for_SPM12.tar.gz -P '+PATH)

    if os.path.exists(PATH+'/AAL3'):
        print('Done')
    else:
        os.system('tar -zxvf '+PATH+'/AAL3_for_SPM12.tar.gz -C '+PATH)

    if os.path.exists(PATH+'/AAL3/AAL3.mat'):
        print('Done')
    else:
        os.system('wget https://www.dropbox.com/s/eeullhxfv8tk6fg/AAL3.mat?dl=1 -P '+PATH+'/AAL3')
        os.system('mv '+PATH+'/AAL3/AAL3.mat?dl=1 '+PATH+'/AAL3/AAL3.mat')

    ###################
    A_HOx='/home/lxmera/nilearn_data/fsl/data/atlases/HarvardOxford/HarvardOxford-cort-maxprob-thr25-2mm.nii.gz'
    if os.path.isfile(A_HOx):
        print('Done')
    else:
        ###############################
        if os.path.exists('/home/lxmera'):
            datasets.fetch_atlas_harvard_oxford('cort-maxprob-thr25-2mm')
        else:
            print('####################################')
            print('#                                  #')
            print('#       CAMBIA EL USUARIO          #')
            print('#                                  #')
            print('####################################')

    mat2=A_HOx[:A_HOx.rfind('/')]+'/labelsHof.mat'
    if os.path.isfile(mat2):
        print('Done')
    else:
        os.system('wget https://www.dropbox.com/s/t0keqsapcbdl10b/labelsHof.mat?dl=1 -P '+A_HOx[:A_HOx.rfind('/')])
        os.system('mv '+A_HOx[:A_HOx.rfind('/')]+'/labelsHof.mat?dl=1 '+A_HOx[:A_HOx.rfind('/')]+'/labelsHof.mat')

    A_MSDL='/home/lxmera/nilearn_data/msdl_atlas/MSDL_rois/msdl_rois.nii'
    if os.path.isfile(A_MSDL):
        print('Done')
    else:
        ###############################
        if os.path.exists('/home/lxmera'):
            datasets.fetch_atlas_msdl()
        else:
            print('####################################')
            print('#                                  #')
            print('#       CAMBIA EL USUARIO          #')
            print('#                                  #')
            print('####################################')

    mat3=A_MSDL[:A_MSDL.rfind('/')]+'/labelsMSDL.mat'
    if os.path.isfile(mat3):
        print('Done')
    else:
        os.system('wget https://www.dropbox.com/s/j18tleliudcx2yn/labelsMSDL.mat?dl=1 -P '+A_MSDL[:A_MSDL.rfind('/')])
        os.system('mv '+A_MSDL[:A_MSDL.rfind('/')]+'/labelsMSDL.mat?dl=1 '+A_MSDL[:A_MSDL.rfind('/')]+'/labelsMSDL.mat')

    atlas=PATH+'/AAL3/AAL3.nii.gz'
    mat=PATH+'/AAL3/AAL3.mat'
    return atlas, mat, A_HOx, mat2, A_MSDL, mat3

def sujetos():
    import nibabel as nb
    ANAT='/home/lxmera/neuro3/data/ds000133/sub-01/ses-pre/anat/sub-01_ses-pre_T1w.nii.gz'
    FUNC='/home/lxmera/neuro3/data/ds000133/sub-01/ses-pre/func/sub-01_ses-pre_task-rest_run-01_bold.nii.gz'
    print(nb.load(ANAT).shape)
    print(nb.load(FUNC).shape)
    return ANAT, FUNC

def texto(uno,  dos, atlas):
    from nilearn import plotting
    import os
    print('Anatomica ', uno)
    print('Funcional ', dos)

    ##################################
    Resul=os.getcwd()+'-Results'
    os.system('mkdir '+Resul)
    ##################################

    plot_atlas=plotting.plot_roi(atlas)
    plot_atlas.savefig(Resul+'/AtlasAAL3.svg')

def series_times_ROI(Maps, func, typeF):
    from nilearn.input_data import NiftiLabelsMasker, NiftiMapsMasker
    from nilearn import plotting
    import scipy.io as sio
    import numpy as np
    import os
    ##################################
    Resul=os.getcwd()#+'-Results'
    n_map=Maps[Maps.rfind('/')+1:][:Maps[Maps.rfind('/')+1:].find('.')]
    n_plot='empty_plot'
    #os.system('mkdir '+Resul)
    ##################################
    if typeF=='Labels':
        masker = NiftiLabelsMasker(labels_img=Maps, standardize=True)
        plot_atlas=plotting.plot_roi(Maps)
        n_plot=Resul+'/Atlas_'+n_map+'_'+typeF+'.svg'
        plot_atlas.savefig(n_plot)
    if typeF=='Maps':
        masker = NiftiMapsMasker(maps_img=Maps, standardize=True, memory='nilearn_cache', verbose=5)

    time_series = masker.fit_transform(func)
    print('Shape of serial times ', np.shape(time_series))
    out_mat=Resul+'/Time_series_'+n_map+'_'+typeF+'.mat'
    sio.savemat(out_mat, {'time_series': time_series})

    return out_mat, n_plot

def Functional_Connectivity(Time_s, in_mat, typeF, kind):
    from nilearn.connectome import ConnectivityMeasure
    from nilearn import plotting
    import scipy.io as sio
    import numpy as np
    import os

    ##################################
    Resul=os.getcwd()#+'-Results'
    n_time=Time_s[Time_s.rfind('/')+1:][:Time_s[Time_s.rfind('/')+1:].find('.')]
    n_plot2='empty_plot'
    #os.system('mkdir '+Resul)
    ##################################

    time_series=sio.loadmat(Time_s)['time_series']
    data=sio.loadmat(in_mat)
    labels=data['labels']

    correlation_measure = ConnectivityMeasure(kind=kind)
    correlation_matrix = correlation_measure.fit_transform([time_series])[0]
    np.fill_diagonal(correlation_matrix, 0)

    if typeF=='Labels':
        vec_size=data['size'][0]
        indx=np.argsort(vec_size)[-np.shape(time_series)[1]:]
        indx=np.sort(indx)
        labels=labels[indx]
    if typeF=='Maps':
        coord=data['region_coords']
        plot_conne=plotting.plot_connectome(correlation_matrix, coord, edge_threshold="80%", colorbar=True)
        n_plot2=Resul+'/ConnectomePlotMDLS.svg'
        plot_conne.savefig(n_plot2)

    size_f=int((np.shape(time_series)[0]**(1/7))*30/2.064782369420003)
    ima=plotting.plot_matrix(correlation_matrix, figure=(size_f, size_f), labels=labels, colorbar=True, vmax=0.8, vmin=-0.8)
    n_plot=Resul+'/Correlation_matrix_'+kind+'_'+n_time+'.svg'
    out_mat=Resul+'/Correlation_matrix_'+kind+'_'+n_time+'.mat'
    ima.figure.savefig(n_plot)
    sio.savemat(out_mat, {'Correlation': correlation_matrix, 'labels': labels})
    return out_mat, n_plot, n_plot2

def Calculate_ALFF_fALFF(slow, ASamplePeriod, Time_s, plots=False):
    import os
    import math
    import scipy
    import numpy as np
    import scipy.io as sio
    import matplotlib.pyplot as plt

    slow=(slow-2)
    AllVolume=sio.loadmat(Time_s)['time_series']
    row, col=np.shape(AllVolume)
    names=['slow_2', 'slow_3', 'slow_4', 'slow_5']
    SlowHigh=[0.25, 0.198, 0.073, 0.027]
    SlowLow=[0.198, 0.073, 0.027, 0.01]

    HighCutoff=SlowHigh[slow] #the High edge of the pass band
    LowCutoff=SlowLow[slow]   #the low edge of the pass band

    sampleFreq 	 = 1/ASamplePeriod
    sampleLength = row

    p=1
    while True:
        if 2**p >= sampleLength:
            break
        else:
            p=p+1
    #paddedLength = 2**(nextpow2(sampleLength))
    paddedLength = 2**(p)

    if (LowCutoff >= sampleFreq/2): # All high included
        idx_LowCutoff = paddedLength/2 + 1;
    else: # high cut off, such as freq > 0.01 Hz
        idx_LowCutoff = math.ceil(LowCutoff * paddedLength * ASamplePeriod + 1);
    # Change from round to ceil: idx_LowCutoff = round(LowCutoff *paddedLength *ASamplePeriod + 1);

    if (HighCutoff>=sampleFreq/2)and(HighCutoff==0):# All low pass
        idx_HighCutoff = paddedLength/2 + 1;
    else: #Low pass, such as freq < 0.08 Hz
        idx_HighCutoff =  np.fix (HighCutoff *paddedLength *ASamplePeriod + 1);
    # Change from round to fix: idx_HighCutoff	=round(HighCutoff *paddedLength *ASamplePeriod + 1);
    #Zero Padding
    a = np.zeros((paddedLength - sampleLength,len(AllVolume[2])))
    AllVolume = np.concatenate((AllVolume, a), axis=0)

    print('\t Performing FFT ...');

    AllVolume=np.transpose(AllVolume)
    AllVolume = 2*np.true_divide(abs(scipy.fft(AllVolume)),sampleLength);
    AllVolume=np.transpose(AllVolume)

    print('Calculating ALFF for slow', slow+2,' ...')
    ALFF_2D = np.mean(AllVolume[idx_LowCutoff:int(idx_HighCutoff)], axis=0)

    print('Calculating fALFF for slow', slow+2,' ...')
    num = np.sum(AllVolume[(idx_LowCutoff):int(idx_HighCutoff)],axis=0,dtype=float)
    den = np.sum(AllVolume[2:int(paddedLength/2 + 1)],axis=0,dtype=float)
    fALFF_2D =  num/den

    metricas = np.concatenate((ALFF_2D, fALFF_2D), axis=0).reshape((2,col))

    if plots:
        plt.figure()
        plt.title('Power Spectral Density')
        freq=np.arange(0.0, 1/ASamplePeriod, 1/(ASamplePeriod*np.shape(AllVolume)[0]))
        plt.plot(freq,AllVolume)

        plt.figure()
        plt.title('ALFF')
        plt.plot(metricas[0,:])

        plt.figure()
        plt.title('fALFF')
        plt.plot(metricas[1,:])
    print('...done')

    ##################################
    Resul=os.getcwd()#+'-Results'
    #os.system('mkdir '+Resul)
    ##################################
    out_mat=Resul+'/ALFF_and_fALFF_'+names[slow]+'.mat'
    sio.savemat(out_mat, {'ALFF': metricas[0], 'fALFF': metricas[1]})
    return out_mat

def Integrate(t1, t2, t3):
    Time_files=[]
    Time_files.append(t1)
    Time_files.append(t2)
    Time_files.append(t3)
    return Time_files

def Calculate_ReHo(func, nneigh, help_reho=False):
    if help_reho:
        from nipype.interfaces import afni
        afni.ReHo.help()
    import os
    Resul=os.getcwd()#+'-Results'
    n_func=func[func.rfind('/')+1:][:func[func.rfind('/')+1:].find('.')]
    out_ReHo=Resul+'/'+n_func+'_ReHo_'+str(nneigh)+'.nii.gz'
    print('3dReHo -prefix '+out_ReHo+' -inset '+func+' -nneigh '+str(nneigh))
    os.system('3dReHo -prefix '+out_ReHo+' -inset '+func+' -nneigh '+str(nneigh))
    if os.path.isfile(out_ReHo):
        print('....ReHo done')
    else:
        print('Fatal error: The ReHo file was NOT created')
    return out_ReHo

def get_graph(Mat_D, Threshold, percentageConnections=False, complet=False):
    import scipy.io as sio
    import numpy as np
    import networkx as nx
    import pandas as pd
    import os
    Data=sio.loadmat(Mat_D)
    matX=Data['Correlation']#[:tamn,:tamn]
    labels=Data['labels']
    print(np.shape(matX))
    print(np.shape(labels))
    print(np.min(matX), np.max(matX))

    if percentageConnections:
        if percentageConnections>0 and percentageConnections<1:
            for i in range(-100,100):
                per=np.sum(matX>i/100.)/np.size(matX)
                if per<=Threshold:
                    Threshold=i/100.
                    break
            print(Threshold)
        else:
            print('The coefficient is outside rank')

    #Lista de conexion del grafo
    row, col=np.shape(matX)
    e=[]
    for i in range(1,row):
      for j in range(i):
          if complet:
              e.append((labels[i],labels[j],matX[i,j]))
          else:
              if matX[i,j]>Threshold:
                  e.append((labels[i],labels[j],matX[i,j]))

    print(np.shape(e)[0], int(((row-1)*row)/2))

    #Generar grafo
    G=nx.Graph()
    G.add_weighted_edges_from(e)
    labelNew=list(G.nodes)

    #Metricas por grafo (ponderados)
    Dpc=nx.degree_pearson_correlation_coefficient(G, weight='weight')
    cluster=nx.average_clustering(G, weight='weight')

    #No ponderados
    estra=nx.estrada_index(G)
    tnsity=nx.transitivity(G)
    conNo=nx.average_node_connectivity(G)
    ac=nx.degree_assortativity_coefficient(G)

    #Metricas por nodo
    tam=15
    BoolCenV=False
    BoolLoad=False
    alpha=0.1
    beta=1.0

    katxCN=nx.katz_centrality_numpy(G, alpha=alpha, beta=beta, weight='weight')
    bcen=nx.betweenness_centrality(G, weight='weight')
    av_nd=nx.average_neighbor_degree(G, weight='weight')
    ctr=nx.clustering(G, weight='weight')
    ranPaN=nx.pagerank_numpy(G, weight='weight')
    Gol_N=nx.hits_numpy(G)
    Dgc=nx.degree_centrality(G)
    cl_ce=nx.closeness_centrality(G)
    cluster_Sq=nx.square_clustering(G)
    centr=nx.core_number(G)
    cami=nx.node_clique_number(G)
    camiN=nx.number_of_cliques(G)
    trian=nx.triangles(G)
    colorG=nx.greedy_color(G)
    try:
        cenVNum=nx.eigenvector_centrality_numpy(G,weight='weight')
        tam=tam+1
        BoolCenV=True
    except TypeError:
        print("La red es muy pequeña y no se puede calcular este parametro gil")
    except:
        print ('NetworkXPointlessConcept: graph null')
    if Threshold>0:
        carga_cen=nx.load_centrality(G, weight='weight') #Pesos  positivos
        BoolLoad=True
        tam=tam+1
    #katxC=nx.katz_centrality(G, alpha=alpha, beta=beta, weight='weight')
    #cenV=nx.eigenvector_centrality(G,weight='weight')
    #cenV=nx.eigenvector_centrality(G,weight='weight')
    #Golp=nx.hits(G)
    #Gol_si=nx.hits_scipy(G)
    #ranPa=nx.pagerank(G, weight='weight')
    #ranPaS=nx.pagerank_scipy(G, weight='weight')

    matrix_datos=np.zeros((tam,np.shape(labelNew)[0]))
    tam=15
    print(np.shape(matrix_datos))
    lim=np.shape(labelNew)[0]
    for i in range(lim):
      roi=labelNew[i]
      #print(roi)
      matrix_datos[0,i]=katxCN[roi]
      matrix_datos[1,i]=bcen[roi]
      matrix_datos[2,i]=av_nd[roi]
      matrix_datos[3,i]=ctr[roi]
      matrix_datos[4,i]=ranPaN[roi]
      matrix_datos[5,i]=Gol_N[0][roi]
      matrix_datos[6,i]=Gol_N[1][roi]
      matrix_datos[7,i]=Dgc[roi]
      matrix_datos[8,i]=cl_ce[roi]
      matrix_datos[9,i]=cluster_Sq[roi]
      matrix_datos[10,i]=centr[roi]
      matrix_datos[11,i]=cami[roi]
      matrix_datos[12,i]=camiN[roi]
      matrix_datos[13,i]=trian[roi]
      matrix_datos[14,i]=colorG[roi]
      if BoolCenV:
          matrix_datos[15,i]=cenVNum[roi]
          tam=tam+1
      if BoolLoad:
          matrix_datos[16,i]=carga_cen[roi]
          tam=tam+1
      #matrix_datos[0,i]=katxC[roi]
      #matrix_datos[2,i]=cenV[roi]
      #matrix_datos[7,i]=Golp[0][roi]
      #matrix_datos[9,i]=Gol_si[0][roi]
      #matrix_datos[10,i]=Golp[1][roi]
      #matrix_datos[12,i]=Gol_si[1][roi]
      #matrix_datos[22,i]=ranPa[roi]
      #matrix_datos[24,i]=ranPaS[roi]
    FuncName=['degree_pearson_correlation_coefficient', 'average_clustering', 'estrada_index', 'transitivity', 'average_node_connectivity', 'degree_assortativity_coefficient', 'katz_centrality_numpy', 'betweenness_centrality', 'average_neighbor_degree', 'clustering', 'pagerank_numpy', 'hits_numpy0', 'hits_numpy1','degree_centrality', 'closeness_centrality', 'square_clustering', 'core_number', 'node_clique_number', 'number_of_cliques', 'triangles', 'greedy_color','eigenvector_centrality_numpy', 'load_centrality']
    frame=pd.DataFrame(matrix_datos)
    frame.columns=labelNew
    frame.index=FuncName[6:tam]

    Resul=os.getcwd()
    out_data=Resul+'/graph_metrics.csv'
    out_mat=Resul+'/graph_metrics_global.mat'

    frame.to_csv(out_data)
    sio.savemat(out_mat, {FuncName[0]: Dpc, FuncName[1]: cluster, FuncName[2]: estra, FuncName[3]: tnsity, FuncName[4]: conNo, FuncName[5]: ac})
    return out_data, out_mat

if __name__=="__main__":

  from os.path import join as opj
  from nipype import Workflow, Node, Function, MapNode
  from nipype.interfaces.io import DataSink
  import cv2

  experiment_dir = '/home/lxmera/neuro3/output'
  output_dir = 'datasink_Metrics'
  working_dir = 'workingdir'
  ATLAS, mat, ATLAS2, mat2, ATLAS3, mat3=DownloadAAL3(opj(experiment_dir, working_dir))

  Subjec=Node(Function(input_names=[], output_names=['ANAT', 'FUNC'], function=sujetos), name='Sujetos')

  Text_In=Node(Function(input_names=['uno', 'dos', 'atlas'], output_names=[], function=texto), name='texto_recibido')
  Text_In.inputs.atlas=ATLAS

  series=Node(Function(input_names=['Maps', 'func', 'typeF'], output_names=['out_mat', 'n_plot'], function=series_times_ROI), name='series_time_AAL3')
  series.inputs.Maps=ATLAS
  series.inputs.typeF='Labels'

  series2=Node(Function(input_names=['Maps', 'func', 'typeF'], output_names=['out_mat', 'n_plot'], function=series_times_ROI), name='series_time_HarvardOxford')
  series2.inputs.Maps=ATLAS2
  series2.inputs.typeF='Labels'

  series3=Node(Function(input_names=['Maps', 'func', 'typeF'], output_names=['out_mat', 'n_plot'], function=series_times_ROI), name='series_time_MSDL')
  series3.inputs.Maps=ATLAS3
  series3.inputs.typeF='Maps'

  Integ=Node(Function(input_names=['t1', 't2', 't3'], output_names=['Time_files'], function=Integrate), name='Integrate_files')

  correlation=Node(Function(input_names=['Time_s', 'in_mat', 'typeF', 'kind'], output_names=['out_mat', 'n_plot', 'n_plot2'], function=Functional_Connectivity), name='Funcional_connectivity_ALL3')
  correlation.inputs.in_mat=mat
  correlation.inputs.typeF='Labels'
  correlation.inputs.kind='correlation'

  correlation2=Node(Function(input_names=['Time_s', 'in_mat', 'typeF', 'kind'], output_names=['out_mat', 'n_plot', 'n_plot2'], function=Functional_Connectivity), name='Funcional_connectivity_HOx')
  correlation2.inputs.in_mat=mat2
  correlation2.inputs.typeF='Labels'
  correlation2.inputs.kind='correlation'

  correlation3=Node(Function(input_names=['Time_s', 'in_mat', 'typeF', 'kind'], output_names=['out_mat', 'n_plot', 'n_plot2'], function=Functional_Connectivity), name='Funcional_connectivity_MSDL')
  correlation3.inputs.in_mat=mat3
  correlation3.inputs.typeF='Maps'
  correlation3.inputs.kind='correlation'

  Integ2=Node(Function(input_names=['t1', 't2', 't3'], output_names=['Corre_files'], function=Integrate), name='Correlation_files')

  Graph=MapNode(Function(input_names=['Mat_D', 'Threshold', 'percentageConnections', 'complet'], output_names=['out_data', 'out_mat'], function=get_graph), name='Graph_Metricts', iterfield=['Mat_D'])
  Graph.iterables = ("Threshold", [0.6])
  Graph.inputs.percentageConnections=False #Porcentaje de conexiones  utilizadas

  ALFF_fALFF=MapNode(Function(input_names=['slow', 'ASamplePeriod', 'Time_s', 'plots'], output_names=['out_mat'], function=Calculate_ALFF_fALFF), name='ALFF_and_fALFF', iterfield=['Time_s'])
  ALFF_fALFF.iterables = ("slow", [2, 3, 4, 5])
  ALFF_fALFF.inputs.ASamplePeriod=1.6   #Time repetition

  ReHo=Node(Function(input_names=['func', 'nneigh', 'help_reho'], output_names=['out_ReHo'], function=Calculate_ReHo), name='Regional_homogeneity')
  ReHo.iterables = ("nneigh", [7, 19, 27])

  # Datasink - Crear una carpeta de salidad para almacenar las entradas
  datasink_metricas = Node(DataSink(base_directory=experiment_dir, container=output_dir), name="datasink_metricas")
  substitutions = [('_subject_id_', 'sub-'),
                 ('_task_name_', '/task-'),
                 ('_fwhm_', 'fwhm-'),
                 ('_roi', ''),
                 ('_mcf', ''),
                 ('_st', ''),
                 ('_flirt', ''),
                 ('.nii_mean_reg', '_mean'),
                 ('.nii.par', '.par')]

  subjFolders = [('slow-%s/' % f, 'slow-%s_' % f) for f in [2, 3, 4, 5]]
  substitutions.extend(subjFolders)
  datasink_metricas.inputs.substitutions = substitutions

  ###################################################Crear el flujo de trabajo#
  metricas = Workflow(name='metricas')
  metricas.base_dir = opj(experiment_dir, working_dir)

  #Concatenar cada uno de lo nodos
  metricas.connect([(Subjec, series, [('FUNC', 'func')]),
                    (Subjec, series2, [('FUNC', 'func')]),
                    (Subjec, series3, [('FUNC', 'func')]),
                    (series, Integ, [('out_mat', 't1')]),
                    (series2, Integ, [('out_mat', 't2')]),
                    (series3, Integ, [('out_mat', 't3')]),
                    (Integ, ALFF_fALFF, [('Time_files', 'Time_s')]),

                    (Subjec, ReHo, [('FUNC', 'func')]),

                    (series, correlation, [('out_mat', 'Time_s')]),
                    (series2, correlation2, [('out_mat', 'Time_s')]),
                    (series3, correlation3, [('out_mat', 'Time_s')]),
                    (correlation, Integ2, [('out_mat', 't1')]),
                    (correlation2, Integ2, [('out_mat', 't2')]),
                    (correlation3, Integ2, [('out_mat', 't3')]),
                    (Integ2, Graph, [('Corre_files', 'Mat_D')]),

                    ###########################################################
                    (series, datasink_metricas, [('out_mat', 'metricas.@out_mats'), ('n_plot', 'metricas.@plot_atlas')]),
                    (series2, datasink_metricas, [('out_mat', 'metricas.@out_mats2'), ('n_plot', 'metricas.@plot_atlas2')]),
                    (series3, datasink_metricas, [('out_mat', 'metricas.@out_mats3')]),

                    (correlation, datasink_metricas, [('out_mat', 'metricas.@out_mat_c'), ('n_plot', 'metricas.@plot_matrix')]),
                    (correlation2, datasink_metricas, [('out_mat', 'metricas.@out_mat_c2'), ('n_plot', 'metricas.@plot_matrix2')]),
                    (correlation3, datasink_metricas, [('out_mat', 'metricas.@out_mat_c3'), ('n_plot', 'metricas.@plot_matrix3'), ('n_plot2', 'metricas.@plot_connectome')]),

                    (ReHo, datasink_metricas, [('out_ReHo', 'metricas.@out_ReHo')]),
                    (ALFF_fALFF, datasink_metricas, [('out_mat', 'metricas.@out_mat')]),
                    (Graph, datasink_metricas, [('out_data', 'metricas.@out_data'), ('out_mat', 'metricas.@out_matGraph')]),
                    ])

  #Generar el gráfico y visualizarlo
  metricas.write_graph(graph2use='flat')
  grafo=cv2.imread('/home/lxmera/neuro3/output/workingdir/metricas/graph_detailed.png')
  #plt.figure()
  #plt.imshow(grafo)

  #Ruuuuunn
  metricas.run('MultiProc', plugin_args={'n_procs': 4})


###########################################################################
#          (C) Vrije Universiteit, Amsterdam (the Netherlands)            #
#                                                                         #
# This file is part of AmCAT - The Amsterdam Content Analysis Toolkit     #
#                                                                         #
# AmCAT is free software: you can redistribute it and/or modify it under  #
# the terms of the GNU Affero General Public License as published by the  #
# Free Software Foundation, either version 3 of the License, or (at your  #
# option) any later version.                                              #
#                                                                         #
# AmCAT is distributed in the hope that it will be useful, but WITHOUT    #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public     #
# License for more details.                                               #
#                                                                         #
# You should have received a copy of the GNU Affero General Public        #
# License along with AmCAT.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################

from __future__ import unicode_literals, print_function, absolute_import
import os
import logging;

from django.core.cache import cache
from django.db import models

from amcat.tools.model import AmcatModel

log = logging.getLogger(__name__)

WARNING_NOT_PRODUCTION = ("This is {server}. "
                           "Use amcat.vu.nl "
                           "unless you explicitly want to use this server. "
                          "Changes made here will probably not be saved")

SINGLETON_ID = 1

# Increment to current db version to trigger db upgrades that syncdb can't handle
# See amcat.tools.db_upgrader
CURRENT_DB_VERSION = 22

MEDIUM_CACHE_ENABLED = "medium_cache_enabled"
TIMEOUT_INFINITY = 31536000 # One year, actually. By then we should have upgraded to Django
                            # 1.6, which allows 'real' infinite caching.

class AmCAT(AmcatModel):
    id = models.BooleanField(primary_key=True, db_column="singleton_pk")

    global_announcement = models.TextField(blank=True, null=True)
    db_version = models.IntegerField()

    def save(self, *args, **kwargs):
        if self.id != SINGLETON_ID:
            raise NotImplementedError()
        super(AmCAT, self).save(*args, **kwargs)

    @classmethod
    def mediums_cache_enabled(self):
        return cache.get(MEDIUM_CACHE_ENABLED) or False

    @classmethod
    def enable_mediums_cache(self, enable=True):
        """
        Disable or enable articleset medium caching. This option can also be accessed
        via manage.py medium_cache [on|off].

        When off, various parts of AmCAT won't use project <--> mediums information
        although caches will always be updated when adding new sets / articles. This
        allows existing installations to build their caches while running.

        @param enable: Disables caching for mediums when set to False
        @return: None
        """
        return cache.set(MEDIUM_CACHE_ENABLED, enable, TIMEOUT_INFINITY)

    @property
    def server_warning(self):
        status = os.environ.get('AMCAT_SERVER_STATUS', '')
        if status != "production":
            if status:
                server = "the {status} server".format(**locals())
            else:
                server = "not the production server"
            return WARNING_NOT_PRODUCTION.format(**locals())

    @classmethod
    def get_instance(cls):
        try:
            return cls.objects.get(pk=SINGLETON_ID)
        except AmCAT.DoesNotExist:
            # create singleton here - don't use initial data as that will override db_version on syncdb
            return AmCAT.objects.create(db_version = CURRENT_DB_VERSION, id=SINGLETON_ID)

    class Meta():
        db_table = 'amcat_system'
        app_label = 'amcat'

###########################################################################
#                          U N I T   T E S T S                            #
###########################################################################

from amcat.tools import amcattest

class TestAmCAT(amcattest.AmCATTestCase):
    def test_get_instance(self):
        a = AmCAT.get_instance()
        self.assertEqual(type(a), AmCAT)

        os.environ['AMCAT_SERVER_STATUS']=""
        self.assertEqual(a.server_warning,
                         WARNING_NOT_PRODUCTION.format(server = "not the production server"))

        os.environ['AMCAT_SERVER_STATUS']="production"
        self.assertEqual(a.server_warning, None)


from flask import render_template, flash, redirect, url_for
from app import app
from app.forms import LoginForm

@app.route('/')
@app.route('/index')
def index():
    user = {'username': 'Ian'}
    posts = [
        {
            'author': {'username': 'Joey Dunkleton'},
            'body': 'Geuss that means more bacon for me!'
        },
        {
            'author': {'username': 'Susan'},
            'body': 'I wish I could shrink you down and carry you around in my big, stinky bucket.'
        }
    ]
    return render_template('index.html', title="Home", user=user, post=posts)

@app.route('/login', methods=['GET','POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for user {}, remember_me={}'.format(
            form.username.data, form.remember_me.data
            ))
        return redirect(url_for('index'))
    return render_template('login.html', title='Sign In', form=form)


# Digite numeros de QI de essoa diversas, o user deve continuar digitando até digitar 0  (utilizar o break p/ interromper). Fazer contagem dos genios (quem tem QI superior aou igual a 140 e ignorar quem tem menos), apenas números ineteiros são permitidos

cont = 0
while True:
    try :
        print("Digite o valor de QI")
        print("Ou 0 para encerrar")
        qi = int(input())
        if qi == 0 :
            break
        if qi < 140 :
            continue
        cont += 1
    except ValueError:
        print("Erro! Apenas números inteiros.")
print(f"Quantidade de gênios é {cont}")


import sublime
from sublime_plugin import TextCommand, WindowCommand
import re

from ...common import util
from ..git_command import GitCommand
from ..ui_mixins.quick_panel import PanelActionMixin, show_branch_panel

COMMIT_NODE_CHAR = "●"
COMMIT_NODE_CHAR_OPTIONS = "●*"
COMMIT_LINE = re.compile(r"[%s][ /_\|\-.]*([a-z0-9]{3,})" % COMMIT_NODE_CHAR_OPTIONS)

class GsCompareCommitCommand(WindowCommand, GitCommand):

    """
    Show a view of all commits diff between branches.
    """

    def run(self, base_commit, target_commit=None, file_path=None, title=None):
        self.base_commit = base_commit or "HEAD"
        self.target_commit = target_commit or "HEAD"
        self._file_path = file_path
        self.title = title or "COMMIT COMPARISON"
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        # need to get repo_path before the new view is created.
        repo_path = self.repo_path
        view = util.view.get_scratch_view(self, "compare_commit", read_only=True)
        settings = view.settings()
        settings.set("git_savvy.compare_commit_view.target_commit", self.target_commit)
        settings.set("git_savvy.compare_commit_view.base_commit", self.base_commit)
        settings.set("git_savvy.repo_path", repo_path)
        settings.set("git_savvy.file_path", self._file_path)
        settings.set("git_savvy.git_graph_args", self.get_graph_args())
        view.set_syntax_file("Packages/GitSavvy/syntax/graph.sublime-syntax")
        view.set_name(self.title)
        view.sel().clear()
        view.run_command("gs_compare_commit_refresh")
        view.run_command("gs_log_graph_navigate")
        view.run_command("gs_handle_vintageous")
        view.run_command("gs_handle_arrow_keys")

    def get_graph_args(self):
        args = self.savvy_settings.get("git_graph_args")
        if self._file_path:
            file_path = self.get_rel_path(self._file_path)
            args = args + ["--", file_path]
        return args

class GsCompareCommitRefreshCommand(TextCommand, GitCommand):

    """
    Refresh view of all commits diff between branches.
    """

    def run(self, edit):
        diff_contents = self.get_commit_branch_string()
        self.view.run_command("gs_replace_view_text", {"text": diff_contents})

    def get_commit_branch_string(self):
        base_commit = self.view.settings().get("git_savvy.compare_commit_view.base_commit")
        target_commit = self.view.settings().get("git_savvy.compare_commit_view.target_commit")
        file_path = self.file_path
        if file_path:
            diff_contents = "File: {}\n\n".format(file_path)
        else:
            diff_contents = ""
        diff_contents += "Commits on {} and not on {}\n".format(target_commit, base_commit)
        args = self.view.settings().get("git_savvy.git_graph_args")
        args.insert(1, "{}..{}".format(base_commit, target_commit))
        diff_contents += self.git(*args)
        diff_contents = diff_contents.replace("*", COMMIT_NODE_CHAR)
        diff_contents += "\n\nCommits on {} and not on {}\n".format(base_commit, target_commit)
        args[1] = "{}..{}".format(target_commit, base_commit)
        diff_contents += self.git(*args)
        diff_contents = diff_contents.replace("*", COMMIT_NODE_CHAR)
        return diff_contents

class GsCompareCommitShowDiffCommand(TextCommand, GitCommand):

    """
    Refresh view of all commits diff between branches.
    """

    def run(self, edit, reverse=False):
        self._reverse = reverse
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        base_commit = self.view.settings().get("git_savvy.compare_commit_view.base_commit")
        target_commit = self.view.settings().get("git_savvy.compare_commit_view.target_commit")
        file_path = self.file_path
        if self._reverse:
            self.view.window().run_command("gs_diff", {
                "base_commit": target_commit,
                "target_commit": base_commit,
                "file_path": file_path,
                "disable_stage": True,
                "title": "DIFF: {}..{}".format(target_commit, base_commit)
            })
        else:
            self.view.window().run_command("gs_diff", {
                "base_commit": base_commit,
                "target_commit": target_commit,
                "file_path": file_path,
                "disable_stage": True,
                "title": "DIFF: {}..{}".format(base_commit, target_commit)
            })

class GsCompareAgainstReferenceCommand(WindowCommand, GitCommand):
    def run(self, base_commit=None, target_commit=None, file_path=None):
        self._file_path = file_path
        self._base_commit = base_commit
        self._target_commit = target_commit
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        self.window.show_input_panel("Ref:", "", self.show_diff, None, self.on_cancel)

    def show_diff(self, ref):
        self.window.run_command("gs_compare_commit", {
            "file_path": self._file_path,
            "base_commit": self._base_commit if self._base_commit else ref,
            "target_commit": self._target_commit if self._target_commit else ref
        })

    def on_cancel(self):
        self.window.run_command("gs_compare_against", {
            "base_commit": self._base_commit,
            "target_commit": self._target_commit,
            "file_path": self._file_path
        })

class GsCompareAgainstBranchCommand(WindowCommand, GitCommand):
    def run(self, base_commit=None, target_commit=None, file_path=None):
        self._file_path = file_path
        self._base_commit = base_commit
        self._target_commit = target_commit
        sublime.set_timeout_async(self.run_async)

    def run_async(self):
        show_branch_panel(self.on_branch_selection)

    def on_branch_selection(self, branch):
        if branch:
            self.window.run_command("gs_compare_commit", {
                "file_path": self._file_path,
                "base_commit": self._base_commit if self._base_commit else branch,
                "target_commit": self._target_commit if self._target_commit else branch
            })
        else:
            self.window.run_command("gs_compare_against", {
                "base_commit": self._base_commit,
                "target_commit": self._target_commit,
                "file_path": self._file_path
            })

class GsCompareAgainstCommand(PanelActionMixin, WindowCommand, GitCommand):
    default_actions = [
        ["compare_against_branch", "Branch"],
        ["compare_against_reference", "Reference"],
    ]

    def run(self, base_commit=None, target_commit=None, file_path=None, current_file=False):
        self._file_path = self.file_path if current_file else file_path
        self._base_commit = base_commit
        self._target_commit = target_commit
        super().run()

    def update_actions(self):
        super().update_actions()
        if self._target_commit != "HEAD":
            self.actions = [["compare_against_head", "HEAD"]] + self.actions

    def compare_against_branch(self):
        self.window.run_command("gs_compare_against_branch", {
            "base_commit": self._base_commit,
            "target_commit": self._target_commit,
            "file_path": self._file_path
        })

    def compare_against_reference(self):
        self.window.run_command("gs_compare_against_reference", {
            "base_commit": self._base_commit,
            "target_commit": self._target_commit,
            "file_path": self._file_path
        })

    def compare_against_head(self):
        self.window.run_command("gs_compare_commit", {
            "base_commit": self._base_commit,
            "target_commit": self._target_commit,
            "file_path": self._file_path
        })


import pymongo

class MongoDB:
    def __init__(self):
        self.__myclient = pymongo.MongoClient("mongodb://localhost:27017/")
        self.__mydb = self.__myclient["dbproyecto"]
        self.__country = self.__mydb["country"]
        self.__country_id = ""
        self.__country_coin = self.__mydb["country_coin"]
        self.__country_weather = self.__mydb["country_weather"]

    def insert_dataC(self, data: dict):
        if self.__country.find_one({'name': data['name']}) is None:
            self.__country.insert_one(data)
            print('Insertado con exito! ')

    def insert_dataCC(self, data: dict):
        if self.__country_coin.find_one({'_id': data['_id']}) is None:
            self.__country_coin.insert_one(data)
            print('Insertado con exito! ')

    def insert_dataCW(self, data: dict):
        if self.__country_weather.find_one({'_id': data['_id']}) is None:
            self.__country_weather.insert_one(data)
            print('Insertado con exito! ')

    def query_data_c(self, key_value: dict):
        response = self.__country.find_one(key_value)
        return response

    def query_data_countrycoin(self, key_value: dict):
        response_gtq = []
        response_usd = []
        response_eur = []
        base = ''
        for item in self.__country_coin.find(key_value):
            response_gtq.append((item['_id'][:10], item['currencies_value']['GTQ']))
            response_usd.append((item['_id'][:10], item['currencies_value']['USD']))
            response_eur.append((item['_id'][:10], item['currencies_value']['EUR']))
            base = item['base']
        return response_usd, response_eur, response_gtq, base

    def query_data_countryweather(self, key_value: dict):
        response = {}
        aux = self.__country_weather.find_one(key_value)
        for item in aux['state_weather']:
            response[str(item['state_name'])] = [[], [], []]
        for item in self.__country_weather.find(key_value):
            for state in item['state_weather']:
                response[state['state_name']][0].append((item['_id'][:10], state['weather_data']['Min']))
                response[state['state_name']][1].append((item['_id'][:10], state['weather_data']['Promedio']))
                response[state['state_name']][2].append((item['_id'][:10], state['weather_data']['Max']))
        return response

    def query_data_countryweather_matplotlib(self, key_value: dict):
        return list(self.__country_weather.find(key_value))

    def get_information_data(self):
        data = self.__country.find()
        countries = []
        for country in data:
            countries.append(country)
        return countries

    def get_country_id(self):
        return str(self.__country_id)

    def get_country_weather_id(self, id_weather: str):
        return self.__country_weather.find_one({'_id': id_weather}) is None


# -*- coding: utf-8 -*-
'''
本模块支持2BPP 4BPP 8BPP RGBA4444,RGBA5551,RGB565,RGBA8888,DXT1,DXT3,DXT5相关解析
支持真彩色PNG自动转换为2BPP 4BPP 8BPP图片(像素颜色转换为最近似定义的调色板颜色索引)
非压缩图片解析参考TiledGGD源码code.google.com/p/tiledggd/
调色板近似查找算法参考yin8086的PIM2文件导入工具
DXT系列压缩解析参考微软的DDS File Reference以及https://github.com/Adys/pilgrim/blob/master/pilgrim/decoders/dxtc.py
重要提示:
本模块功能仅为PIL(python imaging library)的辅助图片解析，并不包含PNG导出相关
本模块只是为了方便本世代游戏图片显示读取
本模块的功能是从相应图片数据区中提取像素颜色值并输出为list，
如果是线性图(linear),需设定tile_w,tile_h和width,height相等
'''
import struct
def setAlphaPalette16():
    Palette_list = [(0x11*i,0x11*i,0x11*i,0xff) for i in range(16)]
    return Palette_list
def setAlphaPalette256():
    Palette_list = [(0x1*i,0x1*i,0x1*i,0xff) for i in range(256)]
    return Palette_list
def remap_3ds_tile(tile_list):
    o_list = []
    for i in range(64):
        o_list.append(i)
    for i in range(0,64,16):
        l1 = tile2linearW(o_list[i:i+16],4,4,2,2)
        o_list[i:i+16] = l1
    l2 = tile2linearW(o_list,8,8,4,4)
    new_tile_list = a=[None for i in range(64)]
    for i in range(64):
        new_tile_list[i] =tile_list[l2[i]]
    return new_tile_list
def tile_pal(pal,tile_x,tile_y):
    #将linear排列的调色板转换为tile排列
    #PSP 恐怖惊魂夜2,女神异闻录3P
    ntx=16/tile_x
    nty=16/tile_y
    i=0
    outpal=[]
    for j in range(256):outpal.append((0,0,0,0))#创建一个空调色板
    for ty in range(nty):
        for tx in range(ntx):
            for y in range(tile_y):
                for x in range(tile_x):
                    outpal[(ty * tile_y + y) * 16 + (tx * tile_x + x)]=pal[i]
                    i+= 1
    return outpal
def tile2linearW(data,width,height,tile_h,tile_w):
    ntx = width/tile_w
    nty = height/tile_h
    tilelst=[]
    tile_len=tile_w*tile_h
    for k in range(0,width*height,tile_len):
        tile = data[k:k+tile_len]
        tilelst.append(tile)
    nPixel_data=[]
    for a in range(nty):
        for b in range(tile_h):
            for c in range(ntx):
                for d in range(tile_w):
                    index = a*ntx+c
                    index_tile = b*tile_w+d
                    nPixel_data.append((tilelst[index][index_tile]))
    return nPixel_data
def tile2linear(data,ntx,nty,tile_h,tile_w):
    #将tile图数据重新排列为线性数据
    #PSP图像常用16x8 32x8等
    #部分字库也可以理解为tile图处理 比如14x14 16x16
    #DXT图像为4x4
    width=ntx*tile_w
    height=nty*tile_h
    tilelst=[]
    tile_len=tile_w*tile_h
    for k in range(0,width*height,tile_len):
        tile = data[k:k+tile_len]
        tilelst.append(tile)
    nPixel_data=[]
    for a in range(nty):
        for b in range(tile_h):
            for c in range(ntx):
                for d in range(tile_w):
                    index = a*ntx+c
                    index_tile = b*tile_w+d
                    nPixel_data.append((tilelst[index][index_tile]))
    return nPixel_data
def getPaletteData(paldata,aRange,byte_len,transparency_settings,transparency_index):
    #读取RGBA8888/RGBA4444调色板的颜色值,aRange为alpha范围，0-0xFF，若为256级灰度，则为0xff
    #部分PS2游戏是128级灰度，比如恐怖惊魂夜
    #byte_len == 4 RGBA8888调色板
    #byte_len == 2 RGBA4444调色板
    #byte_len == 3 RGB调色板,无alpha
    #transparency_settings 透明度设定，如果调色板中某一颜色需要设定为透明底色，则为True
    #transparency_index 强制设定调色板中的设定为透明色的颜色索引值，比如第一色为透明，则为0
    #(在transparency_settings为True时本项有效)
    Palette_size=len(paldata)
    rangesize=aRange
    RGBlst=[]

    if byte_len == 4:#PALETTE_FORMAT_RGBA8888
        for i in range(0,Palette_size,4):
            (r,g,b,a)=ord(paldata[i]),\
                       ord(paldata[i+1]),\
                       ord(paldata[i+2]),\
                       ord(paldata[i+3])
            if ord(paldata[-1]) <= rangesize:
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            RGBlst.append((r,g,b,a))
    if byte_len == 2:#PALETTE_FORMAT_RGBA4444
        for i in range(0,Palette_size,2):
            bt=paldata[i:i+2]
            (r,g,b,a)=((ord(bt[0]) & 0x0f) << 4,\
                       (ord(bt[0]) & 0xf0),\
                       (ord(bt[1]) & 0x0f) << 4,\
                       (ord(bt[1]) & 0xf0))
            a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            RGBlst.append((r,g,b,a))
    if byte_len == 3:#PALETTE_FORMAT_RGB888,no alpha PSP Black Rock Shooter Font
        for i in range(0,Palette_size,3):
            (r , g , b , a)=(ord(paldata[i]) , ord(paldata[i+1]) ,\
                ord(paldata[i+2]) , 255)
            RGBlst.append((r , g , b , a))
    if transparency_settings == True:
        (r0,g0,b0,a0)=RGBlst[transparency_index]
        RGBlst[transparency_index]=(r0,g0,b0,0)
    return RGBlst
def findIndexColor(pixelColor, RGBlst, color_num):
    if pixelColor in RGBlst:
        return RGBlst.index(pixelColor)
    else:
        dlist=[]
        (fR,fG,fB,fA)=pixelColor
        for pColor in RGBlst:
            (tR,tG,tB,tA)=pColor
            rMean = (fR * fA + tR * tA)/510
            rDiff = (fR * fA - tR * tA)/255
            gDiff = (fG * fA - tG * tA)/255
            bDiff = (fB * fA - tB * tA)/255
            aDiff = fA - tA
            dist  = (510 + rMean) * (rDiff**2) + \
                    1020 * (gDiff ** 2) + \
                    (765 - rMean) * (bDiff**2) + \
                    1530 * (aDiff**2)
            dlist.append(dist)
            if dist  ==  0:
                break
        minDist = min(dlist)
        return dlist.index(minDist)
def paint2BPP(width,height,tile_w,tile_h,data_buff,paletteData,Endian_type):
    assert width%tile_w == 0, 'set Width/tile Error'
    #width 图片宽度
    #height 图片高度
    #tile_w tile宽度
    #tile_h tile高度
    #data_buff 图像数据区
    #paletteData 调色板列表(list)
    #Endian_type  BIG或者LITTLE
    #print(width,height,tile_w,tile_h,len(data_buff))
    if Endian_type == 'BIG':
        IsBigEndian = True
    else:
        IsBigEndian = False
    TileSize = (tile_w,tile_h)
    nNecessBytes = width * height/4
    if len(data_buff)<nNecessBytes:
        data_buff += ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /tile_w #amount of tiles horizontally
    nty = height /tile_h #amount of tile in vertically
    pixNum = 0
    newdata=''
    nPixels = width *height
    for i in range(nNecessBytes):#Decompress nBPP pixels from DATA
        bt=ord(data_buff[i])
        for b in range(4):
            if pixNum > nPixels:
                break
            if IsBigEndian:
                j = ((bt & (0x03 << (b * 2))) >> (b * 2))
                newdata+= chr(j)
                pixNum+= 1
            else:
                j = ((bt & (0xC0 >> (b * 2))) >> ((3 - b) * 2))
                newdata+= chr(j)
                pixNum+= 1
    nPixel_data = tile2linear(newdata,ntx,nty,tile_h,tile_w)
    datalist = []
    for char in nPixel_data:
        datalist.append(paletteData[char])
    return datalist
def forceDec4bppto8bpp(image_data):
    nNecessBytes = len(image_data) * 2
    data_buff = image_data
    if len(data_buff) < nNecessBytes:
        data_buff += ('\x00' * (nNecessBytes - len(data_buff)))
    new_data = ""
    pixNum = 0
    for i in range(nNecessBytes):
        bt=ord(data_buff[i])
        for b in range(2):
            if pixNum > nNecessBytes:
                break
            j = ((bt & (0x0f << (b * 4))) >> (b * 4))
            new_data += chr(j)
            pixNum += 1
    return new_data[:nNecessBytes]

def paint_4BPP(width,height,tile_w,tile_h,data_buff,paletteData,Endian_type,platform_type):
    if Endian_type == 'BIG':
        IsBigEndian = True
    else:
        IsBigEndian = False
    nNecessBytes = width * height/2
    TileSize = (tile_w,tile_h)
    if len(data_buff)<nNecessBytes:
        data_buff+= ('\x00' * (nNecessBytes - len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=[]

    nPixels = width *height
    for i in range(nNecessBytes):
        bt=ord(data_buff[i])
        for b in range(2):
            if pixNum > nPixels:
                break
            if IsBigEndian:
                j = ((bt & (0x0f << (b * 4))) >> (b * 4))
                newdata.append(j)
            else:
                j = ((bt & (0xf0 >> (b * 4))) >> ((1 - b) * 4))
                newdata.append(j)
                pixNum+= 1
    if platform_type.upper() == '3DS':
        for i in range(0,len(newdata),64):
            newdata[i:i+64] = remap_3ds_tile(newdata[i:i+64])
    nPixel_data = tile2linear(newdata,ntx,nty,tile_h,tile_w)
    datalist=[]
    for char in nPixel_data:
        datalist.append(paletteData[char])
    return datalist
def paint8BPP(width,height,tile_w,tile_h,data_buff,paletteData,paletteType,pal_tx , pal_ty,platform_type):
    #width 图片宽度
    #height 图片高度
    #tile_w tile宽度
    #tile_h tile高度
    #data_buff 图像数据区
    #paletteData 调色板列表(list)
    #paletteType  调色板类型，linear或者tile
    #pal_tx 调色板tile宽
    #pal_ty 调色板tile高
    assert width%tile_w == 0, 'set Width/tile Error'
    if paletteType.lower() == 'tile':
        paletteData = tile_pal(paletteData,pal_tx,pal_ty)
    #print(width,height,tile_w,tile_h,len(data_buff))
    TileSize=(tile_w,tile_h)
    nNecessBytes = width * height
    if len(data_buff)<nNecessBytes:
        data_buff+= ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=''
    nPixels = width * height
    newdata += data_buff[:nPixels]
    n_list = []
    for c in newdata:
        n_list.append(ord(c))
    if platform_type.upper() == '3DS':
        for i in range(0,len(n_list),64):
            n_list[i:i+64] = remap_3ds_tile(n_list[i:i+64])
    nPixel_data = tile2linear(n_list,ntx,nty,tile_h,tile_w)
    datalist = []
    for char in nPixel_data:
        datalist.append(paletteData[char])
    return datalist
def paintRGB5650(width,height,tile_w,tile_h,data_buff,image_type,platform_type):#uncomplete
    assert width%tile_w == 0, 'set Width/tile Error'
    print(width,height,tile_w,tile_h,len(data_buff))
    TileSize = (tile_w,tile_h)
    nNecessBytes = width * height*2
    if len(data_buff)<nNecessBytes:
        data_buff += ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata = []
    nPixels = width *height
    for i in range(0,nNecessBytes,2):#Decompress nBPP pixels from DATA
        bt=struct.unpack('H',data_buff[i:i+2])[0]
        if pixNum > nPixels:
            break
        (b,g,r,a)=(((bt & 0x1f) * 255 + 15)/31 , (((bt & 0x7e0) >> 5) * 255 + 31)/63,\
                   (((bt & 0xf800) >> 11) * 255 + 15)/31 , 0xff)
        pixNum+= 1
        if image_type == 'BGR':
            newdata.append((b,g,r,a))
        elif image_type == 'RGB':
            newdata.append((r,g,b,a))
        elif image_type == 'BRG':
            newdata.append((b,r,g,a))
        elif image_type == 'GBR':
            newdata.append((g,b,r,a))
        elif image_type == 'GRB':
            newdata.append((g,r,b,a))
        elif image_type == 'RBG':
            newdata.append((r,b,g,a))
        else:
            newdata.append((r,g,b,a))
    if platform_type.upper() == '3DS':
        for i in range(0,len(newdata),64):
            newdata[i:i+64] = remap_3ds_tile(newdata[i:i+64])
    nPixel_data = tile2linear(newdata , ntx , nty , tile_h , tile_w)
    return nPixel_data
def paintRGBA4444(width,height,tile_w,tile_h,data_buff,image_type,platform_type):#uncomplete
    assert width%tile_w == 0, 'set Width/tile Error'
    print(width,height,tile_w,tile_h,len(data_buff),image_type)
    TileSize = (tile_w,tile_h)
    nNecessBytes = width * height*2
    if len(data_buff) < nNecessBytes:
        data_buff += ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=[]
    nPixels = width *height
    for i in range(0,nNecessBytes,2):#Decompress nBPP pixels from DATA
        bt=struct.unpack('H',data_buff[i:i+2])[0]
        if pixNum > nPixels:
            break
        (b,g,r,a)=(((bt & 0xf0) >> 4) * 255 + 7)/15,(((bt & 0xf00) >> 8) * 255 + 7)/15,\
                   (((bt & 0xf000) >> 12) * 255 + 7)/15,(((bt & 0xf) * 255 + 7)/15)
        if image_type == 'ABGR':
            newdata.append((a,b,g,r))
        elif image_type == 'RGBA':
            newdata.append((r,g,b,a))
        elif image_type == 'BGRA':
            newdata.append((b,r,g,a))
        elif image_type == 'ARGB':
            newdata.append((a,r,g,b))
        else:
            newdata.append((r,g,b,a))
        pixNum+= 1
    if platform_type.upper() == '3DS':
        for i in range(0,len(newdata),64):
            newdata[i:i+64] = remap_3ds_tile(newdata[i:i+64])
    nPixel_data = tile2linear(newdata,ntx,nty,tile_h,tile_w)
    return nPixel_data
def paintRGBA5551(width,height,tile_w,tile_h,data_buff,image_type):#uncomplete
    assert width%tile_w == 0, 'set Width/tile Error'
    print(width,height,tile_w,tile_h,len(data_buff))
    TileSize=(tile_w,tile_h)
    nNecessBytes = width * height*2
    if len(data_buff)<nNecessBytes:
        data_buff+= ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=[]
    nPixels = width *height
    for i in range(0,nNecessBytes,2):#Decompress nBPP pixels from DATA
        bt=struct.unpack('H',data_buff[i:i+2])[0]
        if pixNum > nPixels:
            break
        (b,g,r,a)=(((bt&0x1f)*255+15)/31,(((bt&0x3e0)>>5)*255+15)/31,\
                   (((bt&0x7c00)>>10)*255+15)/31,(((bt&0xf)>>15)*0xff))

        if image_type  ==  'ABGR':
            newdata.append((a,b,g,r))
        elif image_type == 'RGBA':
            newdata.append((r,g,b,a))
        elif image_type == 'BGRA':
            newdata.append((b,r,g,a))
        elif image_type == 'ARGB':
            newdata.append((a,r,g,b))
        else:
            newdata.append((r,g,b,a))
        pixNum+= 1

    nPixel_data=tile2linear(newdata,ntx,nty,tile_h,tile_w)
    return nPixel_data
def paintRGBA8880(width,height,tile_w,tile_h,data_buff,image_type,platform_type):#uncomplete
    assert width%tile_w == 0, 'set Width/tile Error'
    print(width,height,tile_w,tile_h,len(data_buff),image_type)
    TileSize=(tile_w,tile_h)
    nNecessBytes = width * height*3
    if len(data_buff)<nNecessBytes:
        data_buff+= ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=[]
    nPixels = width * height
    for i in range(0,nNecessBytes,3):#Decompress nBPP pixels from DATA
        bt = struct.unpack('3B',data_buff[i:i+3])
        if pixNum > nPixels:
            break
        (r,g,b,a)=(bt[0] , bt[1] , bt[2] , 0xff)
        if image_type == 'ABGR':#little endian
            newdata.append((a,b,g,r))
        elif image_type == 'RGBA':
            newdata.append((r,g,b,a))
        elif image_type == 'BGRA':
            newdata.append((b,g,r,a))
        elif image_type == 'ARGB':
            newdata.append((a,r,g,b))
        elif image_type == 'GBRA':
            newdata.append((g,b,r,a))
        else:
            newdata.append((r,g,b,a))
        pixNum += 1
    if platform_type.upper() == '3DS':
        for i in range(0,len(newdata),64):
            newdata[i:i+64] = remap_3ds_tile(newdata[i:i+64])
    nPixel_data = tile2linear(newdata , ntx , nty , tile_h , tile_w)
    datalist = []
    return nPixel_data
def paintRGBA8888(width,height,tile_w,tile_h,data_buff,image_type,platform_type):#uncomplete
    assert width%tile_w == 0, 'set Width/tile Error'
    print(width,height,tile_w,tile_h,len(data_buff),image_type)
    TileSize=(tile_w,tile_h)
    nNecessBytes = width * height*4
    if len(data_buff)<nNecessBytes:
        data_buff+= ('\x00'*(nNecessBytes-len(data_buff)))
    ntx = width /TileSize[0] #amount of tiles horizontally
    nty = height /TileSize[1] #amount of tile in vertically
    pixNum = 0
    newdata=[]
    nPixels = width *height
    for i in range(0,nNecessBytes,4):#Decompress nBPP pixels from DATA
        bt = struct.unpack('4B',data_buff[i:i+4])
        if pixNum > nPixels:
            break
        (r,g,b,a)=(bt[0] , bt[1] , bt[2] , bt[3])
        if image_type == 'ABGR':#little endian
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((a,b,g,r))
        elif image_type == 'RGBA':
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((r,g,b,a))
        elif image_type == 'BGRA':
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((b,g,r,a))
        elif image_type == 'ARGB':
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((a,r,g,b))
        elif image_type == 'GBRA':
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((g,b,r,a))
        else:
            if platform_type == 'PS2':
                rangesize = 0x80
                a=int(float(0xff)*(float(a)/float(rangesize)))#设定alpha通道范围
            newdata.append((r,g,b,a))
        pixNum += 1
    if platform_type.upper() == '3DS':
        for i in range(0,len(newdata),64):
            newdata[i:i+64] = remap_3ds_tile(newdata[i:i+64])
    nPixel_data = tile2linear(newdata , ntx , nty , tile_h , tile_w)
    datalist = []
    return nPixel_data
def decodeDXT1(width,height,data,alpha_settings):
    #alpha_settings,DXT1只能表示两种透明度，一种是完全透明,一种是完全不透明,可为alpha_settings设为True(DXT1A)/False(DXT1)
    colorlist=[]
    for block in range(len(data)/8):
        (color0, color1) = struct.unpack("<HH", data[block*8:block*8+4])
        index_data=data[block*8+4:block*8+8]
        #color0,color1使用RGB565方式存储
        red0 = (color0>> 11) & 0x1f
        green0 = ( color0 >> 5 ) & 0x3f
        blue0 = ( color0 & 0x1f )
        red1 = (color1>> 11) & 0x1f
        green1 = ( color1 >> 5 ) & 0x3f
        blue1 = ( color1 & 0x1f )
        (r0,g0,b0)=((red0 << 3),(green0 << 2),(blue0 << 3))
        (r1,g1,b1)=((red1 << 3),(green1 << 2),(blue1 << 3))
        #dxt1 4x4像素为一个压缩单位,color0,color1为色盘,剩余4字节(32bits)为索引区域,每2bit代表一个像素颜色
        #此时2bit可以表示4种颜色变化
        #所以除了color0和color1还可以插值出2种颜色
        #color2=color0*2/3+color1*1/3
        #color3=color1*2/3+color0*1/3
        a0=0xff
        a1=0
        newdata=''
        #4字节代表4x4的tile区域，索引方式类似于2bpp图，先将4字节索引表还原16字节
        #也可以用index_data = index_data >> 2逐个取2bit
        for i in range(4):
            bt=ord(index_data[i])
            for b in range(4):
                j = ((bt & (0x03 << (b * 2))) >> (b * 2))
                newdata+= chr(j)
        for i in range(16):
                index=ord(newdata[i])
                index_c=index
                if index_c == 0:#如果索引为0，输出color0
                    (rA,gA,bA,aA)=(r0,g0,b0,a0)
                elif index_c == 1:#如果索引为1，输出color1
                    (rA,gA,bA,aA)=(r1,g1,b1,a0)
                elif index_c == 2:#如果索引为2，进行插值color2=color0*2/3+color1*1/3
                    if alpha_settings == False:
                        (rA,gA,bA,aA)=((r0*2+r1)/3,(g0*2+g1)/3,(b0*2+b1)/3,a0)
                    else:
                        if color0>color1:
                            (rA,gA,bA,aA)=((r0*2+r1)/3,(g0*2+g1)/3,(b0*2+b1)/3,a0)
                        else:
                            (rA,gA,bA,aA)=((r1+r0)/2,(g1+g0)/2,(b1+b0)/2,a0)
                elif index_c == 3:#如果索引为3，进行插值color1*2/3+color0*1/3
                    if alpha_settings == False:(rA,gA,bA,aA)=((r1*2+r0)/3,(g1*2+g0)/3,(b1*2+b0)/3,a0)
                    else:
                        if color0>color1:
                            (rA,gA,bA,aA)=((r1*2+r0)/3,(g1*2+g0)/3,(b1*2+b0)/3,a0)
                        else:
                            (rA,gA,bA,aA)=(0,0,0,a0)
                colorlist.append((rA,gA,bA,aA))
    ntx=width/4
    nty=height/4
    newlist=tile2linear(colorlist,ntx,nty,4,4)#将tile图转换为线性图
    return newlist
def decodeDXT3(width,height,data):
    colorlist=[]
    #DXT3为64bit的alpha索引+64bit DXT1颜色插值，每个4x4tile占16字节
    #############
    #-------------8字节alpha索引，每像素的alpha占4bit------------------
    #每个像素可以有16种alpha值
    # 0   1   2   3
    # 4   5   6   7
    # 8   9   10  11
    #12   13  14  15
    #-------------4字节颜色值，color0和color1--------------------------
    #
    #-------------4字节插值判断,每个像素占2bit,共4种插值结果
    #0=color0,1=color1,2=color0*2/3+color1*1/3,3=color1*2/3+color0*1/3
    #共16字节 128bit
    for block in range(len(data)/16):
        b0 = data[block*16:block*16+16]
        color_index = struct.unpack("<8B", b0[:8])#alpha描述索引
        color0, color1 = struct.unpack("<HH", b0[8:12])
        code = struct.unpack("<I", b0[12:])[0]
        #color0,color1使用RGB565方式存储
        r0 = ((color0 >> 11) & 0x1f) << 3
        g0 = ((color0 >> 5) & 0x3f) << 2
        b0 = (color0 & 0x1f) << 3
        r1 = ((color1 >> 11) & 0x1f) << 3
        g1 = ((color1 >> 5) & 0x3f) << 2
        b1 = (color1 & 0x1f) << 3
        for i in range(16):
            aCode=i/2
            fA=color_index[aCode]
            fA=fA>>4
            fA*=17
            index_c=(code>>2*i)&3
            if index_c == 0:
                (rA,gA,bA,aA)=(r0,g0,b0,fA)
            elif index_c == 1:
                (rA,gA,bA,aA)=(r1,g1,b1,fA)
            elif index_c == 2:
                (rA,gA,bA,aA)=((2*r0+r1)/3,(2*g0+g1)/3,(b0*2+b1)/3,fA)
            elif index_c == 3:
                (rA,gA,bA,aA)=((r1*2+r0)/3,(g1*2+g0)/3,(b1*2+b0)/3,fA)
            colorlist.append((rA,gA,bA,aA))
    ntx=width/4
    nty=height/4
    newlist=tile2linear(colorlist,ntx,nty,4,4)#将tile图转换为线性图
    return newlist
def decodeDXT5(width,height,data):
    #DXT5为64bit的alpha索引+64bit DXT1颜色插值，每个4x4tile占16字节
    #
    #-------------8字节alpha索引，每像素的alpha占4bit------------------
    #头2字节为alpha_0和alpha_1，后6字节为alpha插值索引。每个像素占3bit
    #每个像素可以插值出6种或者8种
    #0=alpha0,1=alpha1,2-5插值,6=0x0完全透明,7=0xff完全不透明
    #6字节alpha插值区域
    # 0   1   2   3
    # 4   5   6   7
    # 8   9   10  11
    #12   13  14  15
    #3bit索引读取方法如下
    #比如索引区为'\xa0\x93\x24\x49\x92\x24'
    #2进制为 10100000,10010011,100100,1001001,10010010,100100
    #索引表为
    #000,100,110,001,
    #001,001,001,001,
    #001,001,001,001,
    #001,001,001,001,
    #即对应索引表为
    # 0  4   6   1
    # 1  1   1   1
    # 1  1   1   1
    # 1  1   1   1
    #-------------4字节颜色值，color0和color1--------------------------
    #-------------4字节颜色插值判断,每个像素占2bit,共4种插值结果
    colorlist=[]
    for block in range(len(data)/16):
        b0 = data[block*16:block*16+16]
        (a0,a1)=struct.unpack("<BB", b0[:2])
        bits = struct.unpack("<6B", b0[2:8])
        alphaCode1 = bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24)
        alphaCode2 = bits[0] | (bits[1] << 8)
        color0, color1 = struct.unpack("<HH", b0[8:12])
        code = struct.unpack("<I", b0[12:])[0]
        #color0,color1使用RGB565方式存储
        r0 = ((color0 >> 11) & 0x1f) << 3
        g0 = ((color0 >> 5) & 0x3f) << 2
        b0 = (color0 & 0x1f) << 3
        r1 = ((color1 >> 11) & 0x1f) << 3
        g1 = ((color1 >> 5) & 0x3f) << 2
        b1 = (color1 & 0x1f) << 3
        for i in range(16):
            alphaCodeIndex = 3*i
            if alphaCodeIndex <= 12:
                alphaCode = (alphaCode2 >> alphaCodeIndex) & 0x07
            elif alphaCodeIndex  ==  15:
                alphaCode = (alphaCode2 >> 15) | ((alphaCode1 << 1) & 0x06)
            else:
                alphaCode = (alphaCode1 >> (alphaCodeIndex - 16)) & 0x07
            if alphaCode  ==  0:
                fA=a0
            elif alphaCode  ==  1:
                fA=a1
            else:
                if a0 > a1:
                    fA = ((8-alphaCode)*a0+(alphaCode-1)*a1)/7
                else:
                    if alphaCode  ==  6:
                        fA = 0
                    elif alphaCode  ==  7:
                        fA = 255
                    else:
                        fA = ((6-alphaCode)*a0+(alphaCode-1)*a1)/5
            index_c=(code >> 2*i) & 3
            if index_c == 0:
                (rA,gA,bA,aA)=(r0,g0,b0,fA)
            elif index_c == 1:
                (rA,gA,bA,aA)=(r1,g1,b1,fA)
            elif index_c == 2:
                (rA,gA,bA,aA)=((2*r0+r1)/3,(2*g0+g1)/3,(b0*2+b1)/3,fA)
            elif index_c == 3:
                (rA,gA,bA,aA)=((r1*2+r0)/3,(g1*2+g0)/3,(b1*2+b0)/3,fA)
            colorlist.append((rA,gA,bA,aA))
    ntx=width/4
    nty=height/4
    newlist=tile2linear(colorlist,ntx,nty,4,4)#将tile图转换为线性图
    return newlist

def create2BPP(width,height,tile_w,tile_h,im,paletteData,Endian_type):
    if Endian_type == 'BIG':
        IsBigEndian=True
    else:
        IsBigEndian=False
    assert width  ==  im.size[0], 'PNG Width Error'
    assert height  ==  im.size[1], 'PNG Height Error'
    imdata=''
    ntx=width/tile_w
    nty=height/tile_h
    nPixel_data=[]
    tx,ty=0,0
    for a in range(nty):
        for b in range(ntx):
            for c in range(tile_h):
                for d in range(tile_w):
                    (tx,ty)=(d+tile_w*b,c+tile_h*a)
                    nPixel_data.append((im.getpixel((tx,ty))))
    indexlist=[]
    for pixelColor in nPixel_data:
        getIndex=findIndexColor(pixelColor, paletteData, 4)
        indexlist.append(getIndex)
    imdata=''
    for i in range(0,len(indexlist),4):
        if IsBigEndian:
            n=(indexlist[i],indexlist[i+1],indexlist[i+2],indexlist[i+3])
        else:
            n=(indexlist[i+3],indexlist[i+2],indexlist[i+2],indexlist[i])
        bt=0
        for b in range(4):
            bt+= (n[b]<<(b * 2))
        imdata+= chr(bt)
    return imdata
def create4BPP(width,height,tile_w,tile_h,im,paletteData,Endian_type):
    if Endian_type == 'BIG':
        IsBigEndian=True
    else:
        IsBigEndian=False
    assert width  ==  im.size[0], 'PNG Width Error'
    assert height  ==  im.size[1], 'PNG Height Error'
    imdata=''
    ntx=width/tile_w
    nty=height/tile_h
    nPixel_data=[]
    tx,ty=0,0
    for a in range(nty):
        for b in range(ntx):
            for c in range(tile_h):
                for d in range(tile_w):
                    (tx,ty)=(d+tile_w*b,c+tile_h*a)
                    nPixel_data.append((im.getpixel((tx,ty))))
    indexlist=[]
    for pixelColor in nPixel_data:
        getIndex=findIndexColor(pixelColor, paletteData, 16)
        indexlist.append(getIndex)
    imdata=''
    for i in range(0,len(indexlist),2):
        if IsBigEndian:n=(indexlist[i],indexlist[i+1])
        else:n=(indexlist[i+1],indexlist[i])
        bt=0
        for b in range(2):
            bt+= (n[b]<<(b * 4))
        imdata+= chr(bt)
    return imdata
def create8BPP(width,height,tile_w,tile_h,im,paletteData,paletteType,pal_tx,pal_ty):
    if paletteType.lower() == 'tile':
        paletteData=tile_pal(paletteData,pal_tx,pal_ty)
    assert width  ==  im.size[0], 'PNG Width Error'
    assert height  ==  im.size[1], 'PNG Height Error'
    imdata=''
    ntx=width/tile_w
    nty=height/tile_h
    nPixel_data=[]
    tx,ty=0,0
    for a in range(nty):
        for b in range(ntx):
            for c in range(tile_h):
                for d in range(tile_w):
                    (tx,ty)=(d+tile_w*b,c+tile_h*a)
                    nPixel_data.append((im.getpixel((tx,ty))))
    indexlist=[]
    for pixelColor in nPixel_data:
        getIndex=findIndexColor(pixelColor, paletteData, 256)
        indexlist.append(getIndex)
    imdata=''
    for i in range(len(indexlist)):
        bt=indexlist[i]
        imdata+= chr(bt)
    return imdata
def createRGBA8888(width,height,im,rgbaType):
    #set rgbaType first
    assert width  ==  im.size[0], 'PNG Width Error'
    assert height  ==  im.size[1], 'PNG Height Error'
    imdata=''
    nPixel_data=[]
    for y in range(height):
        for x in range(width):
            (r0,g0,b0,a0)=im.getpixel((x,y))
            if rgbaType == 'BGRA':
                fR,fG,fB,fA=(b0,g0,r0,a0)
            else:
                fR,fG,fB,fA=(r0,g0,b0,a0)
            nPixel_data.append((fR,fG,fB,fA))
    for n in nPixel_data:
        (cR,cG,cB,cA)=n
        #print((cR,cG,cB,cA))
        if cA == 0:
            (cR,cG,cB,cA)=(0,0,0,0)
        imdata+= (chr(cR)+chr(cG)+chr(cB)+chr(cA))
    return imdata