123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- # Created: 07.03.2016
- # Copyright (c) 2016-2018, Manfred Moitzi
- # License: MIT License
- from typing import Iterable, Tuple, Sequence, List, TYPE_CHECKING, cast
- from ezdxf.dxfentity import DXFEntity
- from ezdxf.lldxf.attributes import DXFAttr, DXFAttributes, DefSubclass, XType
- from ezdxf.lldxf.types import DXFVertex
- from ezdxf.lldxf.tags import Tags
- from ezdxf.lldxf.extendedtags import ExtendedTags
- from ezdxf.math import Vector
- from .graphics import none_subclass, entity_subclass, ModernGraphicEntity
- if TYPE_CHECKING:
- from ezdxf.eztypes import Vertex
- _IMAGE_CLS = """0
- CLASS
- 1
- IMAGE
- 2
- AcDbRasterImage
- 3
- ISM
- 90
- 2175
- 91
- 0
- 280
- 0
- 281
- 1
- """
- _IMAGE_TPL = """0
- IMAGE
- 5
- 0
- 330
- 0
- 100
- AcDbEntity
- 8
- 0
- 100
- AcDbRasterImage
- 90
- 0
- 10
- 0.0
- 20
- 0.0
- 30
- 0.0
- 11
- 0.0
- 21
- 0.0
- 31
- 0.0
- 12
- 0.0
- 22
- 0.0
- 32
- 0.0
- 13
- 640
- 23
- 320
- 340
- 0
- 70
- 3
- 280
- 0
- 281
- 50
- 282
- 50
- 283
- 0
- 360
- 0
- 71
- 1
- 91
- 2
- """
- image_subclass = DefSubclass('AcDbRasterImage', {
- 'insert': DXFAttr(10, xtype=XType.point3d),
- 'u_pixel': DXFAttr(11, xtype=XType.point3d), # U-vector of a single pixel (points along the visual bottom of the image, starting at the insertion point)
- 'v_pixel': DXFAttr(12, xtype=XType.point3d), # V2-vector of a single pixel (points along the visual left side of the image, starting at the insertion point)
- 'image_size': DXFAttr(13, xtype=XType.point2d), # Image size in pixels
- 'image_def': DXFAttr(340), # Hard reference to image def object
- 'flags': DXFAttr(70, default=3), # Image display properties:
- # 1 = Show image
- # 2 = Show image when not aligned with screen
- # 4 = Use clipping boundary
- # 8 = Transparency is on
- 'clipping': DXFAttr(280, default=0), # Clipping state: 0 = Off; 1 = On
- 'brightness': DXFAttr(281, default=50), # Brightness value (0-100; default = 50)
- 'contrast': DXFAttr(282, default=50), # Contrast value (0-100; default = 50)
- 'fade': DXFAttr(283, default=0), # Fade value (0-100; default = 0)
- 'image_def_reactor': DXFAttr(360), # Hard reference to image def reactor object, not required by AutoCAD
- 'clipping_boundary_type': DXFAttr(71, default=1), # Clipping boundary type. 1 = Rectangular; 2 = Polygonal
- 'count_boundary_points': DXFAttr(91), # Number of clip boundary vertices that follow
- 'clip_mode': DXFAttr(290, dxfversion='AC1024'), # 0 = outside, 1 = inside mode
- # boundary path coordinates are pixel coordinates NOT drawing units
- })
- class Image(ModernGraphicEntity):
- __slots__ = ()
- TEMPLATE = ExtendedTags.from_text(_IMAGE_TPL)
- CLASS = ExtendedTags.from_text(_IMAGE_CLS)
- DXFATTRIBS = DXFAttributes(none_subclass, entity_subclass, image_subclass)
- # flags for IMAGE
- SHOW_IMAGE = 1
- SHOW_IMAGE_WHEN_NOT_ALIGNED = 2
- USE_CLIPPING_BOUNDARY = 4
- USE_TRANSPARENCY = 8
- def post_new_hook(self) -> None:
- self.reset_boundary_path()
- def set_boundary_path(self, vertices: Iterable[Tuple[float, float]]) -> None:
- vertices = list(vertices)
- if len(vertices) > 2 and vertices[-1] != vertices[0]:
- vertices.append(vertices[0]) # close path, else AutoCAD crashes
- self._set_path_tags(vertices)
- self.set_flag_state(self.USE_CLIPPING_BOUNDARY, state=True)
- self.dxf.clipping = 1
- self.dxf.clipping_boundary_type = 1 if len(vertices) < 3 else 2
- def _set_path_tags(self, vertices: Sequence[Tuple[float, float]]):
- boundary = [DXFVertex(14, value) for value in vertices]
- subclasstags = Tags(tag for tag in self.tags.subclasses[2] if tag.code != 14)
- subclasstags.extend(boundary)
- self.tags.subclasses[2] = subclasstags
- self.dxf.count_boundary_points = len(vertices)
- def reset_boundary_path(self) -> None:
- lower_left_corner = (-.5, -.5)
- upper_right_corner = Vector(self.dxf.image_size) + lower_left_corner
- self._set_path_tags([lower_left_corner, upper_right_corner[:2]])
- self.set_flag_state(Image.USE_CLIPPING_BOUNDARY, state=False)
- self.dxf.clipping = 0
- self.dxf.clipping_boundary_type = 1
- def get_boundary_path(self) -> List['Vertex']:
- image_subclass = self.tags.subclasses[2]
- return [tag.value for tag in image_subclass if tag.code == 14]
- def get_image_def(self) -> 'ImageDef':
- return cast('ImageDef', self.dxffactory.wrap_handle(self.dxf.image_def))
- def destroy(self) -> None:
- super(Image, self).destroy()
- # remove rectors
- image_def = self.get_image_def()
- reactor_handle = self.get_dxf_attrib('image_def_reactor', None)
- if reactor_handle is None:
- return
- image_def.remove_reactor_handle(reactor_handle)
- if self.drawing is not None:
- reactor = self.dxffactory.wrap_handle(reactor_handle)
- self.drawing.objects.delete_entity(reactor)
- _IMAGE_DEF_CLS = """0
- CLASS
- 1
- IMAGEDEF
- 2
- AcDbRasterImageDef
- 3
- ISM
- 90
- 0
- 91
- 0
- 280
- 0
- 281
- 0
- """
- _IMAGE_DEF_TPL = """0
- IMAGEDEF
- 5
- 0
- 330
- 0
- 102
- {ACAD_REACTORS
- 102
- }
- 100
- AcDbRasterImageDef
- 90
- 0
- 1
- path/filename.jpg
- 10
- 640
- 20
- 480
- 11
- 0.01
- 21
- 0.01
- 280
- 1
- 281
- 0
- """
- image_def_subclass = DefSubclass('AcDbRasterImageDef', {
- 'class_version': DXFAttr(90), # class version
- 'filename': DXFAttr(1), # File name of image
- 'image_size': DXFAttr(10, xtype=XType.point2d), # image size in pixels
- 'pixel_size': DXFAttr(11, xtype=XType.point2d), # Default size of one pixel in AutoCAD units
- 'loaded': DXFAttr(280, default=1),
- 'resolution_units': DXFAttr(281, default=0), # Resolution units. 0 = No units; 2 = Centimeters; 5 = Inch
- })
- # IMAGEDEF - requires entry in objects table ACAD_IMAGE_DICT, ACAD_IMAGE_DICT exists not by default
- class ImageDef(DXFEntity):
- TEMPLATE = ExtendedTags.from_text(_IMAGE_DEF_TPL)
- CLASS = ExtendedTags.from_text(_IMAGE_DEF_CLS)
- DXFATTRIBS = DXFAttributes(none_subclass, image_def_subclass)
- _IMAGE_DEF_REACTOR_CLS = """0
- CLASS
- 1
- IMAGEDEF_REACTOR
- 2
- AcDbRasterImageDefReactor
- 3
- ISM
- 90
- 1
- 91
- 0
- 280
- 0
- 281
- 0
- """
- _IMAGE_DEF_REACTOR_TPL = """0
- IMAGEDEF_REACTOR
- 5
- 0
- 330
- 0
- 100
- AcDbRasterImageDefReactor
- 90
- 2
- 330
- 0
- """
- # IMAGEDEF_REACTOR is not required by AutoCAD
- # owner -> IMAGE
- class ImageDefReactor(DXFEntity):
- TEMPLATE = ExtendedTags.from_text(_IMAGE_DEF_REACTOR_TPL)
- CLASS = ExtendedTags.from_text(_IMAGE_DEF_REACTOR_CLS)
- DXFATTRIBS = DXFAttributes(none_subclass, DefSubclass('AcDbRasterImageDef', {
- 'image': DXFAttr(330), # handle to image
- }))
- _RASTER_VARIABLES_CLS = """0
- CLASS
- 1
- RASTERVARIABLES
- 2
- AcDbRasterVariables
- 3
- ISM
- 90
- 0
- 91
- 0
- 280
- 0
- 281
- 0
- """
- _RASTER_VARIABLES_TPL = """0
- RASTERVARIABLES
- 5
- 0
- 102
- {ACAD_REACTORS
- 330
- 0
- 102
- }
- 330
- 0
- 100
- AcDbRasterVariables
- 90
- 0
- 70
- 0
- 71
- 1
- 72
- 3
- """
- class RasterVariables(DXFEntity):
- TEMPLATE = ExtendedTags.from_text(_RASTER_VARIABLES_TPL)
- CLASS = ExtendedTags.from_text(_RASTER_VARIABLES_CLS)
- DXFATTRIBS = DXFAttributes(
- none_subclass,
- DefSubclass('AcDbRasterVariables', {
- 'version': DXFAttr(90, default=0),
- 'frame': DXFAttr(70, default=0), # 0 = no frame; 1= show frame
- 'quality': DXFAttr(71, default=1), # 0=draft; 1=high
- 'units': DXFAttr(72, default=3), # 0 = None; 1 = mm; 2 = cm 3 = m; 4 = km; 5 = in 6 = ft; 7 = yd; 8 = mi
- }),
- )
|