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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
# Conformance lens: checks a parsed metafile against the Microsoft specs and
|
|
5
|
+
# reports structured diagnostics in svg_conform's report shape.
|
|
6
|
+
#
|
|
7
|
+
# Emf::Conformance.check("file.emf", profile: :tolerant).to_h
|
|
8
|
+
#
|
|
9
|
+
# Rules read only the public model API (records, wire fields, Metafile#errors,
|
|
10
|
+
# Metafile#emf_plus_stream); they never touch a backend-specific class.
|
|
11
|
+
module Conformance
|
|
12
|
+
autoload :Diagnostic, "emf/conformance/diagnostic"
|
|
13
|
+
autoload :Report, "emf/conformance/report"
|
|
14
|
+
autoload :Profile, "emf/conformance/profile"
|
|
15
|
+
autoload :Rule, "emf/conformance/rule"
|
|
16
|
+
autoload :Registry, "emf/conformance/registry"
|
|
17
|
+
autoload :Context, "emf/conformance/context"
|
|
18
|
+
autoload :Runner, "emf/conformance/runner"
|
|
19
|
+
autoload :RecordTypes, "emf/conformance/record_types"
|
|
20
|
+
autoload :Manifest, "emf/conformance/manifest"
|
|
21
|
+
autoload :TernaryRasterOperations, "emf/conformance/ternary_raster_operations"
|
|
22
|
+
|
|
23
|
+
# @param input [String, Pathname, Emf::Model::Metafile] a file path, raw bytes or a parsed metafile
|
|
24
|
+
# @param profile [Symbol] :strict (spec-conformant only) or :tolerant (accepts the real-world corpus)
|
|
25
|
+
# @param registry [Registry] rule set; defaults to every rule file under conformance/rules
|
|
26
|
+
# @return [Report]
|
|
27
|
+
def self.check(input, profile: :strict, registry: Registry.default, now: Time.now)
|
|
28
|
+
Runner.new(Profile.fetch(profile), registry).call(input, now: now)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Effects
|
|
8
|
+
# BlurEffect (2.2.3.1).
|
|
9
|
+
class Blur < Effect
|
|
10
|
+
GUID = "633c80a4-1843-482b-9ef2-be2834c5fdd4"
|
|
11
|
+
|
|
12
|
+
class BlurBody < Records::Body
|
|
13
|
+
endian :little
|
|
14
|
+
float32_le :blur_radius
|
|
15
|
+
uint32 :expand_edge
|
|
16
|
+
end
|
|
17
|
+
BODY = BlurBody
|
|
18
|
+
|
|
19
|
+
def blur_radius = body.blur_radius
|
|
20
|
+
def expand_edge = body.expand_edge
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# BrightnessContrastEffect (2.2.3.2).
|
|
7
|
+
class BrightnessContrast < Effect
|
|
8
|
+
GUID = "d3a1dbe1-8ec4-4c17-9f4c-ea97ad1c343d"
|
|
9
|
+
|
|
10
|
+
class BrightnessContrastBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
int32 :brightness_level
|
|
13
|
+
int32 :contrast_level
|
|
14
|
+
end
|
|
15
|
+
BODY = BrightnessContrastBody
|
|
16
|
+
|
|
17
|
+
def brightness_level = body.brightness_level
|
|
18
|
+
def contrast_level = body.contrast_level
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# ColorBalanceEffect (2.2.3.3).
|
|
7
|
+
class ColorBalance < Effect
|
|
8
|
+
GUID = "537e597d-251e-48da-9664-29ca496b70f8"
|
|
9
|
+
|
|
10
|
+
class ColorBalanceBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
int32 :cyan_red
|
|
13
|
+
int32 :magenta_green
|
|
14
|
+
int32 :yellow_blue
|
|
15
|
+
end
|
|
16
|
+
BODY = ColorBalanceBody
|
|
17
|
+
|
|
18
|
+
def cyan_red = body.cyan_red
|
|
19
|
+
def magenta_green = body.magenta_green
|
|
20
|
+
def yellow_blue = body.yellow_blue
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# ColorCurveEffect (2.2.3.4).
|
|
7
|
+
class ColorCurve < Effect
|
|
8
|
+
GUID = "dd6a0022-58e4-4a67-9d9b-d48eb881a53d"
|
|
9
|
+
|
|
10
|
+
class ColorCurveBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
uint32 :curve_adjustment
|
|
13
|
+
uint32 :curve_channel
|
|
14
|
+
int32 :adjustment_intensity
|
|
15
|
+
end
|
|
16
|
+
BODY = ColorCurveBody
|
|
17
|
+
|
|
18
|
+
def curve_adjustment = body.curve_adjustment
|
|
19
|
+
def curve_channel = body.curve_channel
|
|
20
|
+
def adjustment_intensity = body.adjustment_intensity
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# ColorLookupTableEffect (2.2.3.5).
|
|
7
|
+
class ColorLookupTable < Effect
|
|
8
|
+
GUID = "a7ce72a9-0f7f-40d7-b3cc-d0c02d5c3212"
|
|
9
|
+
|
|
10
|
+
class ColorLookupTableBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
string :blue_lookup_table, length: 256
|
|
13
|
+
string :green_lookup_table, length: 256
|
|
14
|
+
string :red_lookup_table, length: 256
|
|
15
|
+
string :alpha_lookup_table, length: 256
|
|
16
|
+
end
|
|
17
|
+
BODY = ColorLookupTableBody
|
|
18
|
+
|
|
19
|
+
def blue_lookup_table = body.blue_lookup_table.to_s
|
|
20
|
+
def green_lookup_table = body.green_lookup_table.to_s
|
|
21
|
+
def red_lookup_table = body.red_lookup_table.to_s
|
|
22
|
+
def alpha_lookup_table = body.alpha_lookup_table.to_s
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Effects
|
|
8
|
+
# ColorMatrixEffect (2.2.3.6).
|
|
9
|
+
class ColorMatrix < Effect
|
|
10
|
+
GUID = "718f2615-7933-40e3-a511-5f68fe14dd74"
|
|
11
|
+
|
|
12
|
+
class ColorMatrixBody < Records::Body
|
|
13
|
+
endian :little
|
|
14
|
+
array :matrix_values, type: :float32_le, initial_length: 25
|
|
15
|
+
end
|
|
16
|
+
BODY = ColorMatrixBody
|
|
17
|
+
|
|
18
|
+
# Matrix[row][column]; the spec lists each column's five rows in turn.
|
|
19
|
+
def matrix = Array.new(5) { |row| Array.new(5) { |column| body.matrix_values[(column * 5) + row] } }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bindata"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Effects
|
|
8
|
+
# An image effect parameter block read through a BinData class (BODY in
|
|
9
|
+
# the subclass). Bytes after the body stay in `trailing`, so an unedited
|
|
10
|
+
# effect re-encodes to its buffer.
|
|
11
|
+
class Effect
|
|
12
|
+
attr_reader :body, :trailing
|
|
13
|
+
|
|
14
|
+
def initialize(buffer, offset:, record_code:)
|
|
15
|
+
@buffer = buffer
|
|
16
|
+
@offset = offset
|
|
17
|
+
@record_code = record_code
|
|
18
|
+
check_bounds
|
|
19
|
+
@body = read_body
|
|
20
|
+
@trailing = buffer.byteslice(@body.num_bytes..).freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_binary = body.to_binary_s + trailing
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :buffer
|
|
28
|
+
|
|
29
|
+
def check_bounds; end
|
|
30
|
+
|
|
31
|
+
def read_body
|
|
32
|
+
self.class::BODY.new.read(buffer)
|
|
33
|
+
rescue IOError, BinData::ValidityError => e
|
|
34
|
+
fail_parse(e.message)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def fail_parse(message)
|
|
38
|
+
raise ParseError.new(offset: @offset, record_code: @record_code,
|
|
39
|
+
message: "malformed #{self.class.name.split('::').last} effect at offset #{@offset}: #{message}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def require_room(needed, what)
|
|
43
|
+
return if needed <= buffer.bytesize
|
|
44
|
+
|
|
45
|
+
fail_parse("#{what} needs #{needed} bytes, buffer holds #{buffer.bytesize}")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# HueSaturationLightnessEffect (2.2.3.7).
|
|
7
|
+
class HueSaturationLightness < Effect
|
|
8
|
+
GUID = "8b2dd6c3-eb07-4d87-a5f0-7108e26a9c5f"
|
|
9
|
+
|
|
10
|
+
class HueSaturationLightnessBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
int32 :hue_level
|
|
13
|
+
int32 :saturation_level
|
|
14
|
+
int32 :lightness_level
|
|
15
|
+
end
|
|
16
|
+
BODY = HueSaturationLightnessBody
|
|
17
|
+
|
|
18
|
+
def hue_level = body.hue_level
|
|
19
|
+
def saturation_level = body.saturation_level
|
|
20
|
+
def lightness_level = body.lightness_level
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# LevelsEffect (2.2.3.8).
|
|
7
|
+
class Levels < Effect
|
|
8
|
+
GUID = "99c354ec-2a31-4f3a-8c34-17a803b33a25"
|
|
9
|
+
|
|
10
|
+
class LevelsBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
int32 :highlight
|
|
13
|
+
int32 :mid_tone
|
|
14
|
+
int32 :shadow
|
|
15
|
+
end
|
|
16
|
+
BODY = LevelsBody
|
|
17
|
+
|
|
18
|
+
def highlight = body.highlight
|
|
19
|
+
def mid_tone = body.mid_tone
|
|
20
|
+
def shadow = body.shadow
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# A parameter block of an unknown GUID, or a ColorCurve block that does
|
|
7
|
+
# not fit its layout (Windows writes those corrupt, ch05 note 10).
|
|
8
|
+
class Opaque
|
|
9
|
+
attr_reader :buffer
|
|
10
|
+
|
|
11
|
+
def initialize(buffer)
|
|
12
|
+
@buffer = buffer
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_binary = buffer
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# RedEyeCorrectionEffect (2.2.3.9): NumberOfAreas WMF RectL objects, read with
|
|
7
|
+
# the core Emf::Binary::Types::RectL (a nested RectL would replace it in
|
|
8
|
+
# BinData's global registry).
|
|
9
|
+
class RedEyeCorrection < Effect
|
|
10
|
+
GUID = "74d29d05-69a4-4266-9549-3cc52836b632"
|
|
11
|
+
RECT_SIZE = 16
|
|
12
|
+
|
|
13
|
+
class RedEyeCorrectionBody < Records::Body
|
|
14
|
+
endian :little
|
|
15
|
+
int32 :number_of_areas
|
|
16
|
+
array :areas, type: :rect_l, initial_length: :number_of_areas
|
|
17
|
+
end
|
|
18
|
+
BODY = RedEyeCorrectionBody
|
|
19
|
+
|
|
20
|
+
def number_of_areas = body.number_of_areas
|
|
21
|
+
def areas = body.areas.map { |r| [r.left, r.top, r.right, r.bottom] }
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def check_bounds
|
|
26
|
+
return if buffer.bytesize < 4
|
|
27
|
+
|
|
28
|
+
count = buffer.unpack1("l<")
|
|
29
|
+
fail_parse("negative NumberOfAreas #{count}") if count.negative?
|
|
30
|
+
require_room(4 + (count * RECT_SIZE), "Areas of #{count} rectangles")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "emf/binary/float32_le"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
module Effects
|
|
8
|
+
# SharpenEffect (2.2.3.10).
|
|
9
|
+
class Sharpen < Effect
|
|
10
|
+
GUID = "63cbf3ee-c526-402c-8f71-62c540bf5142"
|
|
11
|
+
|
|
12
|
+
class SharpenBody < Records::Body
|
|
13
|
+
endian :little
|
|
14
|
+
float32_le :radius
|
|
15
|
+
float32_le :amount
|
|
16
|
+
end
|
|
17
|
+
BODY = SharpenBody
|
|
18
|
+
|
|
19
|
+
def radius = body.radius
|
|
20
|
+
def amount = body.amount
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Effects
|
|
6
|
+
# TintEffect (2.2.3.11).
|
|
7
|
+
class Tint < Effect
|
|
8
|
+
GUID = "1077af00-2848-4441-9489-44ad4c2d7a2c"
|
|
9
|
+
|
|
10
|
+
class TintBody < Records::Body
|
|
11
|
+
endian :little
|
|
12
|
+
int32 :hue
|
|
13
|
+
int32 :amount
|
|
14
|
+
end
|
|
15
|
+
BODY = TintBody
|
|
16
|
+
|
|
17
|
+
def hue = body.hue
|
|
18
|
+
def amount = body.amount
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
# Typed image effect parameter blocks (2.2.3), identified by the GUID of
|
|
6
|
+
# the EmfPlusSerializableObject that carries them.
|
|
7
|
+
module Effects
|
|
8
|
+
autoload :Effect, "emf/emf_plus/effects/effect"
|
|
9
|
+
autoload :Opaque, "emf/emf_plus/effects/opaque"
|
|
10
|
+
autoload :Blur, "emf/emf_plus/effects/blur"
|
|
11
|
+
autoload :BrightnessContrast, "emf/emf_plus/effects/brightness_contrast"
|
|
12
|
+
autoload :ColorBalance, "emf/emf_plus/effects/color_balance"
|
|
13
|
+
autoload :ColorCurve, "emf/emf_plus/effects/color_curve"
|
|
14
|
+
autoload :ColorLookupTable, "emf/emf_plus/effects/color_lookup_table"
|
|
15
|
+
autoload :ColorMatrix, "emf/emf_plus/effects/color_matrix"
|
|
16
|
+
autoload :HueSaturationLightness, "emf/emf_plus/effects/hue_saturation_lightness"
|
|
17
|
+
autoload :Levels, "emf/emf_plus/effects/levels"
|
|
18
|
+
autoload :RedEyeCorrection, "emf/emf_plus/effects/red_eye_correction"
|
|
19
|
+
autoload :Sharpen, "emf/emf_plus/effects/sharpen"
|
|
20
|
+
autoload :Tint, "emf/emf_plus/effects/tint"
|
|
21
|
+
|
|
22
|
+
CLASSES = %i[Blur BrightnessContrast ColorBalance ColorCurve ColorLookupTable ColorMatrix
|
|
23
|
+
HueSaturationLightness Levels RedEyeCorrection Sharpen Tint].freeze
|
|
24
|
+
private_constant :CLASSES
|
|
25
|
+
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
# `serializable` is a Records::SerializableObject.
|
|
29
|
+
def decode(serializable)
|
|
30
|
+
klass = lookup(serializable.object_guid)
|
|
31
|
+
return Opaque.new(serializable.buffer) unless klass
|
|
32
|
+
|
|
33
|
+
klass.new(serializable.buffer, offset: serializable.offset, record_code: serializable.type)
|
|
34
|
+
rescue ParseError
|
|
35
|
+
raise unless klass == ColorCurve
|
|
36
|
+
|
|
37
|
+
Opaque.new(serializable.buffer)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def lookup(guid)
|
|
41
|
+
CLASSES.map { |name| const_get(name) }.find { |klass| guid == klass::GUID }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
# One EMF+ record as framed on the wire: the 12-byte header fields plus the
|
|
6
|
+
# undecoded body. `data` is every byte after the header up to `size`, so a
|
|
7
|
+
# frame always re-serializes to the bytes it was read from.
|
|
8
|
+
#
|
|
9
|
+
# `offset` is the frame's position within its byte stream; `comment_index`
|
|
10
|
+
# is the index into Metafile#records of the EMR_COMMENT it was read from
|
|
11
|
+
# (nil when framed from a bare stream).
|
|
12
|
+
class Frame
|
|
13
|
+
HEADER_BYTES = 12
|
|
14
|
+
|
|
15
|
+
attr_reader :type, :flags, :size, :data_size, :data, :offset, :comment_index
|
|
16
|
+
|
|
17
|
+
def initialize(type:, flags:, size:, data_size:, data:, offset: 0, comment_index: nil)
|
|
18
|
+
@type = type
|
|
19
|
+
@flags = flags
|
|
20
|
+
@size = size
|
|
21
|
+
@data_size = data_size
|
|
22
|
+
@data = data.b.freeze
|
|
23
|
+
@offset = offset
|
|
24
|
+
@comment_index = comment_index
|
|
25
|
+
freeze
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Size must stay 32-bit aligned, so the body is zero-padded; DataSize keeps the real length.
|
|
29
|
+
def with_data(new_data)
|
|
30
|
+
padded = new_data.b + ("\0" * (-new_data.bytesize % 4))
|
|
31
|
+
self.class.new(type: type, flags: flags, size: HEADER_BYTES + padded.bytesize,
|
|
32
|
+
data_size: new_data.bytesize, data: padded,
|
|
33
|
+
offset: offset, comment_index: comment_index)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_binary
|
|
37
|
+
[type, flags, size, data_size].pack("vvVV") + data
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Links
|
|
6
|
+
# An E-flag EmfPlusDrawImagePoints frame paired with the
|
|
7
|
+
# EmfPlusSerializableObject frame that supplies its effect.
|
|
8
|
+
EffectLink = Struct.new(:draw, :effect, keyword_init: true) do
|
|
9
|
+
def initialize(**)
|
|
10
|
+
super
|
|
11
|
+
freeze
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Links
|
|
6
|
+
# The EMF records a single EmfPlusGetDC makes drawable. `emr_range` indexes
|
|
7
|
+
# Metafile#records and is empty when another EMF+ record follows the GetDC.
|
|
8
|
+
GetDcSpan = Struct.new(:comment_index, :offset, :emr_range, keyword_init: true) do
|
|
9
|
+
def initialize(**)
|
|
10
|
+
super
|
|
11
|
+
freeze
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def empty? = emr_range.none?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
module Links
|
|
6
|
+
# A linking diagnostic. `reason` is :missing_effect or :non_adjacent_effect.
|
|
7
|
+
LinkError = Struct.new(:reason, :comment_index, :offset, :message, keyword_init: true) do
|
|
8
|
+
def initialize(**)
|
|
9
|
+
super
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module EmfPlus
|
|
5
|
+
# Ordering and linking rules that span EMF+ records and the EMF records
|
|
6
|
+
# around them. Works on framed records (Parser.from_metafile), never decodes
|
|
7
|
+
# or alters bytes, and reports problems instead of raising.
|
|
8
|
+
module Links
|
|
9
|
+
autoload :GetDcSpan, "emf/emf_plus/links/get_dc_span"
|
|
10
|
+
autoload :EffectLink, "emf/emf_plus/links/effect_link"
|
|
11
|
+
autoload :LinkError, "emf/emf_plus/links/link_error"
|
|
12
|
+
|
|
13
|
+
GET_DC = 0x4004
|
|
14
|
+
SERIALIZABLE_OBJECT = 0x4038
|
|
15
|
+
DRAW_IMAGE_POINTS = 0x401B
|
|
16
|
+
EFFECT_FLAG = 0x2000
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# MS-EMFPLUS 2.3.3.2: EMF records are processed after an EmfPlusGetDC
|
|
21
|
+
# until the next EMF+ record. A GetDC that is not last in its comment is
|
|
22
|
+
# followed by an EMF+ record at once, so its span is empty; otherwise the
|
|
23
|
+
# span runs to the next comment carrying EMF+ records (or the end).
|
|
24
|
+
def get_dc_spans(metafile, frames)
|
|
25
|
+
frames.each_with_index.filter_map do |frame, index|
|
|
26
|
+
next unless frame.type == GET_DC
|
|
27
|
+
|
|
28
|
+
GetDcSpan.new(comment_index: frame.comment_index, offset: frame.offset,
|
|
29
|
+
emr_range: emr_range_after(frames, index, metafile.records.size))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# MS-EMFPLUS 2.3.4.9 says an E-flag DrawImagePoints needs an "earlier"
|
|
34
|
+
# SerializableObject without saying how far back. Only the immediately
|
|
35
|
+
# preceding EMF+ record (across comments) is linked; anything else is
|
|
36
|
+
# reported. Returns [links, errors].
|
|
37
|
+
def effect_links(frames)
|
|
38
|
+
links = []
|
|
39
|
+
errors = []
|
|
40
|
+
frames.each_with_index do |frame, index|
|
|
41
|
+
next unless effect_draw?(frame)
|
|
42
|
+
|
|
43
|
+
effect = frames[index - 1] if index.positive? && frames[index - 1].type == SERIALIZABLE_OBJECT
|
|
44
|
+
effect ? links << EffectLink.new(draw: frame, effect: effect) : errors << effect_error(frames, index)
|
|
45
|
+
end
|
|
46
|
+
[links.freeze, errors.freeze]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def emr_range_after(frames, index, record_count)
|
|
50
|
+
frame = frames[index]
|
|
51
|
+
following = frames[index + 1]
|
|
52
|
+
first = frame.comment_index + 1
|
|
53
|
+
return first...first if following&.comment_index == frame.comment_index
|
|
54
|
+
|
|
55
|
+
first...(following ? following.comment_index : record_count)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def effect_draw?(frame)
|
|
59
|
+
frame.type == DRAW_IMAGE_POINTS && frame.flags.anybits?(EFFECT_FLAG)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def effect_error(frames, index)
|
|
63
|
+
frame = frames[index]
|
|
64
|
+
earlier = frames[0...index].any? { |f| f.type == SERIALIZABLE_OBJECT }
|
|
65
|
+
reason = earlier ? :non_adjacent_effect : :missing_effect
|
|
66
|
+
message = if earlier
|
|
67
|
+
"E-flag DrawImagePoints is not immediately preceded by a SerializableObject"
|
|
68
|
+
else
|
|
69
|
+
"E-flag DrawImagePoints has no SerializableObject"
|
|
70
|
+
end
|
|
71
|
+
LinkError.new(reason: reason, comment_index: frame.comment_index, offset: frame.offset, message: message)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private_class_method :emr_range_after, :effect_draw?, :effect_error
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|