emf 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +224 -19
- data/exe/emf +12 -0
- data/lib/emf/backend.rb +60 -0
- data/lib/emf/binary/class_field_accessors.rb +49 -0
- data/lib/emf/binary/float32_le.rb +54 -0
- data/lib/emf/binary/types.rb +40 -6
- data/lib/emf/conformance/context.rb +36 -0
- data/lib/emf/conformance/diagnostic.rb +18 -0
- data/lib/emf/conformance/manifest/emf_bitmap_misc.yml +622 -0
- data/lib/emf/conformance/manifest/emf_control_buffers.yml +61 -0
- data/lib/emf/conformance/manifest/emf_core.yml +117 -0
- data/lib/emf/conformance/manifest/emf_corpus_rules.yml +21 -0
- data/lib/emf/conformance/manifest/emf_objects_geometry.yml +229 -0
- data/lib/emf/conformance/manifest/emf_plus.yml +357 -0
- data/lib/emf/conformance/manifest/emf_plus_core.yml +33 -0
- data/lib/emf/conformance/manifest/emf_state_path.yml +403 -0
- data/lib/emf/conformance/manifest/emf_text.yml +97 -0
- data/lib/emf/conformance/manifest/wmf.yml +874 -0
- data/lib/emf/conformance/manifest.rb +79 -0
- data/lib/emf/conformance/profile.rb +35 -0
- data/lib/emf/conformance/record_types.rb +24 -0
- data/lib/emf/conformance/registry.rb +76 -0
- data/lib/emf/conformance/report.rb +83 -0
- data/lib/emf/conformance/rule.rb +16 -0
- data/lib/emf/conformance/rules/emf_bitmap.rb +357 -0
- data/lib/emf/conformance/rules/emf_comment_escape.rb +309 -0
- data/lib/emf/conformance/rules/emf_control_buffers.rb +137 -0
- data/lib/emf/conformance/rules/emf_corpus_named.rb +83 -0
- data/lib/emf/conformance/rules/emf_framing.rb +94 -0
- data/lib/emf/conformance/rules/emf_geometry.rb +282 -0
- data/lib/emf/conformance/rules/emf_header.rb +114 -0
- data/lib/emf/conformance/rules/emf_objects.rb +291 -0
- data/lib/emf/conformance/rules/emf_parse_recovery.rb +97 -0
- data/lib/emf/conformance/rules/emf_path_clip.rb +165 -0
- data/lib/emf/conformance/rules/emf_plus.rb +75 -0
- data/lib/emf/conformance/rules/emf_plus_common.rb +58 -0
- data/lib/emf/conformance/rules/emf_plus_drawing.rb +78 -0
- data/lib/emf/conformance/rules/emf_plus_effects.rb +104 -0
- data/lib/emf/conformance/rules/emf_plus_fields.rb +169 -0
- data/lib/emf/conformance/rules/emf_plus_fields_b.rb +102 -0
- data/lib/emf/conformance/rules/emf_plus_framing.rb +172 -0
- data/lib/emf/conformance/rules/emf_plus_objects.rb +97 -0
- data/lib/emf/conformance/rules/emf_plus_payloads.rb +320 -0
- data/lib/emf/conformance/rules/emf_plus_properties.rb +96 -0
- data/lib/emf/conformance/rules/emf_plus_state.rb +77 -0
- data/lib/emf/conformance/rules/emf_state.rb +244 -0
- data/lib/emf/conformance/rules/emf_text.rb +221 -0
- data/lib/emf/conformance/rules/emf_transform.rb +85 -0
- data/lib/emf/conformance/rules/wmf_buffers.rb +259 -0
- data/lib/emf/conformance/rules/wmf_framing.rb +146 -0
- data/lib/emf/conformance/rules/wmf_layout_records.rb +112 -0
- data/lib/emf/conformance/rules/wmf_objects.rb +168 -0
- data/lib/emf/conformance/rules/wmf_records.rb +191 -0
- data/lib/emf/conformance/rules/wmf_rejections.rb +184 -0
- data/lib/emf/conformance/runner.rb +61 -0
- data/lib/emf/conformance/ternary_raster_operations.rb +52 -0
- data/lib/emf/conformance.rb +31 -0
- data/lib/emf/emf_plus/effects/blur.rb +24 -0
- data/lib/emf/emf_plus/effects/brightness_contrast.rb +22 -0
- data/lib/emf/emf_plus/effects/color_balance.rb +24 -0
- data/lib/emf/emf_plus/effects/color_curve.rb +24 -0
- data/lib/emf/emf_plus/effects/color_lookup_table.rb +26 -0
- data/lib/emf/emf_plus/effects/color_matrix.rb +23 -0
- data/lib/emf/emf_plus/effects/effect.rb +50 -0
- data/lib/emf/emf_plus/effects/hue_saturation_lightness.rb +24 -0
- data/lib/emf/emf_plus/effects/levels.rb +24 -0
- data/lib/emf/emf_plus/effects/opaque.rb +19 -0
- data/lib/emf/emf_plus/effects/red_eye_correction.rb +35 -0
- data/lib/emf/emf_plus/effects/sharpen.rb +24 -0
- data/lib/emf/emf_plus/effects/tint.rb +22 -0
- data/lib/emf/emf_plus/effects.rb +45 -0
- data/lib/emf/emf_plus/frame.rb +41 -0
- data/lib/emf/emf_plus/links/effect_link.rb +16 -0
- data/lib/emf/emf_plus/links/get_dc_span.rb +18 -0
- data/lib/emf/emf_plus/links/link_error.rb +15 -0
- data/lib/emf/emf_plus/links.rb +77 -0
- data/lib/emf/emf_plus/object_chain.rb +108 -0
- data/lib/emf/emf_plus/object_table.rb +182 -0
- data/lib/emf/emf_plus/objects/brush.rb +296 -0
- data/lib/emf/emf_plus/objects/custom_line_cap.rb +106 -0
- data/lib/emf/emf_plus/objects/font.rb +47 -0
- data/lib/emf/emf_plus/objects/image.rb +68 -0
- data/lib/emf/emf_plus/objects/image_attributes.rb +28 -0
- data/lib/emf/emf_plus/objects/opaque.rb +19 -0
- data/lib/emf/emf_plus/objects/parts.rb +103 -0
- data/lib/emf/emf_plus/objects/path.rb +21 -0
- data/lib/emf/emf_plus/objects/pen.rb +132 -0
- data/lib/emf/emf_plus/objects/region.rb +39 -0
- data/lib/emf/emf_plus/objects/string_format.rb +55 -0
- data/lib/emf/emf_plus/objects/typed.rb +50 -0
- data/lib/emf/emf_plus/objects.rb +46 -0
- data/lib/emf/emf_plus/parser.rb +64 -2
- data/lib/emf/emf_plus/records/base.rb +107 -0
- data/lib/emf/emf_plus/records/begin_container.rb +31 -0
- data/lib/emf/emf_plus/records/begin_container_no_params.rb +20 -0
- data/lib/emf/emf_plus/records/body.rb +16 -0
- data/lib/emf/emf_plus/records/clear.rb +22 -0
- data/lib/emf/emf_plus/records/clip_transform_flags.rb +26 -0
- data/lib/emf/emf_plus/records/comment.rb +21 -0
- data/lib/emf/emf_plus/records/draw_arc.rb +33 -0
- data/lib/emf/emf_plus/records/draw_beziers.rb +31 -0
- data/lib/emf/emf_plus/records/draw_closed_curve.rb +34 -0
- data/lib/emf/emf_plus/records/draw_curve.rb +38 -0
- data/lib/emf/emf_plus/records/draw_driver_string.rb +61 -0
- data/lib/emf/emf_plus/records/draw_ellipse.rb +28 -0
- data/lib/emf/emf_plus/records/draw_image.rb +42 -0
- data/lib/emf/emf_plus/records/draw_image_points.rb +62 -0
- data/lib/emf/emf_plus/records/draw_lines.rb +34 -0
- data/lib/emf/emf_plus/records/draw_path.rb +23 -0
- data/lib/emf/emf_plus/records/draw_pie.rb +33 -0
- data/lib/emf/emf_plus/records/draw_rects.rb +30 -0
- data/lib/emf/emf_plus/records/draw_string.rb +41 -0
- data/lib/emf/emf_plus/records/end_container.rb +20 -0
- data/lib/emf/emf_plus/records/end_of_file.rb +17 -0
- data/lib/emf/emf_plus/records/fill_brush.rb +21 -0
- data/lib/emf/emf_plus/records/fill_closed_curve.rb +38 -0
- data/lib/emf/emf_plus/records/fill_ellipse.rb +29 -0
- data/lib/emf/emf_plus/records/fill_path.rb +23 -0
- data/lib/emf/emf_plus/records/fill_pie.rb +34 -0
- data/lib/emf/emf_plus/records/fill_polygon.rb +32 -0
- data/lib/emf/emf_plus/records/fill_rects.rb +31 -0
- data/lib/emf/emf_plus/records/fill_region.rb +23 -0
- data/lib/emf/emf_plus/records/get_dc.rb +18 -0
- data/lib/emf/emf_plus/records/header.rb +35 -0
- data/lib/emf/emf_plus/records/multiply_world_transform.rb +24 -0
- data/lib/emf/emf_plus/records/object.rb +32 -0
- data/lib/emf/emf_plus/records/offset_clip.rb +24 -0
- data/lib/emf/emf_plus/records/primitives/argb.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/bitmap.rb +32 -0
- data/lib/emf/emf_plus/records/primitives/bitmap_data.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/blend_colors.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/blend_factors.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/bounded_array.rb +38 -0
- data/lib/emf/emf_plus/records/primitives/byte_reader.rb +25 -0
- data/lib/emf/emf_plus/records/primitives/character_range.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/compressed_image.rb +17 -0
- data/lib/emf/emf_plus/records/primitives/focus_scale_data.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/graphics_version.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/language_identifier.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/metafile.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/palette.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/path.rb +89 -0
- data/lib/emf/emf_plus/records/primitives/path_point_type.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/path_point_type_rle.rb +23 -0
- data/lib/emf/emf_plus/records/primitives/point.rb +18 -0
- data/lib/emf/emf_plus/records/primitives/point_array.rb +42 -0
- data/lib/emf/emf_plus/records/primitives/point_f.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/point_r.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/rect.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/rect_array.rb +24 -0
- data/lib/emf/emf_plus/records/primitives/rect_f.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/region_node.rb +68 -0
- data/lib/emf/emf_plus/records/primitives/region_node_child_nodes.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/region_node_path.rb +37 -0
- data/lib/emf/emf_plus/records/primitives/relative_coordinate.rb +32 -0
- data/lib/emf/emf_plus/records/primitives/string_format_data.rb +23 -0
- data/lib/emf/emf_plus/records/primitives/transform_matrix.rb +23 -0
- data/lib/emf/emf_plus/records/primitives.rb +41 -0
- data/lib/emf/emf_plus/records/reset_clip.rb +17 -0
- data/lib/emf/emf_plus/records/reset_world_transform.rb +17 -0
- data/lib/emf/emf_plus/records/restore.rb +20 -0
- data/lib/emf/emf_plus/records/rotate_world_transform.rb +24 -0
- data/lib/emf/emf_plus/records/save.rb +20 -0
- data/lib/emf/emf_plus/records/scale_world_transform.rb +26 -0
- data/lib/emf/emf_plus/records/serializable_object.rb +32 -0
- data/lib/emf/emf_plus/records/set_anti_alias_mode.rb +25 -0
- data/lib/emf/emf_plus/records/set_clip_path.rb +20 -0
- data/lib/emf/emf_plus/records/set_clip_rect.rb +24 -0
- data/lib/emf/emf_plus/records/set_clip_region.rb +20 -0
- data/lib/emf/emf_plus/records/set_compositing_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_compositing_quality.rb +21 -0
- data/lib/emf/emf_plus/records/set_interpolation_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_page_transform.rb +25 -0
- data/lib/emf/emf_plus/records/set_pixel_offset_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_rendering_origin.rb +22 -0
- data/lib/emf/emf_plus/records/set_text_contrast.rb +24 -0
- data/lib/emf/emf_plus/records/set_text_rendering_hint.rb +21 -0
- data/lib/emf/emf_plus/records/set_ts_clip.rb +40 -0
- data/lib/emf/emf_plus/records/set_ts_graphics.rb +88 -0
- data/lib/emf/emf_plus/records/set_world_transform.rb +22 -0
- data/lib/emf/emf_plus/records/shape_flags.rb +23 -0
- data/lib/emf/emf_plus/records/translate_world_transform.rb +26 -0
- data/lib/emf/emf_plus/records/unknown.rb +20 -0
- data/lib/emf/emf_plus/records.rb +107 -0
- data/lib/emf/emf_plus/serializer.rb +9 -2
- data/lib/emf/emf_plus/stream/conformance.rb +68 -0
- data/lib/emf/emf_plus/stream/editor.rb +21 -0
- data/lib/emf/emf_plus/stream/emf_gap.rb +20 -0
- data/lib/emf/emf_plus/stream/link_index.rb +30 -0
- data/lib/emf/emf_plus/stream/rebuild.rb +47 -0
- data/lib/emf/emf_plus/stream/record_handle.rb +26 -0
- data/lib/emf/emf_plus/stream/segment.rb +70 -0
- data/lib/emf/emf_plus/stream.rb +153 -0
- data/lib/emf/emf_plus.rb +9 -0
- data/lib/emf/emr/binary/dib_header.rb +142 -0
- data/lib/emf/emr/binary/ext_text_out_fields.rb +43 -0
- data/lib/emf/emr/binary/extended_pen_buffers.rb +23 -0
- data/lib/emf/emr/binary/fast_fill.rb +1164 -0
- data/lib/emf/emr/binary/font.rb +159 -0
- data/lib/emf/emr/binary/lazy_utf16_array.rb +82 -0
- data/lib/emf/emr/binary/pack_plan.rb +144 -0
- data/lib/emf/emr/binary/pack_plan_check.rb +75 -0
- data/lib/emf/emr/binary/pack_plan_exact.rb +130 -0
- data/lib/emf/emr/binary/pack_plan_generate.rb +116 -0
- data/lib/emf/emr/binary/pack_plan_values.rb +92 -0
- data/lib/emf/emr/binary/palette_body.rb +19 -0
- data/lib/emf/emr/binary/palette_entry.rb +18 -0
- data/lib/emf/emr/binary/record.rb +33 -0
- data/lib/emf/emr/binary/records/alpha_blend.rb +43 -0
- data/lib/emf/emr/binary/records/angle_arc.rb +2 -2
- data/lib/emf/emr/binary/records/bit_blt.rb +14 -0
- data/lib/emf/emr/binary/records/color_correct_palette.rb +55 -1
- data/lib/emf/emr/binary/records/colormatch_to_target_w.rb +76 -1
- data/lib/emf/emr/binary/records/create_colorspace.rb +67 -1
- data/lib/emf/emr/binary/records/create_colorspace_w.rb +90 -1
- data/lib/emf/emr/binary/records/create_dib_pattern_brush_pt.rb +14 -0
- data/lib/emf/emr/binary/records/create_font_indirect_w.rb +6 -2
- data/lib/emf/emr/binary/records/create_mono_brush.rb +14 -0
- data/lib/emf/emr/binary/records/create_palette.rb +19 -1
- data/lib/emf/emr/binary/records/delete_colorspace.rb +22 -1
- data/lib/emf/emr/binary/records/draw_escape.rb +45 -1
- data/lib/emf/emr/binary/records/ellipse.rb +1 -1
- data/lib/emf/emr/binary/records/eof.rb +9 -0
- data/lib/emf/emr/binary/records/ext_create_pen.rb +80 -1
- data/lib/emf/emr/binary/records/ext_escape.rb +45 -1
- data/lib/emf/emr/binary/records/ext_flood_fill.rb +9 -2
- data/lib/emf/emr/binary/records/ext_select_clip_rgn.rb +9 -1
- data/lib/emf/emr/binary/records/ext_text_out_a.rb +16 -3
- data/lib/emf/emr/binary/records/ext_text_out_w.rb +14 -3
- data/lib/emf/emr/binary/records/fill_rgn.rb +11 -2
- data/lib/emf/emr/binary/records/force_ufi_mapping.rb +38 -1
- data/lib/emf/emr/binary/records/frame_rgn.rb +12 -2
- data/lib/emf/emr/binary/records/gls_bounded_record.rb +61 -1
- data/lib/emf/emr/binary/records/gls_record.rb +42 -1
- data/lib/emf/emr/binary/records/gradient_fill.rb +7 -0
- data/lib/emf/emr/binary/records/invert_rgn.rb +11 -3
- data/lib/emf/emr/binary/records/mask_blt.rb +66 -0
- data/lib/emf/emr/binary/records/named_escape.rb +78 -1
- data/lib/emf/emr/binary/records/paint_rgn.rb +11 -3
- data/lib/emf/emr/binary/records/pixel_format.rb +76 -1
- data/lib/emf/emr/binary/records/plg_blt.rb +66 -0
- data/lib/emf/emr/binary/records/poly_textout_a.rb +128 -1
- data/lib/emf/emr/binary/records/poly_textout_w.rb +128 -1
- data/lib/emf/emr/binary/records/raw.rb +3 -0
- data/lib/emf/emr/binary/records/realize_palette.rb +1 -0
- data/lib/emf/emr/binary/records/rectangle.rb +1 -1
- data/lib/emf/emr/binary/records/resize_palette.rb +16 -2
- data/lib/emf/emr/binary/records/round_rect.rb +2 -2
- data/lib/emf/emr/binary/records/select_palette.rb +1 -0
- data/lib/emf/emr/binary/records/set_color_adjustment.rb +136 -0
- data/lib/emf/emr/binary/records/set_colorspace.rb +22 -1
- data/lib/emf/emr/binary/records/set_dibits_to_device.rb +43 -0
- data/lib/emf/emr/binary/records/set_icm_profile_a.rb +71 -1
- data/lib/emf/emr/binary/records/set_icm_profile_w.rb +71 -1
- data/lib/emf/emr/binary/records/set_linked_ufis.rb +49 -1
- data/lib/emf/emr/binary/records/set_miter_limit.rb +1 -1
- data/lib/emf/emr/binary/records/set_palette_entries.rb +20 -2
- data/lib/emf/emr/binary/records/set_text_justification.rb +8 -2
- data/lib/emf/emr/binary/records/small_text_out.rb +55 -4
- data/lib/emf/emr/binary/records/stretch_blt.rb +14 -0
- data/lib/emf/emr/binary/records/stretch_dibits.rb +14 -0
- data/lib/emf/emr/binary/records/transparent_blt.rb +43 -0
- data/lib/emf/emr/binary/records.rb +4 -2
- data/lib/emf/emr/binary/region_data.rb +33 -0
- data/lib/emf/emr/binary/state_record_body.rb +33 -0
- data/lib/emf/emr/binary/thin_shell.rb +226 -0
- data/lib/emf/emr/binary/value_view/layout.rb +101 -0
- data/lib/emf/emr/binary/value_view/reader_source.rb +88 -0
- data/lib/emf/emr/binary/value_view.rb +173 -0
- data/lib/emf/emr/binary/variable_buffers.rb +87 -0
- data/lib/emf/emr/binary.rb +4 -0
- data/lib/emf/emr/filled_record.rb +77 -0
- data/lib/emf/emr/parser.rb +239 -50
- data/lib/emf/emr/serializer.rb +4 -5
- data/lib/emf/emr.rb +1 -0
- data/lib/emf/error.rb +24 -1
- data/lib/emf/model/diagnostic.rb +41 -0
- data/lib/emf/model/emr/header.rb +40 -1
- data/lib/emf/model/emr/records.rb +142 -6
- data/lib/emf/model/emr/wire_values.rb +43 -0
- data/lib/emf/model/emr.rb +1 -0
- data/lib/emf/model/geometry/color.rb +19 -1
- data/lib/emf/model/metafile.rb +22 -2
- data/lib/emf/model/wmf/bitmap_records.rb +155 -0
- data/lib/emf/model/wmf/brush_records.rb +45 -0
- data/lib/emf/model/wmf/dc_escape_records.rb +67 -0
- data/lib/emf/model/wmf/font_record.rb +40 -0
- data/lib/emf/model/wmf/geometry_records.rb +107 -0
- data/lib/emf/model/wmf/header.rb +36 -0
- data/lib/emf/model/wmf/object_records.rb +71 -0
- data/lib/emf/model/wmf/palette_records.rb +68 -0
- data/lib/emf/model/wmf/records.rb +247 -0
- data/lib/emf/model/wmf/region_records.rb +112 -0
- data/lib/emf/model/wmf/state_records.rb +188 -0
- data/lib/emf/model/wmf/text_records.rb +36 -0
- data/lib/emf/model/wmf.rb +11 -0
- data/lib/emf/model.rb +2 -0
- data/lib/emf/native/bitmap_fields.rb +58 -0
- data/lib/emf/native/diagnostic_contract.rb +39 -0
- data/lib/emf/native/diagnostics.rb +81 -0
- data/lib/emf/native/emf_plus_loader.rb +35 -0
- data/lib/emf/native/emf_plus_snapshot.rb +96 -0
- data/lib/emf/native/emf_plus_source.rb +20 -0
- data/lib/emf/native/emf_plus_stream.rb +150 -0
- data/lib/emf/native/fields.rb +369 -0
- data/lib/emf/native/font_fields.rb +87 -0
- data/lib/emf/native/gradient_fields.rb +23 -0
- data/lib/emf/native/header.rb +35 -0
- data/lib/emf/native/header_errors.rb +30 -0
- data/lib/emf/native/hydrator.rb +151 -0
- data/lib/emf/native/lazy_wire.rb +100 -0
- data/lib/emf/native/legacy_state_fields.rb +22 -0
- data/lib/emf/native/library_path.rb +68 -0
- data/lib/emf/native/loader.rb +120 -0
- data/lib/emf/native/palette_fields.rb +45 -0
- data/lib/emf/native/poly_text_fields.rb +116 -0
- data/lib/emf/native/resource_failure.rb +28 -0
- data/lib/emf/native/small_text_fields.rb +27 -0
- data/lib/emf/native/snapshot.rb +102 -0
- data/lib/emf/native/wmf_bitmap_fields.rb +58 -0
- data/lib/emf/native/wmf_brush_fields.rb +62 -0
- data/lib/emf/native/wmf_fields.rb +117 -0
- data/lib/emf/native/wmf_hydrator.rb +143 -0
- data/lib/emf/native/wmf_loading.rb +49 -0
- data/lib/emf/native/wmf_palette_fields.rb +60 -0
- data/lib/emf/native/wmf_region_fields.rb +92 -0
- data/lib/emf/native/wmf_rejection.rb +84 -0
- data/lib/emf/native/wmf_remaining_fields.rb +70 -0
- data/lib/emf/native/wmf_snapshot.rb +51 -0
- data/lib/emf/native/wmf_text_fields.rb +56 -0
- data/lib/emf/native.rb +61 -0
- data/lib/emf/parse_evidence.rb +57 -0
- data/lib/emf/resource_budget/bitmap.rb +66 -0
- data/lib/emf/resource_budget/gradient.rb +30 -0
- data/lib/emf/resource_budget/poly_text.rb +85 -0
- data/lib/emf/resource_budget.rb +382 -0
- data/lib/emf/resource_limits/emf_records.rb +130 -0
- data/lib/emf/resource_limits.rb +58 -0
- data/lib/emf/version.rb +1 -1
- data/lib/emf/visitors/dump.rb +4 -0
- data/lib/emf/visitors/stats.rb +6 -5
- data/lib/emf/wmf/binary.rb +150 -1
- data/lib/emf/wmf/bitmap_codec.rb +118 -0
- data/lib/emf/wmf/brush_codec.rb +102 -0
- data/lib/emf/wmf/dc_escape_codec.rb +75 -0
- data/lib/emf/wmf/dib.rb +187 -0
- data/lib/emf/wmf/embedded_emf.rb +137 -0
- data/lib/emf/wmf/escape_views.rb +89 -0
- data/lib/emf/wmf/evidence.rb +255 -0
- data/lib/emf/wmf/geometry_codec.rb +49 -0
- data/lib/emf/wmf/palette_codec.rb +85 -0
- data/lib/emf/wmf/parser.rb +147 -2
- data/lib/emf/wmf/recovery.rb +95 -0
- data/lib/emf/wmf/region_codec.rb +151 -0
- data/lib/emf/wmf/serializer.rb +164 -2
- data/lib/emf/wmf/text_codec.rb +123 -0
- data/lib/emf/wmf.rb +7 -0
- data/lib/emf.rb +13 -9
- metadata +287 -10
data/lib/emf/emf_plus/parser.rb
CHANGED
|
@@ -2,11 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
module Emf
|
|
4
4
|
module EmfPlus
|
|
5
|
+
# Frames EMF+ records without decoding their bodies. Unknown record types
|
|
6
|
+
# are framed like any other, so nothing is dropped.
|
|
7
|
+
#
|
|
8
|
+
# Malformed framing raises Emf::ParseError. Pass `errors:` (an Array) to
|
|
9
|
+
# instead collect the ParseError and stop framing the stream at that point,
|
|
10
|
+
# the way Emr::Parser treats a corrupt EMR record.
|
|
5
11
|
module Parser
|
|
6
12
|
module_function
|
|
7
13
|
|
|
8
|
-
def call(
|
|
9
|
-
|
|
14
|
+
def call(bytes, errors: nil, comment_index: nil)
|
|
15
|
+
bytes = bytes.b
|
|
16
|
+
frames = []
|
|
17
|
+
offset = 0
|
|
18
|
+
while offset < bytes.bytesize
|
|
19
|
+
frame = read_frame(bytes, offset, comment_index)
|
|
20
|
+
frames << frame
|
|
21
|
+
offset += frame.size
|
|
22
|
+
end
|
|
23
|
+
frames
|
|
24
|
+
rescue ParseError => e
|
|
25
|
+
raise unless errors
|
|
26
|
+
|
|
27
|
+
errors << e
|
|
28
|
+
frames
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Frames each EMF+ comment of a parsed Metafile separately, tagging every
|
|
32
|
+
# frame with the index (into metafile.records) of the comment it came
|
|
33
|
+
# from. Concatenating the comment payloads gives Metafile#emf_plus.
|
|
34
|
+
def from_metafile(metafile, errors: nil)
|
|
35
|
+
metafile.records.each_with_index.flat_map do |record, index|
|
|
36
|
+
next [] unless record.wire.is_a?(Emf::Emr::Binary::Records::Comment)
|
|
37
|
+
|
|
38
|
+
call(Emf::Emr::Parser.extract_emf_plus(record.wire), errors: errors, comment_index: index)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def read_frame(bytes, offset, comment_index)
|
|
43
|
+
remaining = bytes.bytesize - offset
|
|
44
|
+
fail_at(offset, nil, "truncated EMF+ record header (#{remaining} bytes left)") if remaining < Frame::HEADER_BYTES
|
|
45
|
+
|
|
46
|
+
type, flags, size, data_size = bytes.byteslice(offset, Frame::HEADER_BYTES).unpack("vvVV")
|
|
47
|
+
validate_sizes(offset, type, size, data_size, remaining, comment_index)
|
|
48
|
+
Frame.new(type: type, flags: flags, size: size, data_size: data_size,
|
|
49
|
+
data: bytes.byteslice(offset + Frame::HEADER_BYTES, size - Frame::HEADER_BYTES),
|
|
50
|
+
offset: offset, comment_index: comment_index)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def validate_sizes(offset, type, size, data_size, remaining, comment_index = nil)
|
|
54
|
+
fail_at(offset, type, "EMF+ record Size #{size} < #{Frame::HEADER_BYTES}") if size < Frame::HEADER_BYTES
|
|
55
|
+
fail_at(offset, type, "EMF+ record Size #{size} is not a multiple of 4") unless (size % 4).zero?
|
|
56
|
+
fail_at(offset, type, "EMF+ record DataSize #{data_size} exceeds Size #{size} - 12") if data_size > size - Frame::HEADER_BYTES
|
|
57
|
+
fail_at(offset, type, truncated_message(size, remaining, comment_index, offset)) if size > remaining
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# MS-EMFPLUS 1.3 and MS-EMF 2.3.3.2: an EMR_COMMENT_EMFPLUS holds whole
|
|
61
|
+
# EMF+ records; only an EmfPlusObject (C flag) continues in a later record.
|
|
62
|
+
# A record that runs past its comment is therefore malformed, not split.
|
|
63
|
+
def truncated_message(size, remaining, comment_index, offset)
|
|
64
|
+
return "truncated EMF+ record (Size #{size}, #{remaining} bytes left)" unless comment_index
|
|
65
|
+
|
|
66
|
+
"EMF+ record (Size #{size}) overruns EMR_COMMENT_EMFPLUS record #{comment_index} by " \
|
|
67
|
+
"#{size - remaining} bytes; a record cannot span comments (comment payload offset #{offset})"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def fail_at(offset, type, message)
|
|
71
|
+
raise ParseError.new(offset: offset, record_code: type, message: "#{message} at offset #{offset}")
|
|
10
72
|
end
|
|
11
73
|
end
|
|
12
74
|
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bindata"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Records
|
|
8
|
+
# A framed record whose body is read through a BinData class (BODY in the
|
|
9
|
+
# subclass). Bytes after the body (padding, unknown trailing data) are
|
|
10
|
+
# kept in `trailing`, so an unedited record re-encodes to its frame bytes.
|
|
11
|
+
class Base
|
|
12
|
+
attr_reader :type, :flags, :size, :data_size, :offset, :comment_index, :body, :trailing
|
|
13
|
+
|
|
14
|
+
def initialize(frame)
|
|
15
|
+
@type = frame.type
|
|
16
|
+
@flags = frame.flags
|
|
17
|
+
@size = frame.size
|
|
18
|
+
@data_size = frame.data_size
|
|
19
|
+
@offset = frame.offset
|
|
20
|
+
@comment_index = frame.comment_index
|
|
21
|
+
@body = read_body(frame)
|
|
22
|
+
@trailing = frame.data.byteslice(@body.num_bytes..).freeze
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_binary
|
|
26
|
+
[type, flags, size, data_size].pack("vvVV") + body.to_binary_s + trailing
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns a new record with the given edits applied; the receiver is
|
|
30
|
+
# unchanged. Keys are:
|
|
31
|
+
# flags: the raw Record Flags value;
|
|
32
|
+
# flag fields: the names in #flag_fields (compressed:, emf_object_id:,
|
|
33
|
+
# combine_mode: ...). Booleans set or clear a bit, integers
|
|
34
|
+
# fill a bit range; every other flag bit is kept;
|
|
35
|
+
# body fields: any BinData field of the body. Length fields and
|
|
36
|
+
# their arrays are independent, so a variable-length
|
|
37
|
+
# edit sets both (item_count: 3, rect_data: {...}).
|
|
38
|
+
# Size and DataSize are recomputed. Trailing bytes beyond the original
|
|
39
|
+
# DataSize are alignment padding and are dropped (the new Size re-pads);
|
|
40
|
+
# trailing bytes inside it are unknown data, kept after the body and
|
|
41
|
+
# counted in DataSize.
|
|
42
|
+
# Changing a flag that selects the body layout (compressed, relative)
|
|
43
|
+
# keeps the other fields; array elements of the newly selected layout
|
|
44
|
+
# start zeroed unless the same call supplies them.
|
|
45
|
+
def with(**edits)
|
|
46
|
+
new_flags = edited_flags(edits)
|
|
47
|
+
new_body = edited_body(new_flags, edits)
|
|
48
|
+
self.class.new(edited_frame(new_flags, new_body))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Flag-backed attributes editable through #with, as { name => mask }.
|
|
52
|
+
# Record families and mixins extend it with `super.merge(...)`.
|
|
53
|
+
def flag_fields = {}
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def edited_flags(edits)
|
|
58
|
+
flag_edits = edits.slice(*flag_fields.keys)
|
|
59
|
+
flag_edits.reduce(edits.fetch(:flags, flags)) do |bits, (name, value)|
|
|
60
|
+
encode_flag(bits, name, flag_fields.fetch(name), value)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def encode_flag(bits, name, mask, value)
|
|
65
|
+
shift = (mask & -mask).bit_length - 1
|
|
66
|
+
number = { true => 1, false => 0 }.fetch(value, value)
|
|
67
|
+
unless number.is_a?(Integer) && number.between?(0, mask >> shift)
|
|
68
|
+
raise ArgumentError, "#{name} must fit #{(mask >> shift).bit_length} bit(s), got #{value.inspect}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
(bits & ~mask) | (number << shift)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def edited_body(new_flags, edits)
|
|
75
|
+
fields = edits.except(:flags, *flag_fields.keys)
|
|
76
|
+
unknown = fields.keys - body.field_names
|
|
77
|
+
raise ArgumentError, "unknown field(s) #{unknown.join(', ')} for #{self.class.name}" unless unknown.empty?
|
|
78
|
+
|
|
79
|
+
self.class::BODY.new(data_size: data_size, flags: new_flags).tap do |fresh|
|
|
80
|
+
fresh.assign(deep_merge(body.snapshot, fields))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# BinData#assign(hash) clears every field it is not given, so edits
|
|
85
|
+
# are folded into the body's own snapshot and assigned once.
|
|
86
|
+
def deep_merge(base, edit)
|
|
87
|
+
return edit unless base.is_a?(Hash) && edit.is_a?(Hash)
|
|
88
|
+
|
|
89
|
+
base.merge(edit) { |_name, old, new| deep_merge(old, new) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def edited_frame(new_flags, new_body)
|
|
93
|
+
kept = trailing.byteslice(0, data_size - body.num_bytes)
|
|
94
|
+
Frame.new(type: type, flags: new_flags, size: Frame::HEADER_BYTES, data_size: 0, data: "",
|
|
95
|
+
offset: offset, comment_index: comment_index).with_data(new_body.to_binary_s + kept)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def read_body(frame)
|
|
99
|
+
self.class::BODY.new(data_size: data_size, flags: flags).read(frame.data.byteslice(0, data_size))
|
|
100
|
+
rescue IOError, BinData::ValidityError => e
|
|
101
|
+
raise ParseError.new(offset: offset, record_code: type,
|
|
102
|
+
message: "malformed #{self.class.name.split('::').last} body at offset #{offset}: #{e.message}")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/rect_f"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Records
|
|
8
|
+
# EmfPlusBeginContainer (2.3.7.1). Flags low byte is the PageUnit
|
|
9
|
+
# (UnitType); DestRect and SrcRect define the container transform.
|
|
10
|
+
class BeginContainer < Base
|
|
11
|
+
TYPE = 0x4027
|
|
12
|
+
PAGE_UNIT_MASK = 0x00FF
|
|
13
|
+
|
|
14
|
+
class BeginContainerBody < Body
|
|
15
|
+
endian :little
|
|
16
|
+
rect_f :dest_rect
|
|
17
|
+
rect_f :src_rect
|
|
18
|
+
uint32 :stack_index
|
|
19
|
+
end
|
|
20
|
+
BODY = BeginContainerBody
|
|
21
|
+
|
|
22
|
+
def flag_fields = { page_unit: PAGE_UNIT_MASK }
|
|
23
|
+
|
|
24
|
+
def page_unit = flags & PAGE_UNIT_MASK
|
|
25
|
+
def dest_rect = body.dest_rect
|
|
26
|
+
def src_rect = body.src_rect
|
|
27
|
+
def stack_index = body.stack_index.to_i
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Records
|
|
6
|
+
# EmfPlusBeginContainerNoParams (2.3.7.2): opens a container identified by StackIndex.
|
|
7
|
+
class BeginContainerNoParams < Base
|
|
8
|
+
TYPE = 0x4028
|
|
9
|
+
|
|
10
|
+
class BeginContainerNoParamsBody < Body
|
|
11
|
+
endian :little
|
|
12
|
+
uint32 :stack_index
|
|
13
|
+
end
|
|
14
|
+
BODY = BeginContainerNoParamsBody
|
|
15
|
+
|
|
16
|
+
def stack_index = body.stack_index.to_i
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bindata"
|
|
4
|
+
require "emf/binary/class_field_accessors"
|
|
5
|
+
|
|
6
|
+
module Emf
|
|
7
|
+
module EmfPlus
|
|
8
|
+
module Records
|
|
9
|
+
# Base of every BinData structure declared under Records. Its fields are
|
|
10
|
+
# always class-level, so the accessors are defined once per class.
|
|
11
|
+
class Body < BinData::Record
|
|
12
|
+
prepend Emf::Binary::ClassFieldAccessors
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/argb"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Records
|
|
8
|
+
# EmfPlusClear (2.3.4.1). Flags are unused.
|
|
9
|
+
class Clear < Base
|
|
10
|
+
TYPE = 0x4009
|
|
11
|
+
|
|
12
|
+
class ClearBody < Body
|
|
13
|
+
endian :little
|
|
14
|
+
argb :color
|
|
15
|
+
end
|
|
16
|
+
BODY = ClearBody
|
|
17
|
+
|
|
18
|
+
def color = body.color
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Records
|
|
6
|
+
# Record Flags readers shared by the clipping and transform records.
|
|
7
|
+
module CombineModeFlags
|
|
8
|
+
COMBINE_MODE_MASK = 0x0F00
|
|
9
|
+
OBJECT_ID_MASK = 0x00FF
|
|
10
|
+
|
|
11
|
+
def flag_fields = super.merge(combine_mode: COMBINE_MODE_MASK, emf_object_id: OBJECT_ID_MASK)
|
|
12
|
+
|
|
13
|
+
def combine_mode = (flags & COMBINE_MODE_MASK) >> 8
|
|
14
|
+
def emf_object_id = flags & OBJECT_ID_MASK
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module PostMultiplyFlag
|
|
18
|
+
POST_MULTIPLY_FLAG = 0x2000
|
|
19
|
+
|
|
20
|
+
def flag_fields = super.merge(post_multiply: POST_MULTIPLY_FLAG)
|
|
21
|
+
|
|
22
|
+
def post_multiply? = flags.anybits?(POST_MULTIPLY_FLAG)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Records
|
|
6
|
+
# EmfPlusComment (2.3.3.4): opaque private data.
|
|
7
|
+
class Comment < Base
|
|
8
|
+
TYPE = 0x4003
|
|
9
|
+
|
|
10
|
+
class CommentBody < Body
|
|
11
|
+
endian :little
|
|
12
|
+
mandatory_parameter :data_size
|
|
13
|
+
string :private_data, read_length: :data_size
|
|
14
|
+
end
|
|
15
|
+
BODY = CommentBody
|
|
16
|
+
|
|
17
|
+
def private_data = body.private_data.to_s
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
require "emf/emf_plus/records/primitives/rect_array"
|
|
5
|
+
|
|
6
|
+
module Emf
|
|
7
|
+
module EmfPlus
|
|
8
|
+
module Records
|
|
9
|
+
# EmfPlusDrawArc (2.3.4.2). C selects Rect over RectF; ObjectID is the pen.
|
|
10
|
+
class DrawArc < Base
|
|
11
|
+
include ShapeFlags
|
|
12
|
+
|
|
13
|
+
TYPE = 0x4012
|
|
14
|
+
|
|
15
|
+
class DrawArcBody < Body
|
|
16
|
+
endian :little
|
|
17
|
+
mandatory_parameter :flags
|
|
18
|
+
float32_le :start_angle
|
|
19
|
+
float32_le :sweep_angle
|
|
20
|
+
rect_array :rect_data,
|
|
21
|
+
rect_count: 1,
|
|
22
|
+
compressed: -> { flags.anybits?(ShapeFlags::COMPRESSED_FLAG) }
|
|
23
|
+
end
|
|
24
|
+
BODY = DrawArcBody
|
|
25
|
+
|
|
26
|
+
def pen_id = emf_object_id
|
|
27
|
+
def start_angle = body.start_angle
|
|
28
|
+
def sweep_angle = body.sweep_angle
|
|
29
|
+
def rect = body.rect_data.rects.first
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/point_array"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Records
|
|
8
|
+
# EmfPlusDrawBeziers (2.3.4.3). C compressed, P relative points; ObjectID is the pen.
|
|
9
|
+
class DrawBeziers < Base
|
|
10
|
+
include ShapeFlags
|
|
11
|
+
|
|
12
|
+
TYPE = 0x4019
|
|
13
|
+
|
|
14
|
+
class DrawBeziersBody < Body
|
|
15
|
+
endian :little
|
|
16
|
+
mandatory_parameter :flags
|
|
17
|
+
uint32 :item_count
|
|
18
|
+
point_array :point_data,
|
|
19
|
+
point_count: :item_count,
|
|
20
|
+
relative: -> { flags.anybits?(ShapeFlags::RELATIVE_FLAG) },
|
|
21
|
+
compressed: -> { flags.anybits?(ShapeFlags::COMPRESSED_FLAG) }
|
|
22
|
+
end
|
|
23
|
+
BODY = DrawBeziersBody
|
|
24
|
+
|
|
25
|
+
def pen_id = emf_object_id
|
|
26
|
+
def count = body.item_count
|
|
27
|
+
def points = body.point_data.points
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
require "emf/emf_plus/records/primitives/point_array"
|
|
5
|
+
|
|
6
|
+
module Emf
|
|
7
|
+
module EmfPlus
|
|
8
|
+
module Records
|
|
9
|
+
# EmfPlusDrawClosedCurve (2.3.4.4). C compressed, P relative points; ObjectID is the pen.
|
|
10
|
+
class DrawClosedCurve < Base
|
|
11
|
+
include ShapeFlags
|
|
12
|
+
|
|
13
|
+
TYPE = 0x4017
|
|
14
|
+
|
|
15
|
+
class DrawClosedCurveBody < Body
|
|
16
|
+
endian :little
|
|
17
|
+
mandatory_parameter :flags
|
|
18
|
+
float32_le :tension
|
|
19
|
+
uint32 :item_count
|
|
20
|
+
point_array :point_data,
|
|
21
|
+
point_count: :item_count,
|
|
22
|
+
relative: -> { flags.anybits?(ShapeFlags::RELATIVE_FLAG) },
|
|
23
|
+
compressed: -> { flags.anybits?(ShapeFlags::COMPRESSED_FLAG) }
|
|
24
|
+
end
|
|
25
|
+
BODY = DrawClosedCurveBody
|
|
26
|
+
|
|
27
|
+
def pen_id = emf_object_id
|
|
28
|
+
def tension = body.tension
|
|
29
|
+
def count = body.item_count
|
|
30
|
+
def points = body.point_data.points
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
require "emf/emf_plus/records/primitives/point_array"
|
|
5
|
+
|
|
6
|
+
module Emf
|
|
7
|
+
module EmfPlus
|
|
8
|
+
module Records
|
|
9
|
+
# EmfPlusDrawCurve (2.3.4.5). C selects Point over PointF; ObjectID is the pen.
|
|
10
|
+
class DrawCurve < Base
|
|
11
|
+
include ShapeFlags
|
|
12
|
+
|
|
13
|
+
TYPE = 0x4018
|
|
14
|
+
|
|
15
|
+
class DrawCurveBody < Body
|
|
16
|
+
endian :little
|
|
17
|
+
mandatory_parameter :flags
|
|
18
|
+
float32_le :tension
|
|
19
|
+
uint32 :offset
|
|
20
|
+
uint32 :num_segments
|
|
21
|
+
uint32 :item_count
|
|
22
|
+
point_array :point_data,
|
|
23
|
+
point_count: :item_count,
|
|
24
|
+
relative: -> { false },
|
|
25
|
+
compressed: -> { flags.anybits?(ShapeFlags::COMPRESSED_FLAG) }
|
|
26
|
+
end
|
|
27
|
+
BODY = DrawCurveBody
|
|
28
|
+
|
|
29
|
+
def pen_id = emf_object_id
|
|
30
|
+
def tension = body.tension
|
|
31
|
+
def start_point_index = body.offset
|
|
32
|
+
def num_segments = body.num_segments
|
|
33
|
+
def count = body.item_count
|
|
34
|
+
def points = body.point_data.points
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
require "emf/emf_plus/records/primitives/bounded_array"
|
|
5
|
+
require "emf/emf_plus/records/primitives/point_f"
|
|
6
|
+
|
|
7
|
+
module Emf
|
|
8
|
+
module EmfPlus
|
|
9
|
+
module Records
|
|
10
|
+
# EmfPlusDrawDriverString (2.3.4.6). The glyph position array always holds
|
|
11
|
+
# GlyphCount elements, as the Size and DataSize formulas require.
|
|
12
|
+
class DrawDriverString < Base
|
|
13
|
+
TYPE = 0x4036
|
|
14
|
+
SOLID_COLOR_FLAG = 0x8000
|
|
15
|
+
OBJECT_ID_MASK = 0x00FF
|
|
16
|
+
CMAP_LOOKUP = 0x00000001
|
|
17
|
+
VERTICAL = 0x00000002
|
|
18
|
+
REALIZED_ADVANCE = 0x00000004
|
|
19
|
+
LIMIT_SUBPIXEL = 0x00000008
|
|
20
|
+
|
|
21
|
+
class DrawDriverStringBody < Body
|
|
22
|
+
endian :little
|
|
23
|
+
uint32 :brush_id
|
|
24
|
+
uint32 :options_flags
|
|
25
|
+
uint32 :matrix_present
|
|
26
|
+
uint32 :glyph_count
|
|
27
|
+
bounded_array :glyphs, type: :uint16, element_size: 2, initial_length: :glyph_count
|
|
28
|
+
bounded_array :glyph_positions, type: :point_f, element_size: 8, initial_length: :glyph_count
|
|
29
|
+
array :transform_matrix, type: :float32_le, initial_length: 6, onlyif: -> { matrix_present == 1 }
|
|
30
|
+
end
|
|
31
|
+
BODY = DrawDriverStringBody
|
|
32
|
+
|
|
33
|
+
def flag_fields = { solid_color: SOLID_COLOR_FLAG, font_object_id: OBJECT_ID_MASK }
|
|
34
|
+
|
|
35
|
+
def solid_color? = flags.anybits?(SOLID_COLOR_FLAG)
|
|
36
|
+
def font_object_id = flags & OBJECT_ID_MASK
|
|
37
|
+
def brush_id = body.brush_id
|
|
38
|
+
def options_flags = body.options_flags
|
|
39
|
+
def cmap_lookup? = options_flags.anybits?(CMAP_LOOKUP)
|
|
40
|
+
def vertical? = options_flags.anybits?(VERTICAL)
|
|
41
|
+
def realized_advance? = options_flags.anybits?(REALIZED_ADVANCE)
|
|
42
|
+
def limit_subpixel? = options_flags.anybits?(LIMIT_SUBPIXEL)
|
|
43
|
+
def matrix_present? = body.matrix_present == 1
|
|
44
|
+
def glyph_count = body.glyph_count
|
|
45
|
+
def glyphs = body.glyphs.to_a
|
|
46
|
+
|
|
47
|
+
# Glyphs are UTF-16 code units only under CmapLookup; otherwise they are
|
|
48
|
+
# font glyph indices and carry no text.
|
|
49
|
+
def text
|
|
50
|
+
return unless cmap_lookup?
|
|
51
|
+
|
|
52
|
+
glyphs.pack("v*").force_encoding(Encoding::UTF_16LE)
|
|
53
|
+
.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def glyph_positions = body.glyph_positions.map { |p| [p.x, p.y] }
|
|
57
|
+
def transform_matrix = matrix_present? ? body.transform_matrix.to_a : nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/rect_array"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Records
|
|
8
|
+
# EmfPlusDrawEllipse (2.3.4.7). C selects Rect over RectF; ObjectID is the pen.
|
|
9
|
+
class DrawEllipse < Base
|
|
10
|
+
include ShapeFlags
|
|
11
|
+
|
|
12
|
+
TYPE = 0x400F
|
|
13
|
+
|
|
14
|
+
class DrawEllipseBody < Body
|
|
15
|
+
endian :little
|
|
16
|
+
mandatory_parameter :flags
|
|
17
|
+
rect_array :rect_data,
|
|
18
|
+
rect_count: 1,
|
|
19
|
+
compressed: -> { flags.anybits?(ShapeFlags::COMPRESSED_FLAG) }
|
|
20
|
+
end
|
|
21
|
+
BODY = DrawEllipseBody
|
|
22
|
+
|
|
23
|
+
def pen_id = emf_object_id
|
|
24
|
+
def rect = body.rect_data.rects.first
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/rect_f"
|
|
4
|
+
require "emf/emf_plus/records/primitives/rect"
|
|
5
|
+
|
|
6
|
+
module Emf
|
|
7
|
+
module EmfPlus
|
|
8
|
+
module Records
|
|
9
|
+
# EmfPlusDrawImage (2.3.4.8). The C flag selects EmfPlusRect over
|
|
10
|
+
# EmfPlusRectF for RectData.
|
|
11
|
+
class DrawImage < Base
|
|
12
|
+
TYPE = 0x401A
|
|
13
|
+
COMPRESSED_FLAG = 0x4000
|
|
14
|
+
OBJECT_ID_MASK = 0x00FF
|
|
15
|
+
|
|
16
|
+
class DrawImageBody < Body
|
|
17
|
+
endian :little
|
|
18
|
+
mandatory_parameter :flags
|
|
19
|
+
uint32 :image_attributes_id
|
|
20
|
+
int32 :src_unit
|
|
21
|
+
rect_f :src_rect
|
|
22
|
+
rect :compressed_rect, onlyif: -> { flags.anybits?(COMPRESSED_FLAG) }
|
|
23
|
+
rect_f :rect_data, onlyif: -> { !flags.anybits?(COMPRESSED_FLAG) }
|
|
24
|
+
end
|
|
25
|
+
BODY = DrawImageBody
|
|
26
|
+
|
|
27
|
+
def flag_fields = { compressed: COMPRESSED_FLAG, image_object_id: OBJECT_ID_MASK }
|
|
28
|
+
|
|
29
|
+
def compressed? = flags.anybits?(COMPRESSED_FLAG)
|
|
30
|
+
def image_object_id = flags & OBJECT_ID_MASK
|
|
31
|
+
def image_attributes_id = body.image_attributes_id
|
|
32
|
+
def src_unit = body.src_unit
|
|
33
|
+
def src_rect = rect_values(body.src_rect)
|
|
34
|
+
def dest_rect = rect_values(compressed? ? body.compressed_rect : body.rect_data)
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def rect_values(rect) = [rect.x, rect.y, rect.width, rect.height]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/emf_plus/records/primitives/bounded_array"
|
|
4
|
+
require "emf/emf_plus/records/primitives/rect_f"
|
|
5
|
+
require "emf/emf_plus/records/primitives/point_f"
|
|
6
|
+
require "emf/emf_plus/records/primitives/point"
|
|
7
|
+
require "emf/emf_plus/records/primitives/point_r"
|
|
8
|
+
|
|
9
|
+
module Emf
|
|
10
|
+
module EmfPlus
|
|
11
|
+
module Records
|
|
12
|
+
# EmfPlusDrawImagePoints (2.3.4.9). P selects relative EmfPlusPointR
|
|
13
|
+
# elements and makes C undefined; otherwise C selects EmfPlusPoint over
|
|
14
|
+
# EmfPlusPointF. E means an earlier EmfPlusSerializableObject supplies
|
|
15
|
+
# the effect.
|
|
16
|
+
class DrawImagePoints < Base
|
|
17
|
+
TYPE = 0x401B
|
|
18
|
+
COMPRESSED_FLAG = 0x4000
|
|
19
|
+
EFFECT_FLAG = 0x2000
|
|
20
|
+
RELATIVE_FLAG = 0x0800
|
|
21
|
+
OBJECT_ID_MASK = 0x00FF
|
|
22
|
+
|
|
23
|
+
class DrawImagePointsBody < Body
|
|
24
|
+
endian :little
|
|
25
|
+
mandatory_parameter :flags
|
|
26
|
+
uint32 :image_attributes_id
|
|
27
|
+
int32 :src_unit
|
|
28
|
+
rect_f :src_rect
|
|
29
|
+
uint32 :point_count
|
|
30
|
+
bounded_array :relative_points, type: :point_r, element_size: 2, initial_length: :point_count, onlyif: lambda {
|
|
31
|
+
flags.anybits?(RELATIVE_FLAG)
|
|
32
|
+
}
|
|
33
|
+
bounded_array :compressed_points, type: :point, element_size: 4, initial_length: :point_count,
|
|
34
|
+
onlyif: -> { !flags.anybits?(RELATIVE_FLAG) && flags.anybits?(COMPRESSED_FLAG) }
|
|
35
|
+
bounded_array :float_points, type: :point_f, element_size: 8, initial_length: :point_count,
|
|
36
|
+
onlyif: -> { !flags.anybits?(RELATIVE_FLAG) && !flags.anybits?(COMPRESSED_FLAG) }
|
|
37
|
+
end
|
|
38
|
+
BODY = DrawImagePointsBody
|
|
39
|
+
|
|
40
|
+
def flag_fields
|
|
41
|
+
{ compressed: COMPRESSED_FLAG, relative: RELATIVE_FLAG, effect: EFFECT_FLAG, image_object_id: OBJECT_ID_MASK }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def relative? = flags.anybits?(RELATIVE_FLAG)
|
|
45
|
+
def compressed? = !relative? && flags.anybits?(COMPRESSED_FLAG)
|
|
46
|
+
def effect? = flags.anybits?(EFFECT_FLAG)
|
|
47
|
+
def image_object_id = flags & OBJECT_ID_MASK
|
|
48
|
+
def image_attributes_id = body.image_attributes_id
|
|
49
|
+
def src_unit = body.src_unit
|
|
50
|
+
def src_rect = body.src_rect.then { |r| [r.x, r.y, r.width, r.height] }
|
|
51
|
+
def count = body.point_count
|
|
52
|
+
def points = relative? ? body.relative_points.map { |p| [p.x.to_i, p.y.to_i] } : point_array.map { |p| [p.x, p.y] }
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def point_array
|
|
57
|
+
compressed? ? body.compressed_points : body.float_points
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|