#include #include #include #include #include class BMP2Gcode { public: BMP2Gcode(); void traitement(char* nom_fichier); void fichier_conf(); private: unsigned int BMP_larg(); unsigned int BMP_haut(); unsigned int BMP_offset(); unsigned int BMP_profondeur(); int entete(); int donnees(); int sortie(); void BMP_larg(unsigned int nbr); void BMP_haut(unsigned int nbr); void BMP_offset(unsigned int nbr); void BMP_profondeur(unsigned int nbr); unsigned int conversion(unsigned int valeur, unsigned int min, unsigned int max); unsigned int BMP_largeur, BMP_hauteur, BMP_off, BMP_prof, BMP_taille; double conf_taille_laser, conf_puissance_min, conf_puissance_max, conf_vitesse, conf_taille_image; std::vector tab_donnees; std::string nom_fichier_bmp; }; BMP2Gcode::BMP2Gcode() :BMP_largeur(0), BMP_hauteur(0), BMP_off(0), BMP_prof(0), BMP_taille(0) {} void BMP2Gcode::traitement(char* nom_fichier) { nom_fichier_bmp = nom_fichier; entete(); donnees(); sortie(); } unsigned int BMP2Gcode::BMP_larg() { return BMP_largeur; } unsigned int BMP2Gcode::BMP_haut() { return BMP_hauteur; } unsigned int BMP2Gcode::BMP_offset() { return BMP_off; } unsigned int BMP2Gcode::BMP_profondeur() { return BMP_prof; } int BMP2Gcode::entete() { //ouverture du fichier std::ifstream fichier(nom_fichier_bmp, std::ifstream::binary); //test de l'ouverture du fichier if(!fichier) { std::cerr << "impossible d'ouvrir le fichier" << std::endl; return 1; } /*lecture de l'en tête de 54 octets composé comme suit : -2 octets [0-1] pour la signature -4 octets [2-5] pour la taille du fichier en octets -4 octets [5-8] de champ réservé -4 octets [9-12] pour l'offset -4 octets [13-17] pour la taille de l'en-tête de l'image (28 octets pour windows) -4 octets [18-21] pour la largeur de l'image -4 octets [22-25] pour la hauteur de l'image -2 octets [26-27] pour le nombre de plans (valeur toujours à 1) -2 octets [28-29] pour la profondeur de l'encodage (nbr de bit pour la couleur) -4 octets [30-33] pour la métode de compression (0 non compressé, 1 RLE 8bits/pixel, 2 RLE 4bits/pixel, 3 bitfields) -4 octets [34-37] pour la taille de l'image -4 octets [38-41] pour la résolution horizontale -4 octets [42-45] pour la résolution verticale -4 octets [46-49] pour la palette de couleur -4 octets [50-53] pour le nombre de couleurs importantes. */ char *entete = new char [54]; fichier.read(entete, 54); if(entete[0] == 'B') { if(entete[1] == 'M') { std::cout << "Bitmap windows" << std::endl; } } /*Pour récupérer les informations on va utiliser l'astuce suivante : pour la valeur commençant à entete[indice] on va commencer par prendre l'adresse : &entete[indice] puis on va caster ça dans le type qui correspond bien, int * si c'est sur 4 octets, short * si c'est sur 2 octets. (int *)&entete[indice] correspond donc à un pointeur de type int *, il suffit alors de prendre sa valeur en faisant : *(int *)entete[indice] */ BMP_larg(*(int*)&entete[18]); BMP_haut(*(int*)&entete[22]); BMP_offset(*(int*)&entete[10]); BMP_profondeur(*(short*)&entete[28]); delete[] entete; fichier.close(); return 0; } int BMP2Gcode::donnees() { //ouverture du fichier std::ifstream fichier(nom_fichier_bmp, std::ifstream::binary); //test de l'ouverture du fichier if(!fichier) { std::cerr << "impossible d'ouvrir le fichier" << std::endl; return 1; } if(BMP_off == 0) {entete();} int limite = BMP_larg()*BMP_haut() * BMP_profondeur()/8 + BMP_offset(); char *donnees = new char [ limite ]; fichier.read(donnees, limite); for(int i = BMP_offset() ; i < limite ; i += 3) { if(donnees[i] < 0) {tab_donnees.push_back(256 + (int)donnees[i]);} else {tab_donnees.push_back((int)donnees[i]);} } delete[] donnees; fichier.close(); return 0; } int BMP2Gcode::sortie() { std::string nom_fichier_gcode; nom_fichier_gcode = nom_fichier_bmp + ".gcode"; std::ofstream fichier_sortie; fichier_sortie.open (nom_fichier_gcode); /****************************CONDITIONS INITIALES****************************/ double taille_pixel = (double)(conf_taille_image)/(double)(BMP_largeur), position_Y = 0; int sens = 1, indice = 0, ligne = 1; //Le Gcode utilise comme unité de vitesse des mm/min conf_vitesse *= 60; //on arrondi la taille du pixel au dixième de mm taille_pixel = round(10.0*taille_pixel)/10.0; std::cout << "largeur = " << BMP_largeur << " pixel" << std::endl; std::cout << "taille pixel = " << taille_pixel << " mm" << std::endl; //On passe en mode relatif fichier_sortie << "G91" << std::endl; //on s'assure que le laser est éteint fichier_sortie << "M106 P1 S0" << std::endl; //on défini la vitesse fichier_sortie << "G1 F" << conf_vitesse << std::endl; while(ligne <= BMP_hauteur) { //pour graver une ligne on fera des aller-retour tant que : while(position_Y <= ligne * taille_pixel) { int nbr_pixels = 0; //traitement d'une ligne while(nbr_pixels < BMP_largeur) { unsigned int puissance = conversion(255 - tab_donnees[indice], conf_puissance_min, conf_puissance_max); //on détermine le nombre de pixels successifs pour lesquels la puissance du laser sera la même int nbr = 1; while( puissance == conversion(255 - tab_donnees[indice + nbr], conf_puissance_min, conf_puissance_max) && indice + nbr < BMP_largeur) {nbr ++;} //avant de fixer la puissance du laser on attends que les mouvements soient fini fichier_sortie << "M106 P1 S" << puissance << std::endl; //on se déplace selon le sens fichier_sortie << "G1 X" << sens * taille_pixel * nbr << std::endl; //pour chaque pixel parcourut on incrémente l'étape nbr_pixels += nbr; //et on se déplace dans le tableau selon le sens indice += sens * nbr; } //une fois que la ligne est finie, on décale d'une taille de laser sur l'axe Y fichier_sortie << "G1 Y" << conf_taille_laser << std::endl; //est ce qu'un M400 changerai les choses ?? position_Y += conf_taille_laser; //on change de sens sens *= -1; } //une fois qu'une ligne de pixel est gravée on incrémente le nombre de ligne ligne ++; indice += BMP_largeur; fichier_sortie << ";ligne numéro " << ligne << std::endl; } //il ne faut pas oublier d'éteindre le laser à la fini fichier_sortie << "M106 P1 S0" << std::endl; fichier_sortie.close(); return 0; } void BMP2Gcode::BMP_larg(unsigned int nbr) { BMP_largeur = nbr; } void BMP2Gcode::BMP_haut(unsigned int nbr) { BMP_hauteur = nbr; } void BMP2Gcode::BMP_offset(unsigned int nbr) { BMP_off = nbr; } void BMP2Gcode::BMP_profondeur(unsigned int nbr) { BMP_prof = nbr; } unsigned int BMP2Gcode::conversion(unsigned int valeur, unsigned int min, unsigned int max) { /*pour une valeur de 0 la puissance du laser doit être égale à min *pour une valeur de 255 la puissance du laser doit être égal à max *pour trouver la valeur entre les deux on utilise une fonction affine y = ax + b pour x = 0 <=> y = b = min pour x = 255 <=> y = 255*a+min = max <=> a = (max - min)/255 */ return valeur * (max - min)/255 + min; } void BMP2Gcode::fichier_conf() { //On regarde si le fichier de configuration existe déjà std::ifstream fichier_conf("laser.conf"); //s'il n'existe pas if(!fichier_conf) { //alors on le crée std::ofstream fichier_conf; fichier_conf.open("laser.conf"); fichier_conf << "taille_laser(mm) 0.2" << std::endl; fichier_conf << "puissance_min 0" << std::endl; fichier_conf << "puissance_max 255" << std::endl; fichier_conf << "vitesse(mm/s) 20" << std::endl; fichier_conf << "taille_image_x(mm) 150" << std::endl; std::cout << "*************************************************" <> clef >> valeur) { if(clef == "taille_laser(mm)") {conf_taille_laser = valeur;} if(clef == "puissance_min") {conf_puissance_min = valeur;} if(clef == "puissance_max") {conf_puissance_max = valeur;} if(clef == "vitesse(mm/s)") {conf_vitesse = valeur;} if(clef == "taille_image_x(mm)") {conf_taille_image = valeur;} } std::cout << "***CONFIGURATION***" << std::endl; std::cout << "taille_laser = " << conf_taille_laser << " mm" << std::endl; std::cout << "puissance_min = " << conf_puissance_min << " PWM 0-255" << std::endl; std::cout << "puissance_max = " << conf_puissance_max << " PWM 0-255" << std::endl; std::cout << "vitesse = " << conf_vitesse << " mm/s" << std::endl; std::cout << "taille_image = " << conf_taille_image << " mm" << std::endl; } fichier_conf.close(); } int main(int argc, char* argv[]) { if(argc >= 2) { std::string entree = argv[1]; BMP2Gcode image; image.fichier_conf(); image.traitement(argv[1]); } else {std::cout << "Veuillez préciser un nom de fichier BMP" << std::endl;} return 1; }