Ver código fonte

lots of stuff not working for dxf2svg

bscheibel 4 anos atrás
pai
commit
ed9744fee7
8 arquivos alterados com 14236 adições e 7 exclusões
  1. 8 0
      .idea/encodings.xml
  2. 3 0
      .idea/misc.xml
  3. 13912 0
      app/GV_12.DXF
  4. 9 0
      app/dxf2img.py
  5. 76 0
      app/dxf_to_png.py
  6. 4 5
      app/templates/upload_image.html
  7. 8 2
      app/views.py
  8. 216 0
      dxftoimg.py

+ 8 - 0
.idea/encodings.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/app/GV_12.DXF" charset="windows-1252" />
+    <file url="file://$PROJECT_DIR$/app/GV_12.DXF" charset="US-ASCII" />
+    <file url="file://$PROJECT_DIR$/app/Laeufer.DXF" charset="windows-1252" />
+  </component>
+</project>

+ 3 - 0
.idea/misc.xml

@@ -1,4 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
+  <component name="PyCharmProfessionalAdvertiser">
+    <option name="shown" value="true" />
+  </component>
 </project>

Diferenças do arquivo suprimidas por serem muito extensas
+ 13912 - 0
app/GV_12.DXF


+ 9 - 0
app/dxf2img.py

@@ -0,0 +1,9 @@
+""" from dxf2svg.pycore import extract_all, save_svg_from_dxf
+
+
+def convert(dxffilepath):
+    save_svg_from_dxf(dxffilepath, svgfilepath=None, frame_name=None, size=300)
+
+    extract_all(dxffilepath, size=300)
+
+convert("GV_12.DXF") """

+ 76 - 0
app/dxf_to_png.py

@@ -0,0 +1,76 @@
+import dxfgrabber
+import cv2
+import numpy as np
+import sys
+#https://gist.github.com/msjamali52/91a96176a1be3313af5d3309cbbf4b06
+"""
+def absdiff(num1, num2):
+    if num1 <= num2:
+        return num2 - num1
+    else:
+        return num1 - num2
+"""
+
+def getMinXY(shapes):
+    minX, minY = 99999, 99999
+    for shape in shapes:
+        if shape.dxftype == 'LINE':
+            minX = min(minX, shape.start[0], shape.end[0])
+            minY = min(minY, shape.start[1], shape.end[1])
+        elif shape.dxftype == 'ARC':
+            minX = min(minX, shape.center[0])
+            minY = min(minY, shape.center[1])
+
+    return minX, minY
+
+def getMaxXY(shapes):
+    maxX, maxY = -99999, -99999
+    for shape in shapes:
+        if shape.dxftype == 'LINE':
+            maxX = max(maxX, shape.start[0], shape.end[0])
+            maxY = max(maxY, shape.start[1], shape.end[1])
+        elif shape.dxftype == 'ARC':
+            maxX = max(maxX, shape.center[0])
+            maxY = max(maxY, shape.center[1])
+
+    return maxX, maxY
+
+#Translate x,y values as per fourth quadrant i.e positive x and negative y. Update y value to positive, to be used by opencv axes.
+# shift origin of image by 100 pixels for better clarity of output image
+def getXY(point):
+    x, y = point[0], point[1]
+    return int(x-minX+100), int(abs(y-maxY)+100)
+
+dxf = dxfgrabber.readfile("GV_12.DXF")
+shapes = dxf.entities.get_entities()
+minX, minY = getMinXY(shapes)
+maxX, maxY = getMaxXY(shapes)
+#baseX, baseY = absdiff(minX, 0), absdiff(minY, 0)
+#absMaxX, absMaxY = absdiff(maxX, 0), absdiff(maxY, 0)
+
+
+print(maxX, maxY)
+print(minX, minY)
+#print(absMaxX, absMaxY)
+#print(baseX, baseY)
+
+
+canvas = np.zeros((512,512,3), np.uint8)
+for shape in shapes:
+    if shape.dxftype == 'LINE':
+        x1, y1 = getXY(shape.start)
+        x2, y2 = getXY(shape.end)
+        canvas = cv2.line(canvas, (x1,y1), (x2,y2), (255, 0, 255), 1)
+    elif shape.dxftype == 'ARC':
+        centerX, centerY = getXY(shape.center)
+        if (shape.start_angle > 180) and (shape.end_angle < shape.start_angle):
+            canvas = cv2.ellipse(canvas, (centerX, centerY), (int(shape.radius), int(shape.radius)), 180, int(shape.start_angle) - 180, 180 + int(shape.end_angle), (0, 0, 255), 1)
+        else:
+            canvas = cv2.ellipse(canvas, (centerX, centerY), (int(shape.radius), int(shape.radius)), 0, int(360 - shape.start_angle), int(360 - shape.end_angle), (0, 0, 255), 1)
+    cv2.imshow('test', canvas)
+    cv2.waitKey(50)
+
+# To save canvas use cv2.imwrite()
+#cv2.imwrite('res.png', canvas)
+cv2.waitKey(0)
+cv2.destroyAllWindows()

+ 4 - 5
app/templates/upload_image.html

@@ -1,6 +1,6 @@
-{% extends "templates/public_template.html" %}
+{% extends "public/public_template.html" %}
 
-{% block title %}Upload{% endblock %}
+{% block title %}Dimensions{% endblock %}
 
 {% block main %}
 
@@ -8,16 +8,15 @@
   <div class="row">
     <div class="col">
 
-      <h1>Upload an image</h1>
+      <h1>Upload a DXF file</h1>
       <hr>
 
       <form action="/upload-image" method="POST" enctype="multipart/form-data">
 
         <div class="form-group">
-          <label>Select image</label>
           <div class="custom-file">
             <input type="file" class="custom-file-input" name="image" id="image">
-            <label class="custom-file-label" for="image">Select image...</label>
+            <label class="custom-file-label" for="image">Select file...</label>
           </div>
         </div>
 

+ 8 - 2
app/views.py

@@ -5,7 +5,8 @@ from flask import request, redirect
 
 @app.route("/")
 def index():
-	return render_template("index.html")
+    return render_template("index.html")
+
 
 @app.route("/upload-image", methods=["GET", "POST"])
 def upload_image():
@@ -20,5 +21,10 @@ def upload_image():
 
             return redirect(request.url)
 
-
     return render_template("upload_image.html")
+
+
+@app.route('/show/<filename>')
+def uploaded_file(filename):
+    filename = 'http://127.0.0.1:5000/uploads/' + filename
+    return render_template('template.html', filename=filename)

+ 216 - 0
dxftoimg.py

@@ -0,0 +1,216 @@
+import StringIO, base64, logging, operator
+
+import dxfgrabber
+import Image, ImageDraw, ImageFont #PIL
+
+from homcoord import *
+
+def rint(x):return int(round(x))
+
+class BBox:
+    """bounding box"""
+    def __init__(self,pt1=None,pt2=None):
+        self._corner1=None
+        self._corner2=None
+        if pt1: self+=pt1
+        if pt2: self+=pt2
+
+    def __iadd__(self,pt):
+        if isinstance(pt,BBox):
+            self+=pt._corner1
+            self+=pt._corner2
+        else:
+            if not self._corner1:
+                self._corner1=pt
+            else:
+                self._corner1=Pt(map(min,zip(self._corner1.xy,pt.xy)))
+            if not self._corner2:
+                self._corner2=pt
+            else:
+                self._corner2=Pt(map(max,zip(self._corner2.xy,pt.xy)))
+        return self
+
+    def __repr__(self):
+        return "BBox(%s,%s)"%(self._corner1,self._corner2)
+
+    def __call__(self):
+        """:return: list of flatten corners"""
+        l=list(self._corner1.xy)
+        l.extend(list(self._corner2.xy))
+        return l
+
+    def size(self):
+        """:return: Pt with xy sizes"""
+        return self._corner2-self._corner1
+
+    def center(self):
+        """:return: Pt center"""
+        res=self._corner2+self._corner1
+        return res/2
+
+    def trans(self,trans):
+        """
+        :param trans: Xform
+        :return: BBox = self transformed by trans
+        """
+        return BBox(trans(self._corner1),trans(self._corner2))
+
+def cbox(c,r):
+    """ bounding box of a circle
+    :param c: Pt center
+    :param r: float radius
+    :return: BBox
+    """
+    rr=Pt(r,r)
+    return BBox(c+rr,c-rr)
+
+def Trans(scale=1, offset=[0,0], rotation=0):
+    res=Xform([[scale,0,offset[0]],[0,scale,offset[1]],[0,0,1]])
+    if rotation:
+        res=Xrotate(rotation*pi/180.)*res
+    return res
+
+class DXF:
+    def __init__(self, file, layers=None, ignore=[]):
+        """reads a .dxf file
+        :param file: string path to .dxf file to read
+        :param layers: list or dictionary of layers to handle. Empty = all layers
+        :param ignore: list of strings of entity types to ignore
+        """
+        self.dxf=dxfgrabber.readfile(file)
+        self.layers=layers
+        self.ignore=ignore
+
+    def entities(self,ent=None):
+        """iterator over dxf or block entities"""
+        if not ent:
+            ent=self.dxf.entities
+        for e in ent:
+            if self.layers and e.layer not in self.layers:
+                continue
+            elif e.dxftype in self.ignore:
+                continue
+            else:
+                yield e
+
+    def bbox(self):
+        """:return: :class:BBox dwg enclosing bounding box"""
+        box=BBox()
+        for e in self.entities():
+            if e.dxftype=='LINE':
+                box+=Pt(e.start[:2])
+                box+=Pt(e.end[:2])
+            elif e.dxftype == 'CIRCLE':
+                box+=cbox(Pt(e.center[:2]),e.radius)
+            elif e.dxftype == 'ARC':
+                c=Pt(e.center[:2])
+                a=e.endangle-e.startangle
+                if a>0:
+                    start=e.startangle
+                else: #arc goes clockwise (step will be negative)
+                    start=e.endangle
+                n=rint(abs(a)/10.) # number of points each 10° approximately
+                n=max(n,1)
+                step=a/n #angle between 2 points, might be negative
+                for i in range(n+1):
+                    box+=c.radial(e.radius,radians(start+i*step))
+            elif e.dxftype=='POLYLINE':
+                for v in e.vertices:
+                    box+=Pt(v.location[:2])
+            elif e.dxftype=='BLOCK':
+                pass #TODO ...
+            elif e.dxftype in ['TEXT','INSERT']:
+                box+=Pt(e.insert[:2])
+            else:
+                logging.warning('Unknown entity %s'%e)
+        return box
+
+    def _draw(self,draw,entities,trans,pen="black"):
+        for e in entities:
+            if e.dxftype=='LINE':
+                b=list(trans(Pt(e.start[:2])).xy)
+                b.extend(list(trans(Pt(e.end[:2])).xy))
+                draw.line(b,fill=pen)
+            elif e.dxftype=='CIRCLE':
+                b=cbox(Pt(e.center[:2]),e.radius)
+                b=b.trans(trans)
+                draw.ellipse(b(),outline=pen)
+            elif e.dxftype=='ARC':
+                c=Pt(e.center[:2])
+                b=cbox(c,e.radius)
+                b=b.trans(trans)
+                b=map(rint,b())
+                startangle=degrees(trans.angle(radians(e.startangle)))
+                endangle=degrees(trans.angle(radians(e.endangle)))
+                startangle,endangle=endangle,startangle #swap start/end because of Y symmetry
+                draw.arc(b,int(startangle),int(endangle),fill=pen)
+            elif e.dxftype=='POLYLINE':
+                b=[]
+                for v in e.vertices:
+                    b.extend(list(trans(Pt(v.location[:2])).xy))
+                draw.line(b,fill=pen)
+            elif e.dxftype=='TEXT':
+                h=e.height*trans.mag()
+                pt=Pt(e.insert[:2])+Pt(0,e.height) #ACAD places texts by top left point...
+                font=None
+                try:
+                    font = ImageFont.truetype("c:/windows/fonts/Courier New.ttf", rint(h))
+                except:
+                    pass
+                if not font:
+                    h=h*1.4 #magic factor ...
+                    fh=[8,10,12,14,16,18,20,22,24,26,28,30,36,40,48,60]
+                    i,h=min(enumerate(fh), key=lambda x: abs(x[1]-h)) #http://stackoverflow.com/questions/9706041/finding-index-of-an-item-closest-to-the-value-in-a-list-thats-not-entirely-sort
+                    import os
+                    path=os.path.realpath(__file__)
+                    path=os.path.dirname(path)
+                    font = ImageFont.load(path+'\\base_pil\\72\\Courier New_%s_72.pil'%h)
+                draw.text(trans(pt).xy,e.text,font=font,fill=pen)
+            elif e.dxftype=='INSERT':
+                t2=Trans(1,e.insert,e.rotation).compose(trans)
+
+                self._draw(draw,self.entities(self.dxf.blocks[e.name]._entities),t2,pen)
+            elif e.dxftype=='BLOCK':
+                pass # block definition is automatically stored in dxf.blocks dictionary
+            else:
+                logging.warning('Unknown entity %s'%e)
+
+    def img(self,size=[256,256],back="white",pen="black",border=5,antialias=1):
+        """:result: :class:`PIL:Image` rasterized image"""
+        box=self.bbox()
+        from Goulib.math2 import product
+        if not product(box.size().xy): # either x or y ==0
+            return None
+
+        s=map(operator.div,[float(x-border)*antialias if x else 1E9 for x in size ],box.size().xy)
+        trans=Trans(scale=min(s))
+        size=trans(box.size())+Pt(2*antialias*border,2*antialias*border) #add borders as an offset
+        offset=size/2-trans(box.center()) #offset in pixel coordinates
+        trans=trans*Trans(offset=offset.xy)
+        trans=trans*Xscale(1,-1) #invert y axis
+        trans=trans*Xlate(0,size.y) #origin is lower left corner
+
+        img = Image.new("RGB", map(rint,size.xy), back)
+        self._draw(ImageDraw.Draw(img), self.entities(), trans, pen)
+        if antialias>1:
+            size=size/antialias
+            img=img.resize(map(rint,size.xy), Image.ANTIALIAS)
+        return img
+
+def img2base64(img,fmt='PNG'):
+    """
+    :param img: :class:`PIL:Image`
+    :result: string base64 encoded image content in specified format
+    :see: http://stackoverflow.com/questions/14348442/django-how-do-i-display-a-pil-image-object-in-a-template
+    """
+    output = StringIO.StringIO()
+    img.save(output, fmt)
+    output.seek(0)
+    output_s = output.read()
+    return base64.b64encode(output_s)
+
+if __name__ == '__main__':
+    dxf=DXF("GV_12.DXF")
+    img=dxf.img(size=[1280,None],border=50)
+    print(img2base64(img))
+    img.save('..\\tests\\out.png')